package main

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	//	"sort"
)

import "src.eruta.nl/beoran/attl"
import "github.com/peterh/liner"

func runLine(env *attl.Environment, in string) *attl.Error {
	parsed, err := attl.Parse(in)
	if err != nil {
		return err
	}
	if parsed == nil {
		return attl.ErrorFromString("No parse results")
	}
	val, eff := parsed.Eval(env)
	if val != nil {
		env.Printi(">>${1}\n", val)
	} else {
		env.Printi(">>nil\n")
	}
	err, ok := eff.(*attl.Error)
	if ok {
		return err
	}
	return nil
}

func runLines(env *attl.Environment, line *liner.State) error {
	buf := ""
	for {
		if in, err := line.Prompt("> "); err == nil {
			first := ';'
			if len(in) > 0 {
				first = rune(in[0])
			}
			if first == '\\' {
				buf = buf + "\n" + in[1:len(in)]
			} else {
				if len(buf) > 0 {
					buf = buf + "\n" + in
				} else {
					buf = in + "\n"
				}
				rerr := runLine(env, buf)
				buf = ""
				if rerr != nil {
					env.Printi("Error ${1}: \n", attl.String(rerr.Message))
				}
			}
			line.AppendHistory(in)
		} else if err == liner.ErrPromptAborted {
			env.Printi("Aborted\n")
			return nil
		} else if err == io.EOF {
			return nil
		} else {
			env.Printi("Error reading line: ${1}\n", attl.ErrorFromError(err))
		}
	}
	return nil
}

func runFile(env *attl.Environment, name string) *attl.Error {
	fin, err := os.Open(name)
	if err != nil {
		return attl.ErrorFromError(err)
	}
	defer fin.Close()
	buf, err := ioutil.ReadAll(fin)
	if err != nil {
		return attl.ErrorFromError(err)
	}
	in := string(buf)

	parsed, rerr := attl.Parse(in)
	if rerr != nil {
		return rerr
	}
	if parsed == nil {
		return attl.ErrorFromString("Parse result is empty.")
	}
	args := attl.List{}
	for _, a := range os.Args {
		args = append(args, attl.String(a))
	}
	_, reff := parsed.Eval(env, args...)
	rerr, ok := reff.(*attl.Error)
	if ok {
		return rerr
	}
	return nil
}

func main() {
	// console := muesli.NewStdConsole()
	env := &attl.Environment{}
	env.Out = os.Stdout
	env.Push()

	env.RegisterBuiltins()
	env.RegisterTuringCompleteBuiltins()
	line := liner.NewLiner()
	defer line.Close()

	line.SetCtrlCAborts(true)
	home, _ := os.UserHomeDir()
	historyName := filepath.Join(home, ".attl_history")

	if f, err := os.Open(historyName); err == nil {
		line.ReadHistory(f)
		f.Close()
	}

	if len(os.Args) > 1 {
		for _, name := range os.Args {
			rerr := runFile(env, name)
			if rerr != nil {
				sname := attl.String(name)
				env.Printi("error in ${1}: ${2}\n", sname,
					rerr)
			}
		}
		return
	}
	line.SetWordCompleter(func(line string, pos int) (head string, c []string, tail string) {
		return attl.WordCompleter(*env, line, pos)
	})
	runLines(env, line)

	if f, err := os.Create(historyName); err != nil {
		env.Printi("Error writing history file: ${1}\n", attl.ErrorFromError(err))
	} else {
		line.WriteHistory(f)
		f.Close()
	}
}
