/*!
 * main.cpp
 *
 * Copyright (c) 2015-2018, 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 <limits.h>
#include <cstdio>
#include <string>

#include <json-c/json.h>

extern "C" {
#include <stdlib.h> /* getenv */
#include <libubus.h>
}

#include "sequences/sequences-manager.h"
#include "devices/devices-manager.h"

#include "ubus/capabilities_model.h"
#include "ubus/capabilities_lights_model.h"
#include "ubus/capabilities_shutters_model.h"
#include "ubus/capabilities_sprinklers_model.h"

/*-------------------------------- DEFINES ---------------------------------*/

#define k_dir_sep '/'
#define k_config_dir "share/domo/"

/*!  ----------------------------------------------------------------------------
 *  @fn setup_ubus
 *
 *  @brief Setup the UBus Mechanism.
 */
extern "C" {
static struct ubus_context *setup_ubus(void)
{
	ubus_context *the_ctx;

	if (uloop_init() != 0)
	{

		fprintf(stderr, "Failed to init Uloop.\n");
		return NULL;
	}

	signal(SIGPIPE, SIG_IGN);

	the_ctx = ubus_connect(NULL);

	if (!the_ctx)
	{

		fprintf(stderr, "Failed to connect to ubus\n");
		return NULL;
	}

	ubus_add_uloop(the_ctx);

	return the_ctx;
}
}

/*!  ----------------------------------------------------------------------------
 *  @fn get_config_path
 *
 *  @brief This function return the config path from executable path.
 */
const std::string get_config_path(char *an_exec_path)
{
	int the_pos;
	std::string the_config_path;
	std::string the_exec_path(an_exec_path);

	the_pos = the_exec_path.rfind(k_dir_sep);

	// get exec path.
	the_config_path = the_exec_path.substr(0, the_pos + 1);

	// remove last / is necessary.
	if (the_config_path[the_config_path.size() - 1] == k_dir_sep)
	{
		the_config_path = the_exec_path.substr(0, the_config_path.size() - 1);
	}

	// Remove the binary directory.
	the_pos = the_config_path.rfind(k_dir_sep);
	the_config_path = the_config_path.substr(0, the_pos + 1);

	the_config_path += k_config_dir;

	return the_config_path;
}

/*!  ----------------------------------------------------------------------------
 *  @fn main
 *
 *  @brief Main function of Domo Daemon.
 */
int main(int argc, char *argv[])
{
	int the_ret = 0;
	std::string the_config_path;

	struct ubus_context *the_ctx = NULL;

	/* Get the Path of the binary to load configs. */
	the_config_path = get_config_path(argv[0]);
	printf("config path: %s\n", the_config_path.c_str());

	/* Setup the devices. */
	DevicesManager the_devices_manager(the_config_path + "/devices.json");
	if (the_devices_manager.load() != 0)
	{
		fprintf(stderr, "Failed to load devices.\n");
		return -1;
	}

	/* Setup the Sequences Manager. */
	SequencesManager the_sequences_manager(the_config_path + "/sequences.json", &the_devices_manager);
	if (the_sequences_manager.load() != 0)
	{
		fprintf(stderr, "Failed to load timers.\n");
		return -2;
	}

	the_sequences_manager.save();

	/* Setup the UBus Models. */
	CapabilitiesModel the_capabilities(the_config_path + "./capabilities.json");
	CapabilitiesLightsModel the_cap_lights(&the_devices_manager);
	CapabilitiesShuttersModel the_cap_shutters(&the_devices_manager);
	CapabilitiesSprinklersModel the_cap_sprinklers(&the_devices_manager);

	/* Setup the Ubus context. */
	the_ctx = setup_ubus();
	if (the_ctx == NULL)
	{
		return -1;
	}

	/* Add the UBus to the model exposed. */
	ubus_add_object(the_ctx, &the_capabilities);
	ubus_add_object(the_ctx, &the_cap_lights);
	ubus_add_object(the_ctx, &the_cap_shutters);
	ubus_add_object(the_ctx, &the_cap_sprinklers);

	/* Main Event Loop. */
	uloop_run();

	ubus_free(the_ctx);
	uloop_done();

	return the_ret;
}

#if 0

#include "ubus/speach_command.h"
#include "ubus/timers.h"

#include "timers/Timers.h"
#include "devices/Devices.h"

/*--------------------------------- GLOBALS ---------------------------------*/

#define kConfigPath "/usr/local/share/domo/"

} // SetupUbus.


/*!  ----------------------------------------------------------------------------
 *  @fn main
 *
 *  @brief Main function of Domo Daemon.
 */
int main (void)
{
	int theRet = 0;
	std::string theDevicePath, theTimerPath;
	struct ubus_context *theCtx = NULL;

	// Create Configs Paths...

	theDevicePath = kConfigPath;
	theDevicePath += "/Devices.json";
	
	theTimerPath = kConfigPath;
	theTimerPath += "/Timers.json";

	//printf ("DOMO PATH: %s\n", thePath.c_str());
	
	Devices theDevices (theDevicePath);
	
	if (theDevices.load() != 0) {
		
		return -1;
	}

	/* Setup the Timers. */
	Timers theTimers (theTimerPath, &theDevices);
	
	if (theTimers.load() != 0) {
			
		return -1;
	}
	
	/* Setup the UBus Models. */
	CapabilitiesModel theCapabilities;
	CapabilitiesLightsModel theCapLights (&theDevices);


	SpeachCommandModel theSpeachCommand (&theDevices);
	TimersModel theTimersModel (&theTimers);

	/* Setup the Ubus context. */
	theCtx = setupUbus ();
	if (theCtx == NULL) {

		return -1;
	}



	/* Add the UBus to the model exposed. */
	ubus_add_object (theCtx, &theCapabilities);
	ubus_add_object (theCtx, &theCapLights);
	

	ubus_add_object (theCtx, &theSpeachCommand);
	ubus_add_object (theCtx, &theTimersModel);
	
	/* Main Event Loop. */
	uloop_run ();

	ubus_free (theCtx);
	uloop_done ();

	return theRet;
}
#endif