package main

import (
	"errors"
	"io"
	"io/ioutil"
	"strings"
)

type lineParser struct {
	lines []string
	i     int
	err   error
}

var errUnexpectedEnd = errors.New("unexpected end of file")

func (p *lineParser) eof() bool    { return p.i == len(p.lines) }
func (p *lineParser) peek() string { return p.lines[p.i] }
func (p *lineParser) next() string {
	i := p.i
	p.i++
	return p.lines[i]
}

func (p *lineParser) emitErr(err error) parseLineFn {
	p.err = err
	return nil
}

func (p *lineParser) skipSpaceEOF() bool {
	for !p.eof() && len(strings.TrimSpace(p.peek())) == 0 {
		p.next()
	}
	return p.eof()
}

func skipSpaceBeforeContent(next parseLineFn) parseLineFn {
	return func(p *lineParser) parseLineFn {
		if p.skipSpaceEOF() {
			return p.emitErr(errUnexpectedEnd)
		}
		return next
	}
}

type parseLineFn func(p *lineParser) parseLineFn

func parseLines(r io.Reader, fn parseLineFn) error {
	content, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}
	lines := strings.Split(string(content), "\n")
	for i, line := range lines {
		lines[i] = strings.TrimRight(line, "\r\n")
	}

	parser := &lineParser{lines: lines}
	for fn != nil {
		fn = fn(parser)
	}
	return parser.err
}
