// Sshwifty - A Web SSH client
//
// Copyright (C) 2019 Rui NI <nirui@gmx.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

package controller

import (
	"mime"
	"net/http"
	"strings"
	"time"

	"github.com/niruix/sshwifty/application/log"
)

type staticData struct {
	data          []byte
	dataHash      string
	compressd     []byte
	compressdHash string
	created       time.Time
}

func (s staticData) hasCompressed() bool {
	return len(s.compressd) > 0
}

func staticFileExt(fileName string) string {
	extIdx := strings.LastIndex(fileName, ".")

	if extIdx < 0 {
		return ""
	}

	return strings.ToLower(fileName[extIdx:])
}

func serveStaticPage(
	dataName string,
	w http.ResponseWriter,
	r *http.Request,
	l log.Logger,
) error {
	d, dFound := staticPages[dataName]

	if !dFound {
		return ErrNotFound
	}

	selectedData := d.data

	if clientSupportGZIP(r) && d.hasCompressed() {
		selectedData = d.compressd

		w.Header().Add("Vary", "Accept-Encoding")
		w.Header().Add("Content-Encoding", "gzip")
	}

	mimeType := mime.TypeByExtension(staticFileExt(dataName))

	if len(mimeType) > 0 {
		w.Header().Add("Content-Type", mimeType)
	} else {
		w.Header().Add("Content-Type", "application/binary")
	}

	_, wErr := w.Write(selectedData)

	return wErr
}

func serveStaticData(
	dataName string,
	w http.ResponseWriter,
	r *http.Request,
	l log.Logger,
) error {
	if strings.ToUpper(r.Method) != "GET" {
		return ErrControllerNotImplemented
	}

	fileExt := staticFileExt(dataName)

	if fileExt == ".html" || fileExt == ".htm" {
		return ErrNotFound
	}

	d, dFound := staticPages[dataName]

	if !dFound {
		return ErrNotFound
	}

	selectedData := d.data
	selectedDataHash := d.dataHash
	compressEnabled := false

	if clientSupportGZIP(r) && d.hasCompressed() {
		selectedData = d.compressd
		selectedDataHash = d.compressdHash

		compressEnabled = true

		w.Header().Add("Vary", "Accept-Encoding")
	}

	canUseCache := true

	if !clientContentEtagIsValid(r, selectedDataHash) {
		canUseCache = false
	}

	if clientContentModifiedSince(r, d.created) {
		canUseCache = false
	}

	if canUseCache {
		w.WriteHeader(http.StatusNotModified)

		return nil
	}

	w.Header().Add("Cache-Control", "public, max-age=31536000")
	w.Header().Add("ETag", "\""+selectedDataHash+"\"")

	mimeType := mime.TypeByExtension(fileExt)

	if len(mimeType) > 0 {
		w.Header().Add("Content-Type", mimeType)
	} else {
		w.Header().Add("Content-Type", "application/binary")
	}

	if compressEnabled {
		w.Header().Add("Content-Encoding", "gzip")
	}

	_, wErr := w.Write([]byte(selectedData))

	return wErr
}
