/*!
 * main.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: 04/03/2015
 *
 */

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

#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include "routes/UbusHandler.h"
#include "routes/ExitHandler.h"

#include "authorize.h"
#include "restd.h"

/*-------------------------------- GLOBALE ---------------------------------*/

bool gExitNow = false;

pthread_rwlock_t gRwlock = PTHREAD_RWLOCK_INITIALIZER;

#define kDocument_root "html"
#define PORT "8081"
#define EXAMPLE_URI "/example"
#define EXIT_URI "/exit"

/*!  ----------------------------------------------------------------------------
 *  @fn main
 *
 *  @brief Main function of Rest Daemon.
 */
int main (void)
{
    const char *theOptions[] = {
        "document_root", "/opt/Domo/html", 
        "listening_ports", "8081",
         0};

    CivetServer theServer (theOptions);

    printf("Browse files at http://localhost:%s/\n", PORT);
    printf("Run example at http://localhost:%s%s\n", PORT, EXAMPLE_URI);
    printf("Exit at http://localhost:%s%s\n", PORT, EXIT_URI);
    
    /* Capabilities. */
    theServer.addHandler ("/v1/capabilities",
                         new UBusHandler ("domo.capabilities"));

    /* Lights */
    theServer.addHandler ("/v1/capabilities/lights",
                         new UBusHandler ("domo.capabilities.lights"));

    /* Shutter */
    theServer.addHandler ("/v1/capabilities/shutter",
                         new UBusHandler ("domo.capabilities.shutter"));
    
    /* sprinklers */
    theServer.addHandler ("/v1/capabilities/sprinklers",
                         new UBusHandler ("domo.capabilities.sprinklers"));

    theServer.addHandler ("/v1/capabilities/sprinklers/open",
                         new UBusHandler ("domo.capabilities.sprinklers", "open"));

    theServer.addHandler ("/v1/capabilities/sprinklers/close",
                         new UBusHandler ("domo.capabilities.sprinklers", "close"));

    theServer.addHandler ("/v1/capabilities/sprinklers/up",
                         new UBusHandler ("domo.capabilities.sprinklers", "up"));
    
    theServer.addHandler ("/v1/capabilities/sprinklers/down",
                         new UBusHandler ("domo.capabilities.sprinklers", "down"));

    theServer.addHandler ("/v1/capabilities/sprinklers/position",
                         new UBusHandler ("domo.capabilities.sprinklers", "position"));
    
    /* Speach Command. */
    theServer.addHandler ("/v1/speach",
                         new UBusHandler ("domo.speach.command"));

    printf ("Rest Daemon started on ports %s...\n",
           mg_get_option (theServer.getContext(), "listening_ports"));

    while (!gExitNow) {
        sleep(1);
    }

    printf("Bye!\n");

    return 0;


}


int main_ssl (void)
{
	struct mg_callbacks theCallbacks;

	const char *theOptions[] = {
    	"document_root", "html",
        "put_delete_auth_file", "/tmp/passfile",
    	"listening_ports", "8081,8082s",
    	"ssl_certificate", "ssl_cert.pem",
    	"num_threads", "5",
    	NULL
	};

    // Initialize random number generator. It will be used later on for
    // the session identifier creation.
    srand ((unsigned) time(0));

    memset (&theCallbacks, 0, sizeof (theCallbacks));
#ifndef DEBUG_SECURIRY
    theCallbacks.begin_request = begin_request_handler;
#endif

	CivetServer theServer (theOptions, &theCallbacks);

#ifdef DEBUG_SECURIRY
    theServer.addHandler ("/Exit", new ExitHandler());
#endif

    /* Capabilities. */
    theServer.addHandler ("/v1/capabilities",
                         new UBusHandler ("domo.capabilities"));

    /* Lights */
    theServer.addHandler ("/v1/capabilities/lights",
                         new UBusHandler ("domo.capabilities.lights"));

    /* Shutter */
    theServer.addHandler ("/v1/capabilities/shutter",
                         new UBusHandler ("domo.capabilities.shutter"));
    
    /* sprinklers */
    theServer.addHandler ("/v1/capabilities/sprinklers",
                         new UBusHandler ("domo.capabilities.sprinklers"));

    theServer.addHandler ("/v1/capabilities/sprinklers/open",
                         new UBusHandler ("domo.capabilities.sprinklers", "open"));

    theServer.addHandler ("/v1/capabilities/sprinklers/close",
                         new UBusHandler ("domo.capabilities.sprinklers", "close"));

    theServer.addHandler ("/v1/capabilities/sprinklers/up",
                         new UBusHandler ("domo.capabilities.sprinklers", "up"));
    
    theServer.addHandler ("/v1/capabilities/sprinklers/down",
                         new UBusHandler ("domo.capabilities.sprinklers", "down"));

    theServer.addHandler ("/v1/capabilities/sprinklers/position",
                         new UBusHandler ("domo.capabilities.sprinklers", "position"));
    
    /* Speach Command. */
    theServer.addHandler ("/v1/speach",
                         new UBusHandler ("domo.speach.command"));

    printf ("Rest Daemon started on ports %s...\n",
           mg_get_option (theServer.getContext(), "listening_ports"));


    /* Infinite loop. */
    while (!gExitNow) {

        sleep (1);
    }

    printf("Bye!\n");

	return 0;
}


