/**************************************************************************************
 *
 *     Project:    kvmstoreserver
 *     File name:  httpMethodCheckers.go
 *     Version:    1.0.0
 *     Date:       2018-01-14
 *
 *     Autor:      Bogdanovic Theodor
 *     Contact:    t.bogdanovic@hotmail.com
 *
 *     License:    GPLv3
 *
 **************************************************************************************/
/**************************************************************************************
 * Copyright 2018 Bogdanovic Theodor
 *
 * This file is part of kvmstoreserver.
 *
 * kvmstoreserver is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * kvmstoreserver 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with kvmstoreserver.  If not, see <http://www.gnu.org/licenses/>.
 **************************************************************************************/
/**************************************************************************************
 *  Further explanations:  This source code is under the license specified by the
 *                         Autor above. Core components or other packages are still
 *                         in source code form, under the license specified by the
 *                         respective author.
 **************************************************************************************/

package middlewareFunctions

import (
	"encoding/json"
	"fmt"
	eh "kvmstoreserver_utils/errorHandling"
	"net/http"

	log "github.com/judwhite/logrjack"
)

//*****************************************************************************
//*
//*      Declarations
//*
//*****************************************************************************

// Shortcats for HTTP methods
// Looks more beautiful in the functions than a string
const (
	post = "POST"
	get  = "GET"
	del  = "DELETE"
)

//*****************************************************************************
//*
//*      Public Functions: Middleware functionality
//*
//*****************************************************************************

// MWareIfMethodPost checks if the client request is from HTTP method type POST
func MWareIfMethodPost(nextFunc http.Handler) http.Handler {

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		// BEGIN Handler Logic ->
		if result := checkMethod(w, r, post); result == eh.Nok {
			return
		}

		nextFunc.ServeHTTP(w, r)
		// <- END Handler Logic

	})
}

// MWareIfMethodGet checks if the client request is from HTTP method type Get
func MWareIfMethodGet(nextFunc http.Handler) http.Handler {

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		// BEGIN Handler Logic ->
		if result := checkMethod(w, r, get); result == eh.Nok {
			return
		}

		nextFunc.ServeHTTP(w, r)
		// <- END Handler Logic

	})
}

// MWareIfMethodDelete checks if the client request is from HTTP method type DELETE
func MWareIfMethodDelete(nextFunc http.Handler) http.Handler {

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		// BEGIN Handler Logic ->
		if result := checkMethod(w, r, del); result == eh.Nok {
			return
		}

		nextFunc.ServeHTTP(w, r)
		// <- END Handler Logic

	})
}

//*****************************************************************************
//*
//*      Private Functions
//*
//*****************************************************************************

// checkMethod checks the method type and returns a JSON document (error)
// in case of a wrong methed call. This function has its own inner Structure
func checkMethod(iw http.ResponseWriter, ir *http.Request,
	meth string) eh.Result {

	innerAswerStruct := &struct {
		StatusCode  int    `json:"status_code,omitempty"`
		Description string `json:"description,omitempty"`
		Reason      string `json:"reason,omitempty"`
	}{
		StatusCode:  http.StatusMethodNotAllowed,
		Description: fmt.Sprintf("Access denied, wrong http method"),
		Reason:      fmt.Sprintf("This controller allows only method -> %v", meth),
	}

	if ir.Method != meth {

		jsonOutput, err := json.Marshal(innerAswerStruct)
		if err != nil {
			panic("Can not recover panic, kill this routine without to give the client a answer")
		}

		iw.WriteHeader(http.StatusMethodNotAllowed)
		iw.Write(jsonOutput)
		log.Warnf("Request stopped - Wrong Http method -> (%v | Received: %v | Wanted: %v)",
			ir.RemoteAddr, ir.Method, meth)

		return eh.Nok
	}

	return eh.Ok
}
