/*
 * Mode_Manager.c
 *
 * Created: Fri Jan 27 2023 22:13:26
 *  Author Chris
 */
// ============================================================================================
// Includes
#include "Mode_Manager.h"

#include "Hue.h"
#include "Command.h"
#include "Screens.h"
#include "EEPROM_M24C64.h"
#include "Command_Definition.h"
#include "Display_Default_Configurations.h"

#include "pico/rand.h"


// ============================================================================================
// Defines
#define TIME_INTERVAL_TICK_ms	40
#define TICKS_PER_SECOND		(1000/TIME_INTERVAL_TICK_ms)


// ============================================================================================
// Variables
static volatile Mode _Current_Mode;

static volatile uint32_t _Jam_Current_Angle;
static volatile uint32_t _Jam_Next_Angle;

static volatile uint32_t _Jam_Duration_Until_Next_s;
static volatile uint32_t _Jam_Timer;


// ============================================================================================
// Function Declarations
void Mode_Manager_Jam_Mode_Init(void);
uint32_t Mode_Manager_Jam_Select_Next_Angle(uint32_t current_angle);
uint32_t Mode_Manager_Jam_Get_Duration(void);
void Mode_Manager_Jam_Set_Color(uint32_t angle);
void Mode_Manager_Jam_Step(void);


/*******************************************************************
	Functions
*******************************************************************/
void Mode_Manager_Init(void)
{
	_Current_Mode = MIDI;
}

void Mode_Manager_Tick(void)
{
	if(_Current_Mode != JAM) {
		return;
	}

	if(_Jam_Timer >= _Jam_Duration_Until_Next_s * TICKS_PER_SECOND) {
		Mode_Manager_Jam_Step();
	}

	_Jam_Timer++;
}

void Mode_Manager_Cycle_Mode(void)
{
	_Current_Mode++;
	if(_Current_Mode == PREVIEW) {
		_Current_Mode = MIDI;
	}

	Mode_Manager_Set_Mode(_Current_Mode);

	Screen_Setup_Mode_Change(TRANSITION_NONE, TRANSITION_NONE, SCREEN_TRANSITION_DEFAULT_EASING, SCREEN_TRANSITION_DEFAULT_FRAMES, _Current_Mode);
}

void Mode_Manager_Set_Mode(Mode mode)
{
	switch (mode)
	{
	case MIDI:
		Command_Issue_Set_Request(MULTICORE_COMMAND_SET_MIDI_TO_LIGHT_ENABLED, MULTICORE_NO_PARAMETER, (uint16_t)true);

		Command_Issue_Set_Request(MULTICORE_COMMAND_SET_DIRECT_RED	, MULTICORE_NO_PARAMETER, 0);
		Command_Issue_Set_Request(MULTICORE_COMMAND_SET_DIRECT_GREEN, MULTICORE_NO_PARAMETER, 0);
		Command_Issue_Set_Request(MULTICORE_COMMAND_SET_DIRECT_BLUE	, MULTICORE_NO_PARAMETER, 0);
		break;
	
	case JAM:
		Command_Issue_Set_Request(MULTICORE_COMMAND_SET_MIDI_TO_LIGHT_ENABLED, MULTICORE_NO_PARAMETER, (uint16_t)false);

		Mode_Manager_Jam_Mode_Init();
		break;

	case CONSTANT:
		Command_Issue_Set_Request(MULTICORE_COMMAND_SET_MIDI_TO_LIGHT_ENABLED, MULTICORE_NO_PARAMETER, (uint16_t)false);

		Command_Issue_Set_Request(MULTICORE_COMMAND_SET_DIRECT_FADE_SPEED, MULTICORE_NO_PARAMETER, (uint16_t)_EEPROM_Content.Const_Light_Configuration.Fade_Speed);

		Command_Issue_Set_Request(MULTICORE_COMMAND_SET_DIRECT_RED	, MULTICORE_NO_PARAMETER, _EEPROM_Content.Const_Light_Configuration.Color.R);
		Command_Issue_Set_Request(MULTICORE_COMMAND_SET_DIRECT_GREEN, MULTICORE_NO_PARAMETER, _EEPROM_Content.Const_Light_Configuration.Color.G);
		Command_Issue_Set_Request(MULTICORE_COMMAND_SET_DIRECT_BLUE	, MULTICORE_NO_PARAMETER, _EEPROM_Content.Const_Light_Configuration.Color.B);
		break;

	case PREVIEW:
		Command_Issue_Set_Request(MULTICORE_COMMAND_SET_MIDI_TO_LIGHT_ENABLED, MULTICORE_NO_PARAMETER, (uint16_t)false);
		Command_Issue_Set_Request(MULTICORE_COMMAND_SET_DIRECT_FADE_SPEED, MULTICORE_NO_PARAMETER, 2);
		break;

	default:
		break;
	}
}

