package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"

	"gopkg.in/ini.v1"
	"gordenko.dev/dima/diploma/database"
)

func main() {
	var (
		logfile     = os.Stdout
		iniFileName string
	)

	flag.Usage = func() {
		fmt.Fprint(flag.CommandLine.Output(), helpMessage)
		fmt.Fprint(flag.CommandLine.Output(), configExample)
		fmt.Fprintf(flag.CommandLine.Output(), mainUsage, os.Args[0])
		flag.PrintDefaults()
	}
	flag.StringVar(&iniFileName, "c", "database.ini", "path to *.ini config file")
	flag.Parse()

	config, err := loadConfig(iniFileName)
	if err != nil {
		log.Fatalln(err)
	}

	var (
		exitCh = make(chan struct{})
		wg     = new(sync.WaitGroup)
	)

	db, err := database.New(database.Options{
		TCPPort:      config.TcpPort,
		Dir:          config.Dir,
		DatabaseName: config.DatabaseName,
		RedoDir:      config.REDODir,
		Logfile:      logfile,
		ExitCh:       exitCh,
		WaitGroup:    wg,
	})
	if err != nil {
		log.Fatalf("database.New: %s\n", err)
	}

	go func() {
		err = db.ListenAndServe()
		if err != nil {
			log.Fatalln(err)
		}
	}()

	wg.Add(1)

	fmt.Fprintf(logfile, "database %q started on port %d.\n",
		config.DatabaseName, config.TcpPort)
	fmt.Fprintln(logfile, config)

	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	<-sigs

	close(exitCh)
	wg.Wait()

	fmt.Fprintln(logfile, "database stopped.")
}

// config file

const mainUsage = `Usage:
	%s -c path/to/config.ini

`

const helpMessage = `Diploma project. Database. Version: 1.0
created by Dmytro Gordenko, 1.e4.kc6@gmail.com
`

const configExample = `
database.ini example:

tcpPort      = 12345
dir          = ../../datadir
redoDir      = ../../datadir
databaseName = test

`

type Config struct {
	TcpPort      int
	Dir          string
	REDODir      string
	DatabaseName string
}

func (s Config) String() string {
	return fmt.Sprintf(`starting options:
tcpPort      = %d
dir          = %s
redoDir      = %s
databaseName = %s
`,
		s.TcpPort, s.Dir, s.REDODir, s.DatabaseName)
}

func loadConfig(iniFileName string) (_ Config, err error) {
	file, err := ini.Load(iniFileName)
	if err != nil {
		return
	}

	conf := Config{}

	top := file.Section("")

	conf.TcpPort, err = top.Key("tcpPort").Int()
	if err != nil {
		err = fmt.Errorf("'tcpPort' option is required in config file")
		return
	}
	conf.Dir = top.Key("dir").String()
	conf.REDODir = top.Key("redoDir").String()
	conf.DatabaseName = top.Key("databaseName").String()
	return conf, nil
}
