package main

import (
	"fmt"
	"os"
	"os/signal"
	"time"

	"io"

	"bitbucket.org/nemt/nemt-portal-api/data"
	"bitbucket.org/nemt/nemt-portal-api/domain/service"
	"bitbucket.org/nemt/nemt-portal-api/infra/cache"
	"bitbucket.org/nemt/nemt-portal-api/infra/config"
	"bitbucket.org/nemt/nemt-portal-api/infra/logger"
	"bitbucket.org/nemt/nemt-portal-api/server"
)

func main() {
	var err error

	cfg, err := config.Read()
	endAsErr(err, "Could not read configuration file.", os.Stdout, os.Stderr)

	log, err := logger.New(cfg)
	endAsErr(err, "Could not create logging structure.", os.Stdout, os.Stderr)

	log.Printf("Connecting to the database at %s:%d.\n", cfg.DB.Host, cfg.DB.Port)
	db, err := data.Connect(cfg)
	endAsErr(err, "Could not connect to database.", log.InfoWriter(), log.ErrorWriter())
	atInterruption(func() {
		log.Printf("Closing DB Connection.")
		db.Close()
	})

	log.Printf("Connecting to the cache server at %s:%d.\n", cfg.Cache.Server, cfg.Cache.Port)
	cache := cache.Instance(cfg)

	svc, err := service.New(db, cache, cfg, log)
	endAsErr(err, "Could not create service structure.", log.InfoWriter(), log.ErrorWriter())

	// Runs server.
	log.Info("Runninng server at localhost:", cfg.HTTP.Port)
	err = server.Instance(svc, cfg, log, cache).Run()
	endAsErr(err, "Could not start the server.", log.InfoWriter(), log.ErrorWriter())
}

func atInterruption(fn func()) {
	go func() {
		sc := make(chan os.Signal, 1)
		signal.Notify(sc, os.Interrupt)
		<-sc

		fn()
		os.Exit(0)
	}()
}

func endAsErr(err error, message string, infow io.Writer, errorw io.Writer) {
	if err != nil {
		fmt.Fprintln(errorw, "Error:", err)
		fmt.Fprintln(infow, message)
		time.Sleep(time.Millisecond * 50) // needed for printing all messages before exiting
		os.Exit(1)
	}
}
