package text

import (
	
	
	
	

	
)

const invalidValue = -1

// EOF indicates the end of file.
const EOF = byte(0xff)

// A Reader interface provides abstracted method for reading text.
type Reader interface {
	io.RuneReader

	// Source returns a source of the reader.
	Source() []byte

	// ResetPosition resets positions.
	ResetPosition()

	// Peek returns a byte at current position without advancing the internal pointer.
	Peek() byte

	// PeekLine returns the current line without advancing the internal pointer.
	PeekLine() ([]byte, Segment)

	// PrecendingCharacter returns a character just before current internal pointer.
	PrecendingCharacter() rune

	// Value returns a value of the given segment.
	Value(Segment) []byte

	// LineOffset returns a distance from the line head to current position.
	LineOffset() int

	// Position returns current line number and position.
	Position() (int, Segment)

	// SetPosition sets current line number and position.
	SetPosition(int, Segment)

	// SetPadding sets padding to the reader.
	SetPadding(int)

	// Advance advances the internal pointer.
	Advance(int)

	// AdvanceAndSetPadding advances the internal pointer and add padding to the
	// reader.
	AdvanceAndSetPadding(int, int)

	// AdvanceLine advances the internal pointer to the next line head.
	AdvanceLine()

	// SkipSpaces skips space characters and returns a non-blank line.
	// If it reaches EOF, returns false.
	SkipSpaces() (Segment, int, bool)

	// SkipSpaces skips blank lines and returns a non-blank line.
	// If it reaches EOF, returns false.
	SkipBlankLines() (Segment, int, bool)

	// Match performs regular expression matching to current line.
	Match(reg *regexp.Regexp) bool

	// Match performs regular expression searching to current line.
	FindSubMatch(reg *regexp.Regexp) [][]byte

	// FindClosure finds corresponding closure.
	FindClosure(opener, closer byte, options FindClosureOptions) (*Segments, bool)
}

// FindClosureOptions is options for Reader.FindClosure.
type FindClosureOptions struct {
	// CodeSpan is a flag for the FindClosure. If this is set to true,
	// FindClosure ignores closers in codespans.
	CodeSpan bool

	// Nesting is a flag for the FindClosure. If this is set to true,
	// FindClosure allows nesting.
	Nesting bool

	// Newline is a flag for the FindClosure. If this is set to true,
	// FindClosure searches for a closer over multiple lines.
	Newline bool

	// Advance is a flag for the FindClosure. If this is set to true,
	// FindClosure advances pointers when closer is found.
	Advance bool
}

type reader struct {
	source       []byte
	sourceLength int
	line         int
	peekedLine   []byte
	pos          Segment
	head         int
	lineOffset   int
}

// NewReader return a new Reader that can read UTF-8 bytes .
func ( []byte) Reader {
	 := &reader{
		source:       ,
		sourceLength: len(),
	}
	.ResetPosition()
	return 
}

func ( *reader) (,  byte,  FindClosureOptions) (*Segments, bool) {
	return findClosureReader(, , , )
}

func ( *reader) () {
	.line = -1
	.head = 0
	.lineOffset = -1
	.AdvanceLine()
}

func ( *reader) () []byte {
	return .source
}

func ( *reader) ( Segment) []byte {
	return .Value(.source)
}

func ( *reader) () byte {
	if .pos.Start >= 0 && .pos.Start < .sourceLength {
		if .pos.Padding != 0 {
			return space[0]
		}
		return .source[.pos.Start]
	}
	return EOF
}

func ( *reader) () ([]byte, Segment) {
	if .pos.Start >= 0 && .pos.Start < .sourceLength {
		if .peekedLine == nil {
			.peekedLine = .pos.Value(.Source())
		}
		return .peekedLine, .pos
	}
	return nil, .pos
}

// io.RuneReader interface.
func ( *reader) () (rune, int, error) {
	return readRuneReader()
}

func ( *reader) () int {
	if .lineOffset < 0 {
		 := 0
		for  := .head;  < .pos.Start; ++ {
			if .source[] == '\t' {
				 += util.TabWidth()
			} else {
				++
			}
		}
		.lineOffset =  - .pos.Padding
	}
	return .lineOffset
}

func ( *reader) () rune {
	if .pos.Start <= 0 {
		if .pos.Padding != 0 {
			return rune(' ')
		}
		return rune('\n')
	}
	 := .pos.Start - 1
	for ;  >= 0; -- {
		if utf8.RuneStart(.source[]) {
			break
		}
	}
	,  := utf8.DecodeRune(.source[:])
	return 
}

func ( *reader) ( int) {
	.lineOffset = -1
	if  < len(.peekedLine) && .pos.Padding == 0 {
		.pos.Start += 
		.peekedLine = nil
		return
	}
	.peekedLine = nil
	 := .sourceLength
	for ;  > 0 && .pos.Start < ; -- {
		if .pos.Padding != 0 {
			.pos.Padding--
			continue
		}
		if .source[.pos.Start] == '\n' {
			.AdvanceLine()
			continue
		}
		.pos.Start++
	}
}

