package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"

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

// `Hypha` represents a hypha. It is the thing MycorrhizaWiki generally serves.
// Each hypha has 1 or more revisions.
type Hypha struct {
	FullName      string               `json:"-"`
	Path          string               `json:"-"`
	ViewCount     int                  `json:"views"`
	Deleted       bool                 `json:"deleted"`
	Revisions     map[string]*Revision `json:"revisions"`
	ChildrenNames []string             `json:"-"`
	parentName    string
}

// AsHtml returns HTML representation of the hypha.
// No layout or navigation are present here. Just the hypha.
func (h *Hypha) AsHtml(id string, w http.ResponseWriter) (string, error) {
	if "0" == id {
		id = h.NewestRevision()
	}
	if rev, ok := h.Revisions[id]; ok {
		return rev.AsHtml(w)
	}
	return "", fmt.Errorf("Hypha %v has no such revision: %v", h.FullName, id)
}

// GetNewestRevision returns the most recent Revision.
func (h *Hypha) GetNewestRevision() Revision {
	return *h.Revisions[h.NewestRevision()]
}

// NewestRevision returns the most recent revision's id as a string.
func (h *Hypha) NewestRevision() string {
	return strconv.Itoa(h.NewestRevisionInt())
}

// NewestRevision returns the most recent revision's id as an integer.
func (h *Hypha) NewestRevisionInt() (ret int) {
	for k, _ := range h.Revisions {
		id, _ := strconv.Atoi(k)
		if id > ret {
			ret = id
		}
	}
	return ret
}

// MetaJsonPath returns rooted path to the hypha's `meta.json` file.
// It is not promised that the file exists.
func (h *Hypha) MetaJsonPath() string {
	return filepath.Join(h.Path, "meta.json")
}

// CreateDir creates directory where the hypha must reside.
// It is meant to be used with new hyphae.
func (h *Hypha) CreateDir() error {
	return os.MkdirAll(h.Path, os.ModePerm)
}

// SaveJson dumps the hypha's metadata to `meta.json` file.
func (h *Hypha) SaveJson() {
	data, err := json.MarshalIndent(h, "", "\t")
	if err != nil {
		log.Println("Failed to create JSON of hypha.", err)
		return
	}
	err = ioutil.WriteFile(h.MetaJsonPath(), data, 0644)
	if err != nil {
		log.Println("Failed to save JSON of hypha.", err)
		return
	}
	log.Println("Saved JSON data of", h.FullName)
}

// ActionEdit is called with `?acton=edit`.
// It represents the hypha editor.
func ActionEdit(hyphaName string, w http.ResponseWriter) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	var initContents, initTextMime, initTags string
	if h, ok := hyphae[hyphaName]; ok {
		newestRev := h.GetNewestRevision()
		contents, err := ioutil.ReadFile(newestRev.TextPath)
		if err != nil {
			log.Println("Could not read", newestRev.TextPath)
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(cfg.GenericErrorMsg))
			return
		}
		initContents = string(contents)
		initTextMime = newestRev.TextMime
		initTags = strings.Join(newestRev.Tags, ",")
	} else {
		initContents = "Describe " + hyphaName + "here."
		initTextMime = "text/markdown"
	}

	w.WriteHeader(http.StatusOK)
	w.Write([]byte(EditHyphaPage(hyphaName, initTextMime, initContents, initTags)))
}
