package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/bouncepaw/mycorrhiza/cfg"
	"github.com/gorilla/mux"
)

// GetRevision finds revision with id `id` of `hyphaName` in `hyphae`.
// If `id` is `"0"`, it means the last revision.
// If no such revision is found, last return value is false.
func GetRevision(hyphaName string, id string) (Revision, bool) {
	log.Println("Getting hypha", hyphaName, id)
	if hypha, ok := hyphae[hyphaName]; ok {
		if id == "0" {
			id = hypha.NewestRevision()
		}
		if rev, ok := hypha.Revisions[id]; ok {
			return *rev, true
		}
	}
	return Revision{}, false
}

// RevInMap finds value of `rev` (the one from URL queries like) in the passed map that is usually got from `mux.Vars(*http.Request)`.
// If there is no `rev`, return "0".
func RevInMap(m map[string]string) string {
	if id, ok := m["rev"]; ok {
		return id
	}
	return "0"
}

// `hyphae` is a map with all hyphae. Many functions use it.
var hyphae map[string]*Hypha

func main() {
	if len(os.Args) == 1 {
		panic("Expected a root wiki pages directory")
	}
	wikiDir, err := filepath.Abs(os.Args[1])
	if err != nil {
		panic(err)
	}

	log.Println("Welcome to MycorrhizaWiki α")
	cfg.InitConfig(wikiDir)
	log.Println("Indexing hyphae...")
	hyphae = recurFindHyphae(wikiDir)
	log.Println("Indexed", len(hyphae), "hyphae. Ready to accept requests.")

	// Start server code. See handlers.go for handlers' implementations.
	r := mux.NewRouter()

	r.Queries("action", "getBinary", "rev", revQuery).Path(hyphaUrl).
		HandlerFunc(HandlerGetBinary)
	r.Queries("action", "getBinary").Path(hyphaUrl).
		HandlerFunc(HandlerGetBinary)

	r.Queries("action", "raw", "rev", revQuery).Path(hyphaUrl).
		HandlerFunc(HandlerRaw)
	r.Queries("action", "raw").Path(hyphaUrl).
		HandlerFunc(HandlerRaw)

	r.Queries("action", "zen", "rev", revQuery).Path(hyphaUrl).
		HandlerFunc(HandlerZen)
	r.Queries("action", "zen").Path(hyphaUrl).
		HandlerFunc(HandlerZen)

	r.Queries("action", "view", "rev", revQuery).Path(hyphaUrl).
		HandlerFunc(HandlerView)
	r.Queries("action", "view").Path(hyphaUrl).
		HandlerFunc(HandlerView)

	r.Queries("action", "history").Path(hyphaUrl).
		HandlerFunc(HandlerHistory)

	r.Queries("action", "edit").Path(hyphaUrl).
		HandlerFunc(HandlerEdit)

	r.Queries("action", "rewind", "rev", revQuery).Path(hyphaUrl).
		HandlerFunc(HandlerRewind)

	r.Queries("action", "delete").Path(hyphaUrl).
		HandlerFunc(HandlerDelete)

	r.Queries("action", "rename", "to", hyphaPattern).Path(hyphaUrl).
		HandlerFunc(HandlerRename)

	r.Queries("action", "update").Path(hyphaUrl).Methods("POST").
		HandlerFunc(HandlerUpdate)

	r.HandleFunc(hyphaUrl, HandlerView)

	// Debug page that renders all hyphae.
	// TODO: make it redirect to home page.
	// TODO: make a home page.
	r.HandleFunc("/", func(w http.ResponseWriter, rq *http.Request) {
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		w.WriteHeader(http.StatusOK)
		for _, h := range hyphae {
			log.Println("Rendering latest revision of hypha", h.FullName)
			html, err := h.AsHtml("0", w)
			if err != nil {
				fmt.Fprintln(w, err)
			}
			fmt.Fprintln(w, html)
		}
	})

	http.Handle("/", r)

	srv := &http.Server{
		Handler: r,
		Addr:    cfg.Address,
		// Good practice: enforce timeouts for servers you create!
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
	}

	log.Fatal(srv.ListenAndServe())
}