func ( *reader) (,  int) {
	.Advance()
	if  > .pos.Padding {
		.SetPadding()
	}
}

func ( *reader) () {
	.lineOffset = -1
	.peekedLine = nil
	.pos.Start = .pos.Stop
	.head = .pos.Start
	if .pos.Start < 0 {
		return
	}
	.pos.Stop = .sourceLength
	for  := .pos.Start;  < .sourceLength; ++ {
		 := .source[]
		if  == '\n' {
			.pos.Stop =  + 1
			break
		}
	}
	.line++
	.pos.Padding = 0
}

func ( *reader) () (int, Segment) {
	return .line, .pos
}

func ( *reader) ( int,  Segment) {
	.lineOffset = -1
	.line = 
	.pos = 
}

func ( *reader) ( int) {
	.pos.Padding = 
}

func ( *reader) () (Segment, int, bool) {
	return skipSpacesReader()
}

func ( *reader) () (Segment, int, bool) {
	return skipBlankLinesReader()
}

func ( *reader) ( *regexp.Regexp) bool {
	return matchReader(, )
}

func ( *reader) ( *regexp.Regexp) [][]byte {
	return findSubMatchReader(, )
}

// A BlockReader interface is a reader that is optimized for Blocks.
type BlockReader interface {
	Reader
	// Reset resets current state and sets new segments to the reader.
	Reset(segment *Segments)
}

type blockReader struct {
	source         []byte
	segments       *Segments
	segmentsLength int
	line           int
	pos            Segment
	head           int
	last           int
	lineOffset     int
}

// NewBlockReader returns a new BlockReader.
func ( []byte,  *Segments) BlockReader {
	 := &blockReader{
		source: ,
	}
	if  != nil {
		.Reset()
	}
	return 
}

func ( *blockReader) (,  byte,  FindClosureOptions) (*Segments, bool) {
	return findClosureReader(, , , )
}

func ( *blockReader) () {
	.line = -1
	.head = 0
	.last = 0
	.lineOffset = -1
	.pos.Start = -1
	.pos.Stop = -1
	.pos.Padding = 0
	if .segmentsLength > 0 {
		 := .segments.At(.segmentsLength - 1)
		.last = .Stop
	}
	.AdvanceLine()
}

func ( *blockReader) ( *Segments) {
	.segments = 
	.segmentsLength = .Len()
	.ResetPosition()
}

func ( *blockReader) () []byte {
	return .source
}

func ( *blockReader) ( Segment) []byte {
	 := .segmentsLength - 1
	 := make([]byte, 0, .Stop-.Start+1)
	for ;  >= 0; -- {
		if .Start >= .segments.At().Start {
			break
		}
	}
	 := .Start
	for ;  < .segmentsLength; ++ {
		 := .segments.At()
		if  < 0 {
			 = .Start
		}
		 = .ConcatPadding()
		for ;  < .Stop &&  < .Stop; ++ {
			 = append(, .source[])
		}
		 = -1
		if .Stop > .Stop {
			break
		}
	}
	return 
}

// io.RuneReader interface.
func ( *blockReader) () (rune, int, error) {
	return readRuneReader()
}

func ( *blockReader) () rune {
	if .pos.Padding != 0 {
		return rune(' ')
	}
	if .segments.Len() < 1 {
		return rune('\n')
	}
	 := .segments.At(0)
	if .line == 0 && .pos.Start <= .Start {
		return rune('\n')
	}
	 := len(.source)
	 := .pos.Start - 1
	for ;  <  &&  >= 0; -- {
		if utf8.RuneStart(.source[]) {
			break
		}
	}
	if  < 0 ||  >=  {
		return rune('\n')
	}
	,  := utf8.DecodeRune(.source[:])
	return 
}

func ( *blockReader) () int {
	if .lineOffset < 0 {
		 := 0
		for  := .head;  < .pos.Start; ++ {
			if .source[] == '\t' {
				 += util.TabWidth()
			} else {
				++
			}
		}
		.lineOffset =  - .pos.Padding
	}
	return .lineOffset
}

func ( *blockReader) () byte {
	if .line < .segmentsLength && .pos.Start >= 0 && .pos.Start < .last {
		if .pos.Padding != 0 {
			return space[0]
		}
		return .source[.pos.Start]
	}
	return EOF
}

func ( *blockReader) () ([]byte, Segment) {
	if .line < .segmentsLength && .pos.Start >= 0 && .pos.Start < .last {
		return .pos.Value(.source), .pos
	}
	return nil, .pos
}

