package extension

import (
	
	

	
	gast 
	
	
	
	
	
	
)

var footnoteListKey = parser.NewContextKey()
var footnoteLinkListKey = parser.NewContextKey()

type footnoteBlockParser struct {
}

var defaultFootnoteBlockParser = &footnoteBlockParser{}
NewFootnoteBlockParser returns a new parser.BlockParser that can parse footnotes of the Markdown(PHP Markdown Extra) text.
func () parser.BlockParser {
	return defaultFootnoteBlockParser
}

func ( *footnoteBlockParser) () []byte {
	return []byte{'['}
}

func ( *footnoteBlockParser) ( gast.Node,  text.Reader,  parser.Context) (gast.Node, parser.State) {
	,  := .PeekLine()
	 := .BlockOffset()
	if  < 0 || [] != '[' {
		return nil, parser.NoChildren
	}
	++
	if  > len()-1 || [] != '^' {
		return nil, parser.NoChildren
	}
	 :=  + 1
	 := 0
	 := util.FindClosure([+1:], '[', ']', false, false)
	 =  + 1 + 
	 :=  + 1
	if  > -1 {
		if  >= len() || [] != ':' {
			return nil, parser.NoChildren
		}
	} else {
		return nil, parser.NoChildren
	}
	 := .Padding
	 := .Value(text.NewSegment(.Start+-, .Start+-))
	if util.IsBlank() {
		return nil, parser.NoChildren
	}
	 := ast.NewFootnote()

	 =  + 1 - 
	if  >= len() {
		.Advance()
		return , parser.NoChildren
	}
	.AdvanceAndSetPadding(, )
	return , parser.HasChildren
}

func ( *footnoteBlockParser) ( gast.Node,  text.Reader,  parser.Context) parser.State {
	,  := .PeekLine()
	if util.IsBlank() {
		return parser.Continue | parser.HasChildren
	}
	,  := util.IndentPosition(, .LineOffset(), 4)
	if  < 0 {
		return parser.Close
	}
	.AdvanceAndSetPadding(, )
	return parser.Continue | parser.HasChildren
}

func ( *footnoteBlockParser) ( gast.Node,  text.Reader,  parser.Context) {
	var  *ast.FootnoteList
	if  := .Get(footnoteListKey);  != nil {
		 = .(*ast.FootnoteList)
	} else {
		 = ast.NewFootnoteList()
		.Set(footnoteListKey, )
		.Parent().InsertBefore(.Parent(), , )
	}
	.Parent().RemoveChild(.Parent(), )
	.AppendChild(, )
}

func ( *footnoteBlockParser) () bool {
	return true
}

func ( *footnoteBlockParser) () bool {
	return false
}

type footnoteParser struct {
}

var defaultFootnoteParser = &footnoteParser{}
NewFootnoteParser returns a new parser.InlineParser that can parse footnote links of the Markdown(PHP Markdown Extra) text.
footnote syntax probably conflict with the image syntax. So we need trigger this parser with '!'.
	return []byte{'!', '['}
}

func ( *footnoteParser) ( gast.Node,  text.Reader,  parser.Context) gast.Node {
	,  := .PeekLine()
	 := 1
	if len() > 0 && [0] == '!' {
		++
	}
	if  >= len() || [] != '^' {
		return nil
	}
	++
	if  >= len() {
		return nil
	}
	 := 
	 := util.FindClosure([:], '[', ']', false, false)
	if  < 0 {
		return nil
	}
	 :=  + 
	 := .Value(text.NewSegment(.Start+, .Start+))
	.Advance( + 1)

	var  *ast.FootnoteList
	if  := .Get(footnoteListKey);  != nil {
		 = .(*ast.FootnoteList)
	}
	if  == nil {
		return nil
	}
	 := 0
	for  := .FirstChild();  != nil;  = .NextSibling() {
		 := .(*ast.Footnote)
		if bytes.Equal(.Ref, ) {
			if .Index < 0 {
				.Count += 1
				.Index = .Count
			}
			 = .Index
			break
		}
	}
	if  == 0 {
		return nil
	}

	 := ast.NewFootnoteLink()
	var  []*ast.FootnoteLink
	if  := .Get(footnoteLinkListKey);  != nil {
		 = .([]*ast.FootnoteLink)
	} else {
		 = []*ast.FootnoteLink{}
		.Set(footnoteLinkListKey, )
	}
	.Set(footnoteLinkListKey, append(, ))
	if [0] == '!' {
		.AppendChild(, gast.NewTextSegment(text.NewSegment(.Start, .Start+1)))
	}

	return 
}

