//
// gsh - Go lang based Shell
// (c) 2020 ITS more Co., Ltd.
// 2020-0807 created by SatoxITS (sato@its-more.jp)
//
// Reference: https://golang.org/pkg/
//
package main // gsh main

import (
	"bufio"
	"strings"
	"fmt"
	"os"
	"time"
	"syscall"
	"go/types"
	"go/token"
)

var VERSION = "gsh/0.0.1 (2020-0807a)"
var LINESIZE = (8*1024)
var PATHSEP = ":" // should be ";" in Windows
var PROMPT = "> "

func env(argv []string) {
	env := os.Environ()
	for _, v := range env {
		fmt.Printf("%v\n",v)
	}
}
func which(path string, show bool) (fullpath string, itis bool){
	pathenv, found := os.LookupEnv("PATH")
	if found {
		dirv := strings.Split(pathenv,PATHSEP)
		for _, dir := range dirv {
			fi, err := os.Stat(dir+"/"+path)
			if err == nil {
				fm := fi.Mode()
				if fm.IsRegular() {
					if show {
						fmt.Printf("%s\n",dir+"/"+path)
					}
					return dir+"/"+path, true
				}
			}
		}
	}
	return "", false
}
func eval(argv []string, nlend bool){
	var ai = 1
	pfmt := "%s"
	if argv[ai][0:1] == "%" {
		pfmt = argv[ai]
		ai = 2
	}
	if len(argv) <= ai {
		return
	}
	gocode := strings.Join(argv[ai:]," ");
	fset := token.NewFileSet()
	rval, _ := types.Eval(fset,nil,token.NoPos,gocode)
	fmt.Printf(pfmt,rval.Value)
	if nlend { fmt.Printf("\n") }
}
func excommand(exec bool, argv []string) (ret int) {
	fullpath, itis := which(argv[0],false)
	if itis == false {
		return -1
	}
	if exec {
		syscall.Exec(fullpath,argv,os.Environ())
	}else{
		start := time.Now()
		pa := syscall.ProcAttr {
			"",
			[]string{},
			[]uintptr{os.Stdin.Fd(),os.Stdout.Fd(),os.Stderr.Fd()},
			nil,
		}
		pid, _ := syscall.ForkExec(fullpath,argv,&pa)
		//fmt.Printf("[%d]\n",pid); // '&' to be background
		syscall.Wait4(pid,nil,0,nil);
		end := time.Now()
		elps := end.Sub(start);
		fmt.Printf("--(%d.%09ds)\n",elps/1000000000,elps%1000000000)
	}
	return 0
}
func main() {
	for hi := 0; ; hi++ {
		fmt.Printf("%d",hi)
		fmt.Print(PROMPT)
		reader := bufio.NewReaderSize(os.Stdin,LINESIZE);
		line, _, _ := reader.ReadLine()
		argv := strings.Split(string(line)," ");
		cmd := argv[0]
		if cmd == "exit" || cmd == "quit" {
			break
		}
		if cmd == "-ver" {
			fmt.Printf("%s\n",VERSION);
			continue;
		}
		if cmd == "env" {
			env(argv)
			continue;
		}
		if cmd == "eval" {
			eval(argv,true)
			continue;
		}
		if cmd == "which" {
			which(argv[1],true);
			continue;
		}
		if cmd == "exec" {
			excommand(true,argv[1:])
			continue; // should exit
		}
		excommand(false,argv)
	}
}
//---END--- (^-^)/