package extension

import (
	
	gast 
	
	
	
	
	
	
)

type definitionListParser struct {
}

var defaultDefinitionListParser = &definitionListParser{}

// NewDefinitionListParser return a new parser.BlockParser that
// can parse PHP Markdown Extra Definition lists.
func () parser.BlockParser {
	return defaultDefinitionListParser
}

func ( *definitionListParser) () []byte {
	return []byte{':'}
}

func ( *definitionListParser) ( gast.Node,  text.Reader,  parser.Context) (gast.Node, parser.State) {
	if ,  := .(*ast.DefinitionList);  {
		return nil, parser.NoChildren
	}
	,  := .PeekLine()
	 := .BlockOffset()
	 := .BlockIndent()
	if  < 0 || [] != ':' ||  != 0 {
		return nil, parser.NoChildren
	}

	 := .LastChild()
	// need 1 or more spaces after ':'
	,  := util.IndentWidth([+1:], +1)
	if  < 1 {
		return nil, parser.NoChildren
	}
	if  >= 8 { // starts with indented code
		 = 5
	}
	 +=  + 1 /* 1 = ':' */

	,  := .(*gast.Paragraph)
	var  *ast.DefinitionList
	 := parser.HasChildren
	var  bool
	if  {
		,  = .PreviousSibling().(*ast.DefinitionList)
		if  { // is not first item
			.Offset = 
			.TemporaryParagraph = 
		} else { // is first item
			 = ast.NewDefinitionList(, )
			 |= parser.RequireParagraph
		}
	} else if ,  = .(*ast.DefinitionList);  { // multiple description
		.Offset = 
		.TemporaryParagraph = nil
	} else {
		return nil, parser.NoChildren
	}

	return , 
}

func ( *definitionListParser) ( gast.Node,  text.Reader,  parser.Context) parser.State {
	,  := .PeekLine()
	if util.IsBlank() {
		return parser.Continue | parser.HasChildren
	}
	,  := .(*ast.DefinitionList)
	,  := util.IndentWidth(, .LineOffset())
	if  < .Offset {
		return parser.Close
	}
	,  := util.IndentPosition(, .LineOffset(), .Offset)
	.AdvanceAndSetPadding(, )
	return parser.Continue | parser.HasChildren
}

func ( *definitionListParser) ( gast.Node,  text.Reader,  parser.Context) {
	// nothing to do
}

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

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

type definitionDescriptionParser struct {
}

var defaultDefinitionDescriptionParser = &definitionDescriptionParser{}

// NewDefinitionDescriptionParser return a new parser.BlockParser that
// can parse definition description starts with ':'.
func () parser.BlockParser {
	return defaultDefinitionDescriptionParser
}

func ( *definitionDescriptionParser) () []byte {
	return []byte{':'}
}

func ( *definitionDescriptionParser) (
	 gast.Node,  text.Reader,  parser.Context) (gast.Node, parser.State) {
	,  := .PeekLine()
	 := .BlockOffset()
	 := .BlockIndent()
	if  < 0 || [] != ':' ||  != 0 {
		return nil, parser.NoChildren
	}
	,  := .(*ast.DefinitionList)
	if  == nil {
		return nil, parser.NoChildren
	}
	 := .TemporaryParagraph
	.TemporaryParagraph = nil
	if  != nil {
		 := .Lines()
		 := .Len()
		for  := 0;  < ; ++ {
			 := ast.NewDefinitionTerm()
			 := .At()
			.Lines().Append(.TrimRightSpace(.Source()))
			.AppendChild(, )
		}
		.Parent().RemoveChild(.Parent(), )
	}
	,  := util.IndentPosition([+1:], +1, .Offset--1)
	.AdvanceAndSetPadding(+1, )

	return ast.NewDefinitionDescription(), parser.HasChildren
}

func ( *definitionDescriptionParser) ( gast.Node,  text.Reader,  parser.Context) parser.State {
	// definitionListParser detects end of the description.
	// so this method will never be called.
	return parser.Continue | parser.HasChildren
}

