/*!
 * UbusHandler.cpp
 *
 * Copyright (c) 2015, NADAL Jean-Baptiste. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA
 * 
 * @Author:  NADAL Jean-Baptiste
 * @Date: 21/03/2015
 *
 */

/*-------------------------------- INCLUDES ---------------------------------*/

#include <ubusmsg.h>

#include <jsoncpp/reader.h>

#include <ubuscpp/UBusCall.h>

#include "UbusHandler.h"


#include "restd.h"


/*!  ----------------------------------------------------------------------------
 *  @fn UBusHandler
 *
 *  @brief Constructor of the UBus Handler.
 */
UBusHandler::UBusHandler (std::string aRoute, std::string aPostCmd):
mRoute (aRoute),
mPostCmd (aPostCmd)
{
}


/*!  ----------------------------------------------------------------------------
 *  @fn handleGet
 *
 *  @brief Get Method for the Exit route.
 */
bool UBusHandler::handleGet (CivetServer *aServer, struct mg_connection *aConn)
{
	return Exec ("get", "", aServer, aConn);
}


/*!  ----------------------------------------------------------------------------
 *  @fn handleGet
 *
 *  @brief Get Method for the Exit route.
 */
bool UBusHandler::handlePost (CivetServer *aServer, struct mg_connection *aConn)
{
	int thePostDataLen;
	char thePostData[1024];
	//const struct mg_request_info *theReqInfo = mg_get_request_info (aConn);

	UNUSED_PARAMETER (aServer);
	printf ("Handle Post....\n");

	thePostDataLen = mg_read (aConn, thePostData, sizeof(thePostData));

	printf ("Data: <%s>%d\n", thePostData, thePostDataLen);

	return Exec (mPostCmd, thePostData, aServer, aConn);
}


/*!  ----------------------------------------------------------------------------
 *  @fn handleGet
 *
 *  @brief Get Method for the Exit route.
 */
bool UBusHandler::handlePut (CivetServer *aServer, struct mg_connection *conn)
{
	printf ("Handle Put....\n");
	UNUSED_PARAMETER (aServer);
	UNUSED_PARAMETER (conn);
//  Updates 
	return true;
}


/*!  ----------------------------------------------------------------------------
 *  @fn handleGet
 *
 *  @brief Get Method for the Exit route.
 */
bool UBusHandler::handleDelete (CivetServer *aServer, struct mg_connection *conn)
{
	printf ("Handle Delete....\n");
	UNUSED_PARAMETER (aServer);
	UNUSED_PARAMETER (conn);
// Delete
	return true;
}


/*!  ----------------------------------------------------------------------------
 *  @fn handleOptions
 *
 *  @brief Options Method for the Exit route.
 */
bool UBusHandler::handleOptions (CivetServer *aServer, struct mg_connection *aConn)
{
	UNUSED_PARAMETER (aServer);
	
	/* Add HTTP Headers. for the Responde. */
	mg_printf (aConn, "HTTP/1.1 200 OK\r\n");
    mg_printf (aConn, "Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept\r\n");
    mg_printf (aConn, "Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS\r\n");
    mg_printf (aConn, "Access-Control-Allow-Origin: *\r\n");

	return true;
}


/*!  ----------------------------------------------------------------------------
 *  @fn Exec
 *
 *  @brief Get Method for the Exit route.
 */
bool UBusHandler::Exec (const std::string &aCommand, const std::string &aParam,
						CivetServer *aServer, struct mg_connection *aConn)
{
	std::string theOutputData;
	UBusCall theCall;
	Json::Value theDocument;
	Json::Reader theReader;
	Json::StyledWriter theWriter;
	int theResult;
	int theResultCode;

	UNUSED_PARAMETER (aServer);
	std::string theCallResult;

	theResult = theCall.Exec (mRoute, aCommand.c_str(), aParam.c_str(), theCallResult);
	theResultCode = GetResultCode (theResult);

	if (theResult == 0) {

		if (!theReader.parse (theCallResult, theDocument)) {
			/* Impossible to parse the result of the command. */
			fprintf (stderr, "The Data Returned by the command is not a valid JSon.\n");
			fprintf (stderr, "<%s>\n", theCallResult.c_str());
			theResult = 406;
		}
		else {
			
			struct mg_request_info *theInfo;
			theInfo = (struct mg_request_info *)mg_get_request_info (aConn);
			
			theDocument["id"] = theInfo->uri;
			theDocument["status"] = mg_get_response_code_text (theResultCode, aConn);
			theDocument["response_code"] = theResultCode;
			theOutputData = theWriter.write (theDocument);
		}
	}

	/* Add HTTP Headers. for the Responde. */
	mg_printf (aConn, "HTTP/1.1 %d %s\r\n", 
			theResultCode, mg_get_response_code_text (theResultCode, aConn));
    mg_printf (aConn, "Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept\r\n");
    mg_printf (aConn, "Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS\r\n");
    mg_printf (aConn, "Access-Control-Allow-Origin: *\r\n");
    mg_printf (aConn, "Cache-Control: no-store, no-cache, must-revalidate, max-age=0\r\n");
    mg_printf (aConn, "Connection: close\r\n");
 	mg_printf (aConn, "Content-Type: application/json; charset=utf-8\r\n");
	mg_printf (aConn, "Pragma: no-cache\r\n\r\n");

	/* Add Information into the response JSon. */

	mg_printf (aConn, "%s\n", theOutputData.c_str());

	return true;
}


/*!  -----------------------------------------------------------------------
 *  @fn GetResultCode
 *
 *  @brief TODO.
 *
 */
int UBusHandler::GetResultCode (int anExecResult)
{
	int theResultCode;
	
	switch (anExecResult) {
		case 0:
			theResultCode = 200; /* OK */
			break;
		case -1:
			theResultCode = 404; /* HTTP_NOT_FOUND */
			break;
		case -2:
			theResultCode = 507; /* HTTP_INSUFFICIENT_STORAGE */
			break;
		case UBUS_STATUS_METHOD_NOT_FOUND:
			theResultCode = 405; /* HTTP_METHOD_NOT_ALLOWED */
			break;
		case -3:
			theResultCode = 500; /* HTTP_INTERNAL_SERVER_ERROR */
			break;
		case -4: // NotImplemented
			theResultCode = 501; /* HTTP_NOT_IMPLEMENTED */
			break;
		case UBUS_STATUS_INVALID_ARGUMENT:
			theResultCode = 412; /* HTTP_PRECONDITION_FAILED */
			break;
		default:
			theResultCode = 500; // HTTP_INTERNAL_SERVER_ERROR
			break;
	}
	
	return theResultCode;
}