Mode Mode_Manager_Get_Current_Mode(void)
{
	return _Current_Mode;
}

void Mode_Manager_Set_Default_Color_Notes(void)
{
	_EEPROM_Content.Channel_MIDI_Configuration[0].Note_Color_Red 	= NOTE_C;
	_EEPROM_Content.Channel_MIDI_Configuration[0].Note_Color_Green 	= NOTE_D;
	_EEPROM_Content.Channel_MIDI_Configuration[0].Note_Color_Blue 	= NOTE_E;
}

uint Mode_Manager_Jam_Get_Current_Angle()
{
	return _Jam_Current_Angle;
}

uint Mode_Manager_Jam_Get_Next_Angle()
{
	return _Jam_Next_Angle;
}

uint Mode_Manager_Jam_Get_Duration_s()
{
	return _Jam_Duration_Until_Next_s;
}

uint Mode_Manager_Jam_Get_Duration_Tick()
{
	return _Jam_Duration_Until_Next_s * TICKS_PER_SECOND;
}

uint Mode_Manager_Jam_Get_Time_Left_s()
{
	return _Jam_Duration_Until_Next_s - (_Jam_Timer / TICKS_PER_SECOND);
}

uint Mode_Manager_Jam_Get_Time_Left_Tick()
{
	return _Jam_Duration_Until_Next_s * TICKS_PER_SECOND - _Jam_Timer;
}

/*******************************************************************
	Internal Functions
*******************************************************************/
/////////////////////////////
// Jam Mode Implementation //
/////////////////////////////
void Mode_Manager_Jam_Mode_Init(void)
{
	Command_Issue_Set_Request(MULTICORE_COMMAND_SET_DIRECT_FADE_SPEED, MULTICORE_NO_PARAMETER, _EEPROM_Content.Jam_Light_Configuration.Fade_Speed);

	_Jam_Current_Angle 			= _EEPROM_Content.Jam_Light_Configuration.Hue_Angle_Start_Color % HUE_MAX_ANGLE;
	_Jam_Duration_Until_Next_s 	= Mode_Manager_Jam_Get_Duration();
	_Jam_Next_Angle 			= Mode_Manager_Jam_Select_Next_Angle(_Jam_Current_Angle);
	_Jam_Timer					= 0;

	Mode_Manager_Jam_Set_Color(_Jam_Current_Angle);	
}

uint32_t Mode_Manager_Jam_Select_Next_Angle(uint32_t current_angle)
{
    uint32_t Random_Value = get_rand_32();
	uint32_t Angle_Step = ((Random_Value & 0x07) + 1)  * _EEPROM_Content.Jam_Light_Configuration.Color_Change;

	return (current_angle + Angle_Step) % 360;
}

uint32_t Mode_Manager_Jam_Get_Duration(void)
{
	uint32_t Duration_Span_s = _EEPROM_Content.Jam_Light_Configuration.Durations.Max - _EEPROM_Content.Jam_Light_Configuration.Durations.Min;

	uint32_t Random_Value = get_rand_32();
	uint32_t Factor = ((Random_Value & 0x07) << 4);

	Duration_Span_s = (Duration_Span_s * Factor) / 112;

	return _EEPROM_Content.Jam_Light_Configuration.Durations.Min + Duration_Span_s;
}

void Mode_Manager_Jam_Set_Color(uint32_t angle)
{
	LED_Data_t Color;
	Color.Pixel = Hue_Get_Color_From_Angle(angle);

	Command_Issue_Set_Request(MULTICORE_COMMAND_SET_DIRECT_RED	, MULTICORE_NO_PARAMETER, Color.R);
	Command_Issue_Set_Request(MULTICORE_COMMAND_SET_DIRECT_GREEN, MULTICORE_NO_PARAMETER, Color.G);
	Command_Issue_Set_Request(MULTICORE_COMMAND_SET_DIRECT_BLUE	, MULTICORE_NO_PARAMETER, Color.B);
}

void Mode_Manager_Jam_Step(void)
{
	_Jam_Current_Angle 			= _Jam_Next_Angle;
	_Jam_Duration_Until_Next_s 	= Mode_Manager_Jam_Get_Duration();
	_Jam_Next_Angle 			= Mode_Manager_Jam_Select_Next_Angle(_Jam_Current_Angle);
	_Jam_Timer					= 0;

	Mode_Manager_Jam_Set_Color(_Jam_Current_Angle);	
}