#if 0

/ Simple example program on how to use Embedded C++ interface.

#include "CivetServer.h"

#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif

#define DOCUMENT_ROOT "."
#define PORT "8081"
#define EXAMPLE_URI "/example"
#define EXIT_URI "/exit"
bool exitNow = false;

class ExampleHandler: public CivetHandler
{
public:
    bool handleGet(CivetServer *server, struct mg_connection *conn) {
        mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
        mg_printf(conn, "<html><body>\r\n");
        mg_printf(conn, "<h2>This is an example text from a C++ handler</h2>\r\n");
        mg_printf(conn, "<p>To see a page from the A handler <a href=\"A\">click here</a></p>\r\n");
        mg_printf(conn, "<p>To see a page from the A handler with a parameter <a href=\"A?param=1\">click here</a></p>\r\n");
        mg_printf(conn, "<p>To see a page from the A/B handler <a href=\"A/B\">click here</a></p>\r\n");
        mg_printf(conn, "<p>To see a page from the *.foo handler <a href=\"xy.foo\">click here</a></p>\r\n");
        mg_printf(conn, "<p>To exit <a href=\"%s\">click here</a></p>\r\n", EXIT_URI);
        mg_printf(conn, "</body></html>\r\n");
        return true;
    }
};

class ExitHandler: public CivetHandler
{
public:
    bool handleGet(CivetServer *server, struct mg_connection *conn) {
        mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n");
        mg_printf(conn, "Bye!\n");
        exitNow = true;
        return true;
    }
};

class AHandler: public CivetHandler
{
private:
    bool handleAll(const char * method, CivetServer *server, struct mg_connection *conn) {
        std::string s = "";
        mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
        mg_printf(conn, "<html><body>");
        mg_printf(conn, "<h2>This is the A handler for \"%s\" !</h2>", method);
        if (CivetServer::getParam(conn, "param", s)) {
            mg_printf(conn, "<p>param set to %s</p>", s.c_str());
        } else {
            mg_printf(conn, "<p>param not set</p>");
        }
        mg_printf(conn, "</body></html>\n");
        return true;
    }
public:
    bool handleGet(CivetServer *server, struct mg_connection *conn) {
        return handleAll("GET", server, conn);
    }
    bool handlePost(CivetServer *server, struct mg_connection *conn) {
        return handleAll("POST", server, conn);
    }
};

class ABHandler: public CivetHandler
{
public:
    bool handleGet(CivetServer *server, struct mg_connection *conn) {
        mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
        mg_printf(conn, "<html><body>");
        mg_printf(conn, "<h2>This is the AB handler!!!</h2>");
        mg_printf(conn, "</body></html>\n");
        return true;
    }
};

class FooHandler: public CivetHandler
{
public:
    bool handleGet(CivetServer *server, struct mg_connection *conn) {
        /* Handler may access the request info using mg_get_request_info */
        struct mg_request_info * req_info = mg_get_request_info(conn);

        mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
        mg_printf(conn, "<html><body>");
        mg_printf(conn, "<h2>This is the Foo handler!!!</h2>");
        mg_printf(conn, "<p>The request was:<br><pre>%s %s HTTP/%s</pre></p>",
                  req_info->request_method, req_info->uri, req_info->http_version);
        mg_printf(conn, "</body></html>\n");
        return true;
    }
};


int main(int argc, char *argv[])
{

    const char * options[] = { "document_root", DOCUMENT_ROOT,
                               "listening_ports", PORT, 0
                             };

    CivetServer server(options);

    server.addHandler(EXAMPLE_URI, new ExampleHandler());
    server.addHandler(EXIT_URI, new ExitHandler());
    server.addHandler("/a", new AHandler());
    server.addHandler("/a/b", new ABHandler());
    server.addHandler("**.foo$", new FooHandler());

    printf("Browse files at http://localhost:%s/\n", PORT);
    printf("Run example at http://localhost:%s%s\n", PORT, EXAMPLE_URI);
    printf("Exit at http://localhost:%s%s\n", PORT, EXIT_URI);

    while (!exitNow) {
#ifdef _WIN32
        Sleep(1000);
#else
        sleep(1);
#endif
    }

    printf("Bye!\n");

    return 0;
}

#endif