func ( *blockReader) ( int) {
	.lineOffset = -1

	if  < .pos.Stop-.pos.Start && .pos.Padding == 0 {
		.pos.Start += 
		return
	}

	for ;  > 0; -- {
		if .pos.Padding != 0 {
			.pos.Padding--
			continue
		}
		if .pos.Start >= .pos.Stop-1 && .pos.Stop < .last {
			.AdvanceLine()
			continue
		}
		.pos.Start++
	}
}

func ( *blockReader) (,  int) {
	.Advance()
	if  > .pos.Padding {
		.SetPadding()
	}
}

func ( *blockReader) () {
	.SetPosition(.line+1, NewSegment(invalidValue, invalidValue))
	.head = .pos.Start
}

func ( *blockReader) () (int, Segment) {
	return .line, .pos
}

func ( *blockReader) ( int,  Segment) {
	.lineOffset = -1
	.line = 
	if .Start == invalidValue {
		if .line < .segmentsLength {
			 := .segments.At()
			.head = .Start
			.pos = 
		}
	} else {
		.pos = 
		if .line < .segmentsLength {
			 := .segments.At()
			.head = .Start
		}
	}
}

func ( *blockReader) ( int) {
	.lineOffset = -1
	.pos.Padding = 
}

func ( *blockReader) () (Segment, int, bool) {
	return skipSpacesReader()
}

func ( *blockReader) () (Segment, int, bool) {
	return skipBlankLinesReader()
}

func ( *blockReader) ( *regexp.Regexp) bool {
	return matchReader(, )
}

func ( *blockReader) ( *regexp.Regexp) [][]byte {
	return findSubMatchReader(, )
}

func skipBlankLinesReader( Reader) (Segment, int, bool) {
	 := 0
	for {
		,  := .PeekLine()
		if  == nil {
			return , , false
		}
		if util.IsBlank() {
			++
			.AdvanceLine()
		} else {
			return , , true
		}
	}
}

func skipSpacesReader( Reader) (Segment, int, bool) {
	 := 0
	for {
		,  := .PeekLine()
		if  == nil {
			return , , false
		}
		for ,  := range  {
			if util.IsSpace() {
				++
				.Advance(1)
				continue
			}
			return .WithStart(.Start +  + 1), , true
		}
	}
}

func matchReader( Reader,  *regexp.Regexp) bool {
	,  := .Position()
	 := .FindReaderSubmatchIndex()
	.SetPosition(, )
	if  == nil {
		return false
	}
	.Advance([1] - [0])
	return true
}

func findSubMatchReader( Reader,  *regexp.Regexp) [][]byte {
	,  := .Position()
	 := .FindReaderSubmatchIndex()
	.SetPosition(, )
	if  == nil {
		return nil
	}
	var  bytes.Buffer
	.Grow([1] - [0])
	for  := 0;  < [1]; {
		, ,  := readRuneReader()
		 += 
		.WriteRune()
	}
	 := .Bytes()
	var  [][]byte
	for  := 0;  < len();  += 2 {
		if [] < 0 {
			 = append(, []byte{})
			continue
		}
		 = append(, [[]:[+1]])
	}

	.SetPosition(, )
	.Advance([1] - [0])
	return 
}

func readRuneReader( Reader) (rune, int, error) {
	,  := .PeekLine()
	if  == nil {
		return 0, 0, io.EOF
	}
	,  := utf8.DecodeRune()
	if  == utf8.RuneError {
		return 0, 0, io.EOF
	}
	.Advance()
	return , , nil
}

func findClosureReader( Reader, ,  byte,  FindClosureOptions) (*Segments, bool) {
	 := 1
	 := 0
	 := false
	,  := .Position()
	var  *Segments

	for {
		,  := .PeekLine()
		if  == nil {
			goto 
		}
		 := 0
		for  < len() {
			 := []
			if .CodeSpan &&  != 0 &&  == '`' {
				 := 0
				for ;  < len(); ++ {
					if [] == '`' {
						++
					} else {
						--
						break
					}
				}
				if  ==  {
					 = 0
				}
			} else if  == 0 &&  == '\\' &&  < len()-1 && util.IsPunct([+1]) {
				 += 2
				continue
			} else if .CodeSpan &&  == 0 &&  == '`' {
				for ;  < len(); ++ {
					if [] == '`' {
						++
					} else {
						--
						break
					}
				}
			} else if (.CodeSpan &&  == 0) || !.CodeSpan {
				if  ==  {
					--
					if  == 0 {
						if  == nil {
							 = NewSegments()
						}
						.Append(.WithStop(.Start + ))
						.Advance( + 1)
						 = true
						goto 
					}
				} else if  ==  {
					if !.Nesting {
						goto 
					}
					++
				}
			}
			++
		}
		if !.Newline {
			goto 
		}
		.AdvanceLine()
		if  == nil {
			 = NewSegments()
		}
		.Append()
	}
:
	if !.Advance {
		.SetPosition(, )
	}
	if  {
		return , true
	}
	return nil, false
}