/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

package main

import (
	"encoding/json"
	ui "github.com/VladimirMarkelov/clui"
	"io/ioutil"
	"os"
	"path"

	"github.com/shibukawa/configdir"

	"code.vanwa.ch/sebastian/ecload/pkg/ecload"
)

var Version string
var Build string

const THEME = "//----------------- Theme properties -----------------" +
	"//----------------- Colors -----------------" +
	"// View colors - internal area and border" +
	"ViewBack = white" +
	"ViewText = white bold" +
	"// general colors" +
	"Back         = white" +
	"Text         = black" +
	"DisabledText = white" +
	"DisabledBack = black bold" +
	"// editable & listbox-like controls (interactive ones)" +
	"EditBack       = blue" +
	"EditText       = yellow" +
	"EditActiveBack = blue bold" +
	"EditActiveText = yellow bold" +
	"SelectionText  = yellow bold" +
	"SelectionBack  = cyan bold" +
	"// scroll control" +
	"ScrollText = white bold" +
	"ScrollBack = white" +
	"ThumbText  = white bold" +
	"ThumbBack  = white" +
	"// window-like controls (checkbox, radiogroup...)" +
	"ControlText         = black" +
	"ControlBack         = cyan bold" +
	"ControlActiveBack   = cyan bold" +
	"ControlActiveText   = yellow bold" +
	"ControlDisabledBack = cyan bold" +
	"ControlDisabledText = black bold" +
	"ControlShadow       = black" +
	"// progressbar control" +
	"ProgressBack       = blue" +
	"ProgressText       = yellow" +
	"ProgressActiveBack = blue bold" +
	"ProgressActiveText = yellow bold" +
	"// button control" +
	"ButtonBack=green bold" +
	"ButtonText=black" +
	"ButtonActiveBack=green bold" +
	"ButtonActiveText=white bold" +
	"ButtonShadowBack=black" +
	"ButtonDisabledText=black bold" +
	"ButtonDisabledBack=white" +
	"// bar chart control" +
	"BarChartBack=black" +
	"BarChartText=white" +
	"// spark chart" +
	"SparkChartBack=black" +
	"SparkChartText=white" +
	"SparkChartBarBack=black" +
	"SparkChartBarText=cyan" +
	"SparkChartMaxBack=black" +
	"SparkChartMaxText=cyan bold" +
	"// table view" +
	"TableText=white" +
	"TableBack=black" +
	"TableSelectedText=white" +
	"TableSelectedBack=black bold" +
	"TableActiveCellText=white bold" +
	"TableActiveCellBack=black bold" +
	"TableLineText=white" +
	"TableHeaderText=white" +
	"TableHeaderBack=black" +
	"//----------------- Objects -----------------" +
	"SingleBorder=─│┌┐└┘" +
	"DoubleBorder=═║╔╗╚╝" +
	"Edit=←→V*" +
	"ScrollBar=░■▲▼◄►" +
	"ViewButtons=^_■[]" +
	"CheckBox=[] X?" +
	"Radio=() *" +
	"ProgressBar=░▒" +
	"BarChart=█─│┌┐└┘┬┴├┤┼" +
	"SparkChart=█" +
	"TableView=─│┼▼▲"

const VENDOR = "vanwa.ch"
const APPNAME = "ecload"
const SETTINGNAME = "last.json"

const WAITWIDTH = 40
const WAITHEIGHT = 10

type settings struct {
	Out string
	Size int
}

func main() {
	logger := ecload.InitLogger(ioutil.Discard, ioutil.Discard, ioutil.Discard, ioutil.Discard)

	tmp, err := ioutil.TempDir("", "ecload")
	if err != nil {
		logger.Error.Println(err)
		os.Exit(1)
	}

	defer os.RemoveAll(tmp)

	err = ioutil.WriteFile(path.Join(tmp, "ecload.theme"), []byte(THEME), 0600)
	if err != nil {
		logger.Error.Println(err)
		os.Exit(1)
	}

	mainLoop(tmp, logger)
}

func createView(themeDir string, logger ecload.Logger) {
	configDirs := configdir.New(VENDOR, APPNAME)
	cache := configDirs.QueryCacheFolder()

	sizes := []string{"small", "medium", "large", "max"}
	outPath, _ := os.UserHomeDir()
	size := 0

	if cache != nil {
		var config settings

		data, _ := cache.ReadFile(SETTINGNAME)
		err := json.Unmarshal(data, &config)

		if err == nil {
			if config.Out != "" {
				outPath = config.Out
			}
			size = config.Size
		}
	}

	ui.SetThemePath(themeDir)
	ui.SetCurrentTheme("ecload")

	view := ui.AddWindow(0, 0, 75, 10, "Download e-codices")
	view.SetPack(ui.Vertical)
	view.SetGaps(0, 1)
	view.SetPaddings(2, 2)
	view.SetSizable(false)

	frmPath := ui.CreateFrame(view, 1, 1, ui.BorderThin, ui.Fixed)
	frmPath.SetPack(ui.Vertical)
	frmPath.SetTitle("Download path")

	lblPath := ui.CreateLabel(frmPath, ui.AutoSize, ui.AutoSize, outPath, ui.Fixed)
	btnSet := ui.CreateButton(frmPath, ui.AutoSize, ui.AutoSize, "Select", ui.Fixed)

	frmSize := ui.CreateFrame(view, 1, 1, ui.BorderThin, ui.Fixed)
	frmSize.SetPack(ui.Vertical)
	frmSize.SetTitle("Size")
	rg := ui.CreateRadioGroup()

	for _, size := range sizes {
		radio := ui.CreateRadio(frmSize, ui.AutoSize, size, ui.Fixed)
		radio.OnActive(func(active bool) {
			go save(lblPath, rg)
		})
		rg.AddItem(radio)
	}
	rg.SetSelected(size)

	frmId := ui.CreateFrame(view, 1, 1, ui.BorderThin, ui.Fixed)
	frmId.SetTitle("Id")
	fldId := ui.CreateEditField(frmId, 70, "", ui.Fixed)

	frmBtns := ui.CreateFrame(view, 1, 1, ui.BorderNone, ui.Fixed)
	frmBtns.SetPack(ui.Vertical)
	btnStart := ui.CreateButton(frmBtns, ui.AutoSize, ui.AutoSize, "Download", ui.Fixed)
	btnStart.SetEnabled(false)

	ui.ActivateControl(view, fldId)

	fldId.OnChange(func(ev ui.Event) {
		allowStart := fldId.Title() != ""
		btnStart.SetEnabled(allowStart)
	})

	btnSet.OnClick(func(ev ui.Event) {
		s := "Select directory"

		dlg := ui.CreateFileSelectDialog(
			s,
			"*",
			outPath,
			true,
			true)
		dlg.OnClose(func() {
			if dlg.Selected {
				lblPath.SetTitle(dlg.FilePath)
				go save(lblPath, rg)
			}
		})
	})

	btnStart.OnClick(func(ev ui.Event) {
		size := sizes[rg.Selected()]
		w, h := view.Size()

		wait := ui.AddWindow(w / 2 - WAITWIDTH / 2, h / 2 - WAITHEIGHT / 2, WAITWIDTH, WAITHEIGHT, "Downloading...")
		wait.SetModal(true)
		wait.SetPack(ui.Vertical)
		wait.SetGaps(0, 1)
		wait.SetPaddings(2, 2)
		wait.SetSizable(false)

		ui.CreateLabel(wait, ui.AutoSize, ui.AutoSize, "Please be patient. Maybe bring me some tea.", ui.Fixed)

		ec := make(chan error)
		finished := make(chan bool, 1)

		go func(out string, size string, id string, logger ecload.Logger) {
			err := ecload.DownloadBook(lblPath.Title(), size, fldId.Title(), logger)
			if err != nil {
				ec <- err
			} else {
				close(finished)
			}

		}(lblPath.Title(), size, fldId.Title(), logger)

		select {
		case <-finished:
			successDlg := ui.CreateAlertDialog("Success", "Download finished.", "Yay!")
			successDlg.OnClose(func() {
				ui.PutEvent(ui.Event{Type: ui.EventCloseWindow})
				ui.ActivateControl(view, fldId)
			})
		case err := <-ec:
			if err != nil {
				errorDlg := ui.CreateAlertDialog("Error", err.Error(), "Ah well")
				errorDlg.OnClose(func() {
					ui.PutEvent(ui.Event{Type: ui.EventCloseWindow})
					ui.ActivateControl(view, fldId)
				})
			}
		}
	})
}

func save(lblPath *ui.Label, rg *ui.RadioGroup) {
	configDirs := configdir.New(VENDOR, APPNAME)
	cache := configDirs.QueryCacheFolder()

	config := settings { Out: lblPath.Title(), Size: rg.Selected() }
	data, _ := json.Marshal(&config)

	cache.WriteFile(SETTINGNAME, data)
}

func mainLoop(themeDir string, logger ecload.Logger) {
	ui.InitLibrary()
	defer ui.DeinitLibrary()

	createView(themeDir, logger)

	ui.MainLoop()
}
