/*!
 * Timers.cpp
 *
 * Copyright (c) 2016, 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: 17/05/2016
 *
 */

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

#include <cstdio>
#include <ctime>

#include <iostream>
#include <fstream>

#include "devices/Devices.h"

#include "timers/Timers.h"
#include "timers/Clock.h"

//#define k60s 60000
#define k60s 2000


/*!  ----------------------------------------------------------------------------
 *  @fn Timers
 *
 *  @brief Constructor of the Timers Managagers.
 */
Timers::Timers (std::string aPath, Devices *aDevice):
mDevices (aDevice),
mTimersPath (aPath)
{
}


/*!  ----------------------------------------------------------------------------
 *  @fn ~Timers
 *
 *  @brief Destructors of the Timer Managers.
 */
Timers::~Timers (void)
{
}


/*!  ----------------------------------------------------------------------------
 *  @fn load
 *
 *  @brief Load the Timer Managers.
 */
int Timers::load (void)
{
	Json::Reader theReader;
	Json::Value theRoot;
	std::ifstream theTimerFile (mTimersPath.c_str());

	/* Read and Parse the Json file. */
	if (!theReader.parse (theTimerFile, theRoot)) {

		fprintf (stderr, "Failed to parse the Timers File (%s).\n",
				 mTimersPath.c_str());
		return -1;
	}

	/* Create the Objects.. */
	for (Json::Value& theElement : theRoot["timers"]) {
		Event theEvent;
		if (theEvent.load_from_json (theElement) == 0) {

			mTimers.push_back (theEvent);
		}
	}

	Start (k60s, true);

	return 0;
}


/*!  ----------------------------------------------------------------------------
 *  @fn save
 *
 *  @brief Method to save the Timers Object into a Json File.
 */
int Timers::save (void)
{
	Json::StyledStreamWriter theWriter;

	/* Save to the File. */
	std::ofstream theOutput (mTimersPath.c_str());
	theWriter.write (theOutput, to_json());

	return 0;
}


/*!  ----------------------------------------------------------------------------
 *  @fn get
 *
 *  @brief Method to get a specific Timers Object.
 */
Event Timers::get (uint16_t anID)
{
	std::vector<Event>::iterator timer_evt;

	for (timer_evt = mTimers.begin(); timer_evt != mTimers.end(); timer_evt++) {

		if ((*timer_evt).getID() == anID)

			return (*timer_evt);
	}
}


/*!  ----------------------------------------------------------------------------
 *  @fn remove
 *
 *  @brief Method to remove a specific Timers Object.
 */
int Timers::remove (uint16_t anID)
{
	std::vector<Event>::iterator timer_evt;

	for (timer_evt = mTimers.begin(); timer_evt != mTimers.end(); timer_evt++) {

		if ((*timer_evt).getID() == anID)

			mTimers.erase (timer_evt);
			return 0;
	}

	return -1;
}


/*!  ----------------------------------------------------------------------------
 *  @fn to_json
 *
 *  @brief Method to return the Timers Object into a Json formar into a Json Object.
 */
Json::Value Timers::to_json (void)
{
	std::vector<Event>::iterator timer_evt;
	Json::Value theRoot(Json::objectValue), timers_json(Json::arrayValue);

	for (timer_evt = mTimers.begin(); timer_evt != mTimers.end(); timer_evt++) {

		timers_json.append ((*timer_evt).to_json());
	}

	theRoot["timers"] = timers_json;

	return theRoot;
}


/*!  ----------------------------------------------------------------------------
 *  @fn Expire
 *
 *  @brief Method Call when the Timer has expired.
 */
int Timers::Expire (void)
{
	std::vector<Event>::iterator timer_evt;
	Clock theClock;
	fprintf (stderr, "**** >> Manage timers....\n");

	for(timer_evt = mTimers.begin(); timer_evt != mTimers.end(); timer_evt++) {

		if ((*timer_evt).isActive()) {

			theClock.set ((*timer_evt));

			if ((*timer_evt).isInProgress()) {
				if (theClock.isExpired()) {
					
					// Action Stop.
					fprintf (stdout, "Timer Stop\n");
					(*timer_evt).stop (mDevices);
				}
				else {
					fprintf (stdout, "Not expired yet.\n");
				}
			}
			else {

				if (theClock.isEqualToCurrentTime ()) {

					// Action START.
					fprintf (stdout, "Timer Start\n");
					(*timer_evt).start (mDevices);
				}
			}
		}
	}

	return 0;
}
