package parser

import 

// check if the specified position is preceded by an odd number of backslashes
func isBackslashEscaped( []byte,  int) bool {
	 := 0
	for --1 >= 0 && [--1] == '\\' {
		++
	}
	return &1 == 1
}

func ( *Parser) ( []byte,  []ast.CellAlignFlags,  bool) {
	.AddBlock(&ast.TableRow{})
	 := 0

	 := skipChar(, 0, '|')

	 := len()
	 := 0 // keep track of total colspan in this row.
	for  = 0;  < len() &&  < ; ++ {
		 := 0
		 = skipChar(, , ' ')

		 := 

		// If we are in a codespan we should discount any | we see, check for that here and skip ahead.
		if ,  := codeSpan(, [:], 0);  > 0 {
			 +=  - 1
		}

		for  <  && ([] != '|' || isBackslashEscaped(, )) && [] != '\n' {
			++
		}

		 := 

		// skip the end-of-cell marker, possibly taking us past end of buffer
		// each _extra_ | means a colspan
		for  < len() && [] == '|' && !isBackslashEscaped(, ) {
			++
			++
		}
		// only colspan > 1 make sense.
		if  < 2 {
			 = 0
		}

		for  >  && -1 <  && [-1] == ' ' {
			--
		}

		 := &ast.TableCell{
			IsHeader: ,
			Align:    [],
			ColSpan:  ,
		}
		.Content = [:]
		if  ==  &&  > 0 {
			// an empty cell that we should ignore, it exists because of colspan
			--
		} else {
			.AddBlock()
		}

		if  > 0 {
			 +=  - 1
		}
	}

	// pad it out with empty columns to get the right number
	for ;  < len(); ++ {
		 := &ast.TableCell{
			IsHeader: ,
			Align:    [],
		}
		.AddBlock()
	}

	// silently ignore rows with too many cells
}

// tableFooter parses the (optional) table footer.
func ( *Parser) ( []byte) bool {
	 := 1

	// ignore up to 3 spaces
	 := len()
	 := skipCharN(, 0, ' ', 3)
	for ;  <  && [] != '\n'; ++ {
		// If we are in a codespan we should discount any | we see, check for that here and skip ahead.
		if ,  := codeSpan(, [:], 0);  > 0 {
			 +=  - 1
		}

		if [] == '|' && !isBackslashEscaped(, ) {
			++
			continue
		}
		// remaining data must be the = character
		if [] != '=' {
			return false
		}
	}

	// doesn't look like a table footer
	if  == 1 {
		return false
	}

	.AddBlock(&ast.TableFooter{})

	return true
}

// tableHeaders parses the header. If recognized it will also add a table.
func ( *Parser) ( []byte,  bool) ( int,  []ast.CellAlignFlags,  ast.Node) {
	 := 0
	 := 1
	 := true
	 := true
	for  = 0;  < len() && [] != '\n'; ++ {
		// If we are in a codespan we should discount any | we see, check for that here and skip ahead.
		if ,  := codeSpan(, [:], 0);  > 0 {
			 +=  - 1
		}

		if [] == '|' && !isBackslashEscaped(, ) {
			++
		}
		if [] != '-' && [] != ' ' && [] != ':' && [] != '|' {
			 = false
		}
		if [] != ' ' && [] != '|' {
			 = false
		}
	}

	// doesn't look like a table header
	if  == 1 {
		return
	}

	// include the newline in the data sent to tableRow
	 := skipCharN(, , '\n', 1)
	 := [:]

	// column count ignores pipes at beginning or end of line
	if [0] == '|' {
		--
	}
	{
		 := 
		// remove whitespace from the end
		for len() > 0 {
			 := len() - 1
			if [] == '\n' || [] == ' ' {
				 = [:]
			} else {
				break
			}
		}
		 := len()
		if  > 2 && [-1] == '|' && !isBackslashEscaped(, -1) {
			--
		}
	}

	// if the header looks like a underline, then we omit the header
	// and parse the first line again as underline
	if  && ! {
		 = nil
		 = 0
	} else {
		++ // move past newline
	}

	 = make([]ast.CellAlignFlags, )

	// move on to the header underline
	if  >= len() {
		return
	}

	if [] == '|' && !isBackslashEscaped(, ) {
		++
	}
	 = skipChar(, , ' ')

	// each column header is of form: / *:?-+:? *|/ with # dashes + # colons >= 3
	// and trailing | optional on last column
	 := 0
	 := len()
	for  <  && [] != '\n' {
		 := 0

		if [] == ':' {
			++
			[] |= ast.TableAlignmentLeft
			++
		}
		for  <  && [] == '-' {
			++
			++
		}
		if  <  && [] == ':' {
			++
			[] |= ast.TableAlignmentRight
			++
		}
		for  <  && [] == ' ' {
			++
		}
		if  ==  {
			return
		}
		// end of column test is messy
		switch {
		case  < 1:
			// not a valid column
			return

		case [] == '|' && !isBackslashEscaped(, ):
			// marker found, now skip past trailing whitespace
			++
			++
			for  <  && [] == ' ' {
				++
			}

			// trailing junk found after last column
			if  >=  &&  < len() && [] != '\n' {
				return
			}

		case ([] != '|' || isBackslashEscaped(, )) && +1 < :
			// something else found where marker was required
			return

		case [] == '\n':
			// marker is optional for the last column
			++

		default:
			// trailing junk found after last column
			return
		}
	}
	if  !=  {
		return
	}

	if  {
		 = &ast.Table{}
		.AddBlock()
		if  != nil {
			.AddBlock(&ast.TableHeader{})
			.tableRow(, , true)
		}
	}
	 = skipCharN(, , '\n', 1)
	return
}

/*
Table:

Name  | Age | Phone
------|-----|---------
Bob   | 31  | 555-1234
Alice | 27  | 555-4321
*/
func ( *Parser) ( []byte) int {
	, ,  := .tableHeader(, true)
	if  == 0 {
		return 0
	}

	.AddBlock(&ast.TableBody{})

	for  < len() {
		,  := 0, 
		for ;  < len() && [] != '\n'; ++ {
			if [] == '|' {
				++
			}
		}

		if  == 0 {
			 = 
			break
		}

		// include the newline in data sent to tableRow
		 = skipCharN(, , '\n', 1)

		if .tableFooter([:]) {
			continue
		}

		.tableRow([:], , false)
	}
	if , ,  := .caption([:], []byte(captionTable));  > 0 {
		 := &ast.Caption{}
		.Inline(, )

		// Some switcheroo to re-insert the parsed table as a child of the captionfigure.
		 := &ast.CaptionFigure{}
		.HeadingID = 
		 := &ast.Table{}
		// Retain any block level attributes.
		.AsContainer().Attribute = .AsContainer().Attribute
		 := .GetChildren()
		ast.RemoveFromTree()

		.SetChildren()
		ast.AppendChild(, )
		ast.AppendChild(, )

		.addChild()
		.Finalize()

		 += 
	}

	return 
}