package main

import (
	"flag"
	"github.com/natefinch/lumberjack"
	"log"
	"os"
	"os/exec"
	"strconv"
	"sync"
)

var config Config

const sockfile = "/tmp/gopaper.sock"
const pidfilePath = "/tmp/gopaper.pid"

var clog = log.New(os.Stdout, "## ", 0)
var elog = log.New(os.Stdout, "ERROR: ", 3)

func main() {
	//SETUP FLAGS
	var debugFlag = flag.Bool("debug", false, "help message for flag n")
	var dirFlag = flag.String("dir", "", "help message")
	flag.Parse()

	clog.Println("Welcome to GoPaper!")

	//INIT CONFIG
	err := config.load()
	if err != nil {
		elog.Println("unable to initialize config", err)
	}
	handleProcesses()
	setupLogging(*debugFlag)

	var waitGroup sync.WaitGroup
	waitGroup.Add(1)
	slideshowDir := make(chan string)

	func() {
		defer func() {
			if r := recover(); r != nil {
				log.Println("Panic recovered at top level", r)
				cleanExit(1)
			}
		}()
		go server(slideshowDir)
		go slideshow(slideshowDir)
	}()

	slideshowDir <- *dirFlag

	waitGroup.Wait()
}

func cleanExit(code int) {
	if code == 1 {
		log.Println("shutting down gracefully after errors")
	} else {
		log.Println("shutting down gracefully")
	}

	err := os.Remove(sockfile)
	if err != nil && !os.IsNotExist(err) {
		elog.Printf("unable to remove sockfile at %v. Error: %v\n", sockfile, err)
	} else if !os.IsNotExist(err) {
		log.Println("sockfile removed")
	} else {
		log.Println("no need to remove sockfile -- it doesn't exist")
	}

	err = os.Remove(pidfilePath)
	if err != nil && !os.IsNotExist(err) {
		elog.Printf("unable to remove pidfile at %v. Error: %v\n", pidfilePath, err)
	} else if !os.IsNotExist(err) {
		log.Println("pidfile removed")
	} else {
		log.Println("no need to remove pidfile -- it doesn't exist")
	}
	os.Exit(code)
}

func killPrevProc() error {
	//check if pidfile already exists
	if _, err := os.Stat(pidfilePath); os.IsNotExist(err) {
		return nil
	}
	//if it does, kill the process and delete the pidfile
	prexPid, err := os.ReadFile(pidfilePath)
	if err != nil {
		elog.Println("unable to read pre-existing pidfile", err)
		return err
	}
	//kill process
	err = exec.Command("kill", string(prexPid)).Run()
	if err != nil {
		elog.Printf("Error attempting to kill process %v: %v\n", string(prexPid), err)
	}
	//remove pidfile
	err = os.Remove(pidfilePath)
	if err != nil && !os.IsNotExist(err) {
		elog.Printf("unable to remove pidfile at %v. Error: %v\n", pidfilePath, err)
	}
	return nil
}
func handleProcesses() {
	err := killPrevProc()
	if err != nil {
		elog.Println("error attempting to kill pre-existing process: ", err)
		os.Exit(1)
	}
	//create new pidfile
	pid := strconv.FormatInt(int64(os.Getpid()), 10)
	pidfile, err := os.Create(pidfilePath)
	if err != nil {
		elog.Println("error trying to create pidfile:", err)
		os.Exit(1)
	}
	pidfile.WriteString(pid)

}

func setupLogging(debug bool) {
	clog.Printf("debug: %v", debug)
	//SETUP LOGGERS
	if debug {
		logfile := config.Cache + "logfile"
		clog.Printf("Logging to %v", logfile)
		output := &lumberjack.Logger{
			Filename:   logfile,
			MaxSize:    1,  // megabytes after which new file is created
			MaxBackups: 3,  // number of backups
			MaxAge:     28, //days
		}
		log.SetOutput(output)
		clog.SetOutput(output)
		elog.SetOutput(output)
	}
	elog.SetFlags(log.LstdFlags | log.Lshortfile)
	log.SetFlags(log.LstdFlags)
}