type footnoteASTTransformer struct {
}

var defaultFootnoteASTTransformer = &footnoteASTTransformer{}
NewFootnoteASTTransformer returns a new parser.ASTTransformer that insert a footnote list to the last of the document.
func () parser.ASTTransformer {
	return defaultFootnoteASTTransformer
}

func ( *footnoteASTTransformer) ( *gast.Document,  text.Reader,  parser.Context) {
	var  *ast.FootnoteList
	var  []*ast.FootnoteLink
	if  := .Get(footnoteListKey);  != nil {
		 = .(*ast.FootnoteList)
	}
	if  := .Get(footnoteLinkListKey);  != nil {
		 = .([]*ast.FootnoteLink)
	}

	.Set(footnoteListKey, nil)
	.Set(footnoteLinkListKey, nil)

	if  == nil {
		return
	}

	 := map[int]int{}
	if  != nil {
		for ,  := range  {
			if .Index >= 0 {
				[.Index]++
			}
		}
		for ,  := range  {
			.RefCount = [.Index]
		}
	}
	for  := .FirstChild();  != nil; {
		var  gast.Node = 
		 := .NextSibling()
		if  := .LastChild();  != nil && gast.IsParagraph() {
			 = 
		}
		 := .(*ast.Footnote)
		 := .Index
		if  < 0 {
			.RemoveChild(, )
		} else {
			 := ast.NewFootnoteBacklink()
			.RefCount = []
			.AppendChild(, )
		}
		 = 
	}
	.SortChildren(func(,  gast.Node) int {
		if .(*ast.Footnote).Index < .(*ast.Footnote).Index {
			return -1
		}
		return 1
	})
	if .Count <= 0 {
		.Parent().RemoveChild(.Parent(), )
		return
	}

	.AppendChild(, )
}
FootnoteConfig holds configuration values for the footnote extension. Link* and Backlink* configurations have some variables: Occurrances of “^^” in the string will be replaced by the corresponding footnote number in the HTML output. Occurrances of “%%” will be replaced by a number for the reference (footnotes can have multiple references).
type FootnoteConfig struct {
	html.Config
IDPrefix is a prefix for the id attributes generated by footnotes.
IDPrefix is a function that determines the id attribute for given Node.
LinkTitle is an optional title attribute for footnote links.
BacklinkTitle is an optional title attribute for footnote backlinks.
LinkClass is a class for footnote links.
BacklinkClass is a class for footnote backlinks.
BacklinkHTML is an HTML content for footnote backlinks.
FootnoteOption interface is a functional option interface for the extension.
type FootnoteOption interface {
SetFootnoteOption sets given option to the extension.
	SetFootnoteOption(*FootnoteConfig)
}
NewFootnoteConfig returns a new Config with defaults.
func () FootnoteConfig {
	return FootnoteConfig{
		Config:        html.NewConfig(),
		LinkTitle:     []byte(""),
		BacklinkTitle: []byte(""),
		LinkClass:     []byte("footnote-ref"),
		BacklinkClass: []byte("footnote-backref"),
		BacklinkHTML:  []byte("&#x21a9;&#xfe0e;"),
	}
}
SetOption implements renderer.SetOptioner.
func ( *FootnoteConfig) ( renderer.OptionName,  interface{}) {
	switch  {
	case optFootnoteIDPrefixFunction:
		.IDPrefixFunction = .(func(gast.Node) []byte)
	case optFootnoteIDPrefix:
		.IDPrefix = .([]byte)
	case optFootnoteLinkTitle:
		.LinkTitle = .([]byte)
	case optFootnoteBacklinkTitle:
		.BacklinkTitle = .([]byte)
	case optFootnoteLinkClass:
		.LinkClass = .([]byte)
	case optFootnoteBacklinkClass:
		.BacklinkClass = .([]byte)
	case optFootnoteBacklinkHTML:
		.BacklinkHTML = .([]byte)
	default:
		.Config.SetOption(, )
	}
}

type withFootnoteHTMLOptions struct {
	value []html.Option
}

func ( *withFootnoteHTMLOptions) ( *renderer.Config) {
	if .value != nil {
		for ,  := range .value {
			.(renderer.Option).SetConfig()
		}
	}
}

func ( *withFootnoteHTMLOptions) ( *FootnoteConfig) {
	if .value != nil {
		for ,  := range .value {
			.SetHTMLOption(&.Config)
		}
	}
}
WithFootnoteHTMLOptions is functional option that wraps goldmark HTMLRenderer options.
WithFootnoteIDPrefix is a functional option that is a prefix for the id attributes generated by footnotes.
WithFootnoteIDPrefixFunction is a functional option that is a prefix for the id attributes generated by footnotes.
WithFootnoteLinkTitle is a functional option that is an optional title attribute for footnote links.
WithFootnoteBacklinkTitle is a functional option that is an optional title attribute for footnote backlinks.
WithFootnoteLinkClass is a functional option that is a class for footnote links.
WithFootnoteBacklinkClass is a functional option that is a class for footnote backlinks.
WithFootnoteBacklinkHTML is an HTML content for footnote backlinks.
FootnoteHTMLRenderer is a renderer.NodeRenderer implementation that renders FootnoteLink nodes.
NewFootnoteHTMLRenderer returns a new FootnoteHTMLRenderer.
RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs.
func ( *FootnoteHTMLRenderer) ( renderer.NodeRendererFuncRegisterer) {
	.Register(ast.KindFootnoteLink, .renderFootnoteLink)
	.Register(ast.KindFootnoteBacklink, .renderFootnoteBacklink)
	.Register(ast.KindFootnote, .renderFootnote)
	.Register(ast.KindFootnoteList, .renderFootnoteList)
}

func ( *FootnoteHTMLRenderer) ( util.BufWriter,  []byte,  gast.Node,  bool) (gast.WalkStatus, error) {
	if  {
		 := .(*ast.FootnoteLink)
		 := strconv.Itoa(.Index)
		_, _ = .WriteString(`<sup id="`)
		_, _ = .Write(.idPrefix())
		_, _ = .WriteString(`fnref:`)
		_, _ = .WriteString()
		_, _ = .WriteString(`"><a href="#`)
		_, _ = .Write(.idPrefix())
		_, _ = .WriteString(`fn:`)
		_, _ = .WriteString()
		_, _ = .WriteString(`" class="`)
		_, _ = .Write(applyFootnoteTemplate(.FootnoteConfig.LinkClass,
			.Index, .RefCount))
		if len(.FootnoteConfig.LinkTitle) > 0 {
			_, _ = .WriteString(`" title="`)
			_, _ = .Write(util.EscapeHTML(applyFootnoteTemplate(.FootnoteConfig.LinkTitle, .Index, .RefCount)))
		}
		_, _ = .WriteString(`" role="doc-noteref">`)

		_, _ = .WriteString()
		_, _ = .WriteString(`</a></sup>`)
	}
	return gast.WalkContinue, nil
}

func ( *FootnoteHTMLRenderer) ( util.BufWriter,  []byte,  gast.Node,  bool) (gast.WalkStatus, error) {
	if  {
		 := .(*ast.FootnoteBacklink)
		 := strconv.Itoa(.Index)
		_, _ = .WriteString(`&#160;<a href="#`)
		_, _ = .Write(.idPrefix())
		_, _ = .WriteString(`fnref:`)
		_, _ = .WriteString()
		_, _ = .WriteString(`" class="`)
		_, _ = .Write(applyFootnoteTemplate(.FootnoteConfig.BacklinkClass, .Index, .RefCount))
		if len(.FootnoteConfig.BacklinkTitle) > 0 {
			_, _ = .WriteString(`" title="`)
			_, _ = .Write(util.EscapeHTML(applyFootnoteTemplate(.FootnoteConfig.BacklinkTitle, .Index, .RefCount)))
		}
		_, _ = .WriteString(`" role="doc-backlink">`)
		_, _ = .Write(applyFootnoteTemplate(.FootnoteConfig.BacklinkHTML, .Index, .RefCount))
		_, _ = .WriteString(`</a>`)
	}
	return gast.WalkContinue, nil
}

func ( *FootnoteHTMLRenderer) ( util.BufWriter,  []byte,  gast.Node,  bool) (gast.WalkStatus, error) {
	 := .(*ast.Footnote)
	 := strconv.Itoa(.Index)
	if  {
		_, _ = .WriteString(`<li id="`)
		_, _ = .Write(.idPrefix())
		_, _ = .WriteString(`fn:`)
		_, _ = .WriteString()
		_, _ = .WriteString(`" role="doc-endnote"`)
		if .Attributes() != nil {
			html.RenderAttributes(, , html.ListItemAttributeFilter)
		}
		_, _ = .WriteString(">\n")
	} else {
		_, _ = .WriteString("</li>\n")
	}
	return gast.WalkContinue, nil
}

func ( *FootnoteHTMLRenderer) ( util.BufWriter,  []byte,  gast.Node,  bool) (gast.WalkStatus, error) {
	 := "section"
	if .Config.XHTML {
		 = "div"
	}
	if  {
		_, _ = .WriteString("<")
		_, _ = .WriteString()
		_, _ = .WriteString(` class="footnotes" role="doc-endnotes"`)
		if .Attributes() != nil {
			html.RenderAttributes(, , html.GlobalAttributeFilter)
		}
		_ = .WriteByte('>')
		if .Config.XHTML {
			_, _ = .WriteString("\n<hr />\n")
		} else {
			_, _ = .WriteString("\n<hr>\n")
		}
		_, _ = .WriteString("<ol>\n")
	} else {
		_, _ = .WriteString("</ol>\n")
		_, _ = .WriteString("</")
		_, _ = .WriteString()
		_, _ = .WriteString(">\n")
	}
	return gast.WalkContinue, nil
}

func ( *FootnoteHTMLRenderer) ( gast.Node) []byte {
	if .FootnoteConfig.IDPrefix != nil {
		return .FootnoteConfig.IDPrefix
	}
	if .FootnoteConfig.IDPrefixFunction != nil {
		return .FootnoteConfig.IDPrefixFunction()
	}
	return []byte("")
}

func ( []byte, ,  int) []byte {
	 := true
	for ,  := range  {
		if  != 0 {
			if [-1] == '^' &&  == '^' {
				 = false
				break
			}
			if [-1] == '%' &&  == '%' {
				 = false
				break
			}
		}
	}
	if  {
		return 
	}
	 := []byte(strconv.Itoa())
	 := []byte(strconv.Itoa())
	 := bytes.Replace(, []byte("^^"), , -1)
	return bytes.Replace(, []byte("%%"), , -1)
}

type footnote struct {
	options []FootnoteOption
}
Footnote is an extension that allow you to use PHP Markdown Extra Footnotes.