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

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

#include <cstdio>
#include <ctime>

#include <json-c/json.h>

#include "devices/devices-manager.h"

#include "sequences/clock.h"

#include "domo.h"

#include "sequences-manager.h"

//#define k60s 60000
#define k60s 2000

/*!  ----------------------------------------------------------------------------
 *  @fn SequencesManager
 *
 *  @brief Constructor of the Timers Managagers.
 */
SequencesManager::SequencesManager(const std::string &a_path, DevicesManager *a_device_manager) : m_devices_manager(a_device_manager),
																								  m_sequences_file_path(a_path)
{
}

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

/*!  ----------------------------------------------------------------------------
 *  @fn load
 *
 *  @brief Load the Timer Managers.
 */
int SequencesManager::load(void)
{
	struct json_object *the_root_node, *the_sequence_array_node;

	the_root_node = json_object_from_file(m_sequences_file_path.c_str());
	if (the_root_node == NULL)
	{
		fprintf(stderr, "Failed to parse the Timers File (%s).\n", m_sequences_file_path.c_str());
		return -1;
	}

	if (json_object_object_get_ex(the_root_node, k_entry_sequences, &the_sequence_array_node) && (json_object_get_type(the_sequence_array_node) == json_type_array))
	{
		int the_len;
		struct json_object *the_sequence_node;

		the_len = json_object_array_length(the_sequence_array_node);
		for (int i = 0; i < the_len; i++)
		{
			Sequence the_sequence;
			the_sequence_node = json_object_array_get_idx(the_sequence_array_node, i);
			the_sequence.from_json(the_sequence_node);

			m_sequences.push_back(the_sequence);
		}
	}

	/* Clean the json object. */
	json_object_put(the_root_node);

	tzset ();

	start(k60s, true);

	return 0;
}

/*!  ----------------------------------------------------------------------------
 *  @fn save
 *
 *  @brief Method to save the Timers Object into a Json File.
 */
int SequencesManager::save(void)
{
	int the_result;
	struct json_object *the_root_node;

	the_root_node = to_json();

	the_result = json_object_to_file(m_sequences_file_path.c_str(), the_root_node);

	/* Clean the json object. */
	json_object_put(the_root_node);

	return the_result;
}

/*!  ----------------------------------------------------------------------------
 *  @fn get
 *
 *  @brief Method to get a specific Timers Object.
 */
bool SequencesManager::get(uint16_t an_id, Sequence &a_sequence)
{
#if 0
	std::vector<Event>::iterator the_timer_evt;

	for (the_timer_evt = m_timers.begin(); the_timer_evt != m_timers.end(); the_timer_evt++)
	{
		if ((*the_timer_evt).get_id() == an_id)
		{
			an_event = (*the_timer_evt);
			return true;
		}
	}
#endif
	return false;
}

/*!  ----------------------------------------------------------------------------
 *  @fn remove
 *
 *  @brief Method to remove a specific Timers Object.
 */
int SequencesManager::remove(uint16_t an_id)
{
	std::vector<Sequence>::iterator the_seq_it;

	for (the_seq_it = m_sequences.begin(); the_seq_it != m_sequences.end(); the_seq_it++)
	{
		if ((*the_seq_it).get_id() == an_id)
		{
			m_sequences.erase(the_seq_it);
			return 0;
		}
	}

	return -1;
}

/*!  ----------------------------------------------------------------------------
 *  @fn to_json
 *
 *  @brief Method to return the Timers Object into a Json formar into a Json Object.
 */
struct json_object *SequencesManager::to_json(void)
{
	std::vector<Sequence>::iterator the_seq_it;
	struct json_object *the_root_node, *the_sequence_array_node;

	the_root_node = json_object_new_object();

	the_sequence_array_node = json_object_new_array();
	json_object_object_add(the_root_node, k_entry_sequences, the_sequence_array_node);

	for (the_seq_it = m_sequences.begin(); the_seq_it != m_sequences.end(); the_seq_it++)
	{
		json_object_array_add(the_sequence_array_node, (*the_seq_it).to_json());
	}

	return the_root_node;
}

/*!  ----------------------------------------------------------------------------
 *  @fn expire
 *
 *  @brief Method Call when the Timer has expired.
 */
int SequencesManager::expire(void)
{
	std::vector<Sequence>::iterator the_seq_it;
	Clock the_clock;
	// fprintf(stderr, "**** >> Manage timers....\n");

	for (the_seq_it = m_sequences.begin(); the_seq_it != m_sequences.end(); the_seq_it++)
	{
		if ((*the_seq_it).is_active())
		{
			// printf("sequence %d active.\n", (*the_seq_it).get_id());
			if (!(*the_seq_it).is_in_progress())
			{
				// should the sequence start ?
				if (the_clock.is_equal_to_timer((*the_seq_it).get_timer()))
				{
					// Action START.
					fprintf(stdout, "Sequence Start\n");
					(*the_seq_it).start(m_devices_manager);
				}
			} 
			else 
			{	
				// The action is in progress.
				if (the_clock.is_expired((*the_seq_it)))
				{
					if (!(*the_seq_it).switch_to_next_action(m_devices_manager)) {
						fprintf(stdout, "Sequence Stop\n");
						(*the_seq_it).stop();
					}
				}
			}
		}
	}

	return 0;
}

#if 0
	for (the_seq_it = m_sequences.begin(); the_seq_it != m_sequences.end(); the_seq_it++)
	{
		if ((*the_seq_it).is_active())
		{
	
			the_clock.set((*the_timer_evt));

			if ((*the_seq_it).is_in_progress())
			{
				if (the_clock.is_expired())
				{
					// Action Stop.
					fprintf(stdout, "Timer Stop\n");
					(*the_seq_it).stop(m_devices_manager);
				}
				else
				{
					fprintf(stdout, "Not expired yet.\n");
				}
			}
			else
			{

				if (the_clock.is_equal_to_current_time())
				{
					// Action START.
					fprintf(stdout, "Timer Start\n");
					(*the_seq_it).start(m_devices_manager);
				}
			}
		}
	}
	return 0;
}
#endif
