package lexer

import (
	"errors"
	"fmt"
	"strings"
)

var (
	_ error = (*Error)(nil)
)

var (
	// ErrUnacceptableRune indicates the read rune isn't acceptable in the context
	ErrUnacceptableRune = errors.New("rune not acceptable in context")

	// ErrNotImplemented indicates something hasn't been implemented yet
	ErrNotImplemented = errors.New("not implemented")
)

// Error represents a generic parsing error
type Error struct {
	Filename string
	Line     int
	Column   int

	Content string
	Hint    string
	Err     error
}

func (err Error) prefix() string {
	switch {
	case err.Line > 0 || err.Column > 0:
		if err.Filename != "" {
			return fmt.Sprintf("%s:%v:%v", err.Filename, err.Line, err.Column)
		}

		return fmt.Sprintf("%v:%v", err.Line, err.Column)
	default:
		return err.Filename
	}
}

func (err Error) Error() string {
	var s []string

	prefix := err.prefix()
	if prefix != "" {
		s = append(s, prefix)
	}

	if err.Err != nil {
		s = append(s, err.Err.Error())
	}

	if err.Content != "" {
		s = append(s, fmt.Sprintf("%q", err.Content))
	}

	if err.Hint != "" {
		s = append(s, err.Hint)
	}

	return strings.Join(s, ": ")
}

func (err Error) Unwrap() error {
	return err.Err
}