// Copyright 2014, 2015 by Sascha L. Teichmann
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"

	"bitbucket.org/s_l_teichmann/mtsatellite/common"

	"github.com/gorilla/mux"
)

func main() {
	var (
		webPort        int
		webHost        string
		webDir         string
		mapDir         string
		redisPort      int
		redisHost      string
		colorsFile     string
		bgColor        string
		workers        int
		transparent    bool
		transparentDim float64
		updateHosts    string
		websockets     bool
		playersFIFO    string
		version        bool
		yMin           int
		yMax           int
	)

	defaultBgColor := common.ColorToHex(common.BackgroundColor)

	flag.IntVar(&webPort, "web-port", 8808, "port of the web server")
	flag.IntVar(&webPort, "p", 8808, "port of the web server (shorthand)")
	flag.StringVar(&webHost, "web-host", "localhost", "address to bind web server")
	flag.StringVar(&webHost, "h", "localhost", "address to bind web server(shorthand)")
	flag.StringVar(&webDir, "web", "web", "static served web files.")
	flag.StringVar(&webDir, "w", "web", "static served web files (shorthand)")
	flag.StringVar(&mapDir, "map", "map", "directory of prerendered tiles")
	flag.StringVar(&mapDir, "m", "map", "directory of prerendered tiles (shorthand)")
	flag.StringVar(&updateHosts, "update-hosts", "localhost",
		"';' separated list of hosts which are allowed to send map update requests")
	flag.StringVar(&updateHosts, "u", "localhost",
		"';' separated list of hosts which are allowed to send map update requests (shorthand)")
	flag.StringVar(&redisHost, "redis-host", "", "address of the backend Redis server")
	flag.StringVar(&redisHost, "rh", "", "address of the backend Redis server (shorthand)")
	flag.IntVar(&redisPort, "redis-port", 6379, "port of the backend Redis server")
	flag.IntVar(&redisPort, "rp", 6379, "port of the backend Redis server (shorthand)")
	flag.IntVar(&workers, "workers", 1, "number of workers to render tiles")
	flag.StringVar(&colorsFile, "colors", "colors.txt", "colors used to render map tiles.")
	flag.StringVar(&colorsFile, "c", "colors.txt", "colors used to render map tiles (shorthand).")
	flag.StringVar(&bgColor, "background", defaultBgColor, "background color")
	flag.StringVar(&bgColor, "bg", defaultBgColor, "background color (shorthand)")
	flag.BoolVar(&transparent, "transparent", false, "Render transparent blocks.")
	flag.BoolVar(&transparent, "t", false, "Render transparent blocks (shorthand).")
	flag.Float64Var(&transparentDim,
		"transparent-dim", common.DefaultTransparentDim*100.0,
		"Extra dimming of transparent nodes each depth meter in percent.")
	flag.Float64Var(&transparentDim,
		"td", common.DefaultTransparentDim*100.0,
		"Extra fimming of transparent nodes each depth meter in percent. (shorthand)")
	flag.BoolVar(&websockets, "websockets", false, "Forward tile changes to clients via websockets.")
	flag.BoolVar(&websockets, "ws", false, "Forward tile changes to clients via websockets (shorthand).")
	flag.StringVar(&playersFIFO, "players", "", "Path to FIFO file to read active players from.")
	flag.StringVar(&playersFIFO, "ps", "", "Path to FIFO file to read active players from (shorthand).")
	flag.IntVar(&yMin, "ymin", common.MinHeight, "Minimum y in blocks.")
	flag.IntVar(&yMax, "ymax", common.MaxHeight, "Maximum y in blocks.")
	flag.BoolVar(&version, "version", false, "Print version and exit.")

	flag.Parse()

	if version {
		common.PrintVersionAndExit()
	}

	bg := common.ParseColorDefault(bgColor, common.BackgroundColor)

	router := mux.NewRouter()

	subBaseLine := newSubBaseLine(mapDir, bg)
	router.Path("/map/{z:[0-9]+}/{x:[0-9]+}/{y:[0-9]+}.png").Handler(subBaseLine)

	var btu baseTilesUpdates
	var wsf *websocketForwarder

	if websockets {
		wsf = newWebsocketForwarder()
		go wsf.run()
		router.Path("/ws").Methods("GET").Handler(wsf)
		btu = wsf
	}

	if playersFIFO != "" {
		plys := newPlayers(playersFIFO, wsf)
		go plys.run()
		router.Path("/players").Methods("GET").Handler(plys)
	}

	if redisHost != "" {
		var colors *common.Colors
		var err error
		if colors, err = common.ParseColors(colorsFile); err != nil {
			log.Fatalf("ERROR: problem loading colors: %s", err)
		}
		colors.TransparentDim = common.Clamp32f(
			float32(transparentDim/100.0), 0.0, 100.0)
		redisAddress := fmt.Sprintf("%s:%d", redisHost, redisPort)

		var allowedUpdateIps []net.IP
		if allowedUpdateIps, err = ipsFromHosts(updateHosts); err != nil {
			log.Fatalf("ERROR: name resolving problem: %s", err)
		}

		tu := newTileUpdater(
			mapDir,
			redisAddress,
			allowedUpdateIps,
			colors, bg,
			yMin, yMax,
			transparent,
			workers,
			btu)
		go tu.doUpdates()
		router.Path("/update").Methods("POST").Handler(tu)
	}

	router.PathPrefix("/").Handler(http.FileServer(http.Dir(webDir)))
	http.Handle("/", router)

	addr := fmt.Sprintf("%s:%d", webHost, webPort)
	if err := http.ListenAndServe(addr, nil); err != nil {
		log.Fatalf("Starting server failed: %s\n", err)
	}
}