/**************************************************************************************
 *
 *     Project:    kvmstoreserver
 *     File name:  testCaseRef_4_3_006_test.go
 *     Version:    1.0.0
 *     Date:       2018-01-12
 *
 *     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 main

import (
	"bytes"
	"fmt"
	"net/http"
	"strconv"
	"time"
)

//*****************************************************************************
//*
//*      Declarations: Constants
//*
//*****************************************************************************

// clientAction alias type for uint8
type clientAction uint8

// Enum to define the client request action
const (
	actionAdd clientAction = iota
	actionGet
	actionDel
)

// Enum with aliases for the HTTP methods
const (
	// GET is a alias for string "GET"
	GET string = "GET"

	// POST is a alias for string "POST"
	POST string = "POST"

	// DELETE is a alias for string "DELETE"
	DELETE string = "DELETE"
)

// Client and (partial Server) configuration parameters
const (
	pathToTestConfiguration string = "C:/Users/tbogd/GIT/gitlab.com/tbogdanovic/Diplomarbeit_NDS_16NI/CODE/kvmstoreserver_solution/etc/kvmstoreserver_test.conf"

	// Replace here the hostname (or IP) and the port with the parameters
	// from the config file above
	kvmstoreserverNameOrIP string = "192.168.117.86"
	serverPortTest         string = "3345"

	// Don not touch the settings below
	serverStartDelay int = 2

	addRoute string = "http://" + kvmstoreserverNameOrIP + ":" + serverPortTest + "/add/"
	getRoute string = "http://" + kvmstoreserverNameOrIP + ":" + serverPortTest + "/get/"
	delRoute string = "http://" + kvmstoreserverNameOrIP + ":" + serverPortTest + "/del/"
)

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

// runKvmssTestInstance starts a kvmstoreserver in a separate
// goroutine and waits 2 seconds until everything is ready.
// (!!! This time must be deducted during time measurements !!!)
func runKvmssTestInstance() {

	go func() {
		testkvvmsrv := newAppServer(true, pathToTestConfiguration)
		testkvvmsrv.start()
		testkvvmsrv.wait()
	}()

	time.Sleep(time.Second * time.Duration(serverStartDelay))
}

// This is a dynamic test clinet, which you can give a sequence number, from
// which it then generates a valid key name. In addition, you can also give him
// the RevNbr, which is written in the JSON document. To send a request, the
// action can be given, what needs to be addressed (add, get, del), as well as
// the HTTP Mtheode which should be written in the header. The last parameter
// allows the setting of free parameters, which are appended to the url call.
// The result is an HTTP response.
// (Attention, the body of the response (reader) is NOT closed!)
func testClient(keyNbr, revNbr int, action clientAction, httpMeth string, paramExt string) *http.Response {

	// Intialize a request body - default pattern
	keyNbrStr := strconv.Itoa(keyNbr)
	newName := "Testsystem_Name_" + keyNbrStr
	newRev := revNbr
	newNbr := keyNbr
	newVers := float64(keyNbr) + 0.99999999
	newAct := keyNbr%2 == 0
	newNull := "null"

	buildBodyRequestADD := func() *bytes.Reader {
		return bytes.NewReader([]byte(
			fmt.Sprintf(`{"system_name": "%v","system_number": %v,"system_version": %v,"system_active": %v,"system_null": %v, "rev_nbr": %v}`,
				newName, newNbr, newVers, newAct, newNull, newRev),
		))
	}

	buildBodyRequestDEL := func() *bytes.Reader {
		return bytes.NewReader([]byte(
			fmt.Sprintf(`{"key_name": "%v","confirm_delete": true}`,
				newName),
		))
	}

	// Initialize and run a client request and catch and return a
	// reference as output
	client := &http.Client{Timeout: time.Second * 60}
	var callURL string
	var req *http.Request
	var reqBuildError error

	switch action {
	case actionAdd:
		callURL = addRoute + newName
		req, reqBuildError = http.NewRequest(httpMeth, callURL, buildBodyRequestADD())
	case actionGet:
		callURL = getRoute + newName

		if paramExt != "" {
			callURL = callURL + paramExt
		}
		req, reqBuildError = http.NewRequest(httpMeth, callURL, nil)
	case actionDel:
		callURL = delRoute + newName
		req, reqBuildError = http.NewRequest(httpMeth, callURL, buildBodyRequestDEL())
	}

	if reqBuildError != nil {
		panic("Error by building request")
	}

	req.Header.Set("User-Agent", "Injection-Client-storeserver-1.0.0")
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		panic("Can not call target URL (Go internal client agent)")
	}

	// The body (reader) is not closed here!

	return resp
}