func ( *definitionDescriptionParser) ( gast.Node,  text.Reader,  parser.Context) {
	 := .(*ast.DefinitionDescription)
	.IsTight = !.HasBlankPreviousLines()
	if .IsTight {
		for  := .FirstChild();  != nil;  = .NextSibling() {
			,  := .(*gast.Paragraph)
			if  {
				 := gast.NewTextBlock()
				.SetLines(.Lines())
				.ReplaceChild(, , )
			}
		}
	}
}

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

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

// DefinitionListHTMLRenderer is a renderer.NodeRenderer implementation that
// renders DefinitionList nodes.
type DefinitionListHTMLRenderer struct {
	html.Config
}

// NewDefinitionListHTMLRenderer returns a new DefinitionListHTMLRenderer.
func ( ...html.Option) renderer.NodeRenderer {
	 := &DefinitionListHTMLRenderer{
		Config: html.NewConfig(),
	}
	for ,  := range  {
		.SetHTMLOption(&.Config)
	}
	return 
}

// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs.
func ( *DefinitionListHTMLRenderer) ( renderer.NodeRendererFuncRegisterer) {
	.Register(ast.KindDefinitionList, .renderDefinitionList)
	.Register(ast.KindDefinitionTerm, .renderDefinitionTerm)
	.Register(ast.KindDefinitionDescription, .renderDefinitionDescription)
}

// DefinitionListAttributeFilter defines attribute names which dl elements can have.
var DefinitionListAttributeFilter = html.GlobalAttributeFilter

func ( *DefinitionListHTMLRenderer) (
	 util.BufWriter,  []byte,  gast.Node,  bool) (gast.WalkStatus, error) {
	if  {
		if .Attributes() != nil {
			_, _ = .WriteString("<dl")
			html.RenderAttributes(, , DefinitionListAttributeFilter)
			_, _ = .WriteString(">\n")
		} else {
			_, _ = .WriteString("<dl>\n")
		}
	} else {
		_, _ = .WriteString("</dl>\n")
	}
	return gast.WalkContinue, nil
}

// DefinitionTermAttributeFilter defines attribute names which dd elements can have.
var DefinitionTermAttributeFilter = html.GlobalAttributeFilter

func ( *DefinitionListHTMLRenderer) (
	 util.BufWriter,  []byte,  gast.Node,  bool) (gast.WalkStatus, error) {
	if  {
		if .Attributes() != nil {
			_, _ = .WriteString("<dt")
			html.RenderAttributes(, , DefinitionTermAttributeFilter)
			_ = .WriteByte('>')
		} else {
			_, _ = .WriteString("<dt>")
		}
	} else {
		_, _ = .WriteString("</dt>\n")
	}
	return gast.WalkContinue, nil
}

// DefinitionDescriptionAttributeFilter defines attribute names which dd elements can have.
var DefinitionDescriptionAttributeFilter = html.GlobalAttributeFilter

func ( *DefinitionListHTMLRenderer) (
	 util.BufWriter,  []byte,  gast.Node,  bool) (gast.WalkStatus, error) {
	if  {
		 := .(*ast.DefinitionDescription)
		_, _ = .WriteString("<dd")
		if .Attributes() != nil {
			html.RenderAttributes(, , DefinitionDescriptionAttributeFilter)
		}
		if .IsTight {
			_, _ = .WriteString(">")
		} else {
			_, _ = .WriteString(">\n")
		}
	} else {
		_, _ = .WriteString("</dd>\n")
	}
	return gast.WalkContinue, nil
}

type definitionList struct {
}

// DefinitionList is an extension that allow you to use PHP Markdown Extra Definition lists.
var DefinitionList = &definitionList{}

func ( *definitionList) ( goldmark.Markdown) {
	.Parser().AddOptions(parser.WithBlockParsers(
		util.Prioritized(NewDefinitionListParser(), 101),
		util.Prioritized(NewDefinitionDescriptionParser(), 102),
	))
	.Renderer().AddOptions(renderer.WithNodeRenderers(
		util.Prioritized(NewDefinitionListHTMLRenderer(), 500),
	))
}