/** \file .c
 *  \brief This module
 */

/***************************************************************************************************
 * Includes
 **************************************************************************************************/

#include "rpi_param.h"

#include <math.h>
#include <stdlib.h>

#include "log.h"

/***************************************************************************************************
 * Preprocessor Constants and Macros
 **************************************************************************************************/

/***************************************************************************************************
 * Type and Contant Definitions
 **************************************************************************************************/

pixled_param_t const dummyPixledParam = {.chanLedCount = 0};
auton_param_t const dummyAutonParam = {
    .sensitivity = 10, .gravity = 80, .pattern = 1, .isHueAutoShiftEnabled = true};
ledbar_param_t const dummyLedbarParam = {.sensitivity = 1.,
                                         .hueBase = 121,
                                         .hueInterval = -100,
                                         .hueAutoShift = 0,
                                         .hueAutoShiftInterval = 0,
                                         .hueAutoShiftSpeed = 1.,
                                         .isIncreasing = false,
                                         .luminosity = 20,
                                         .saturation = 180};

/***************************************************************************************************
 * Persistent Variables
 **************************************************************************************************/

param_t param;

/***************************************************************************************************
 * Internal Function Prototypes
 **************************************************************************************************/

/***************************************************************************************************
 * External Function Definitions
 **************************************************************************************************/

void param_setup() {
  param.pixled = dummyPixledParam;
  param.auton = dummyAutonParam;
  for (size_t i = 0; i < LED_NCHANS; ++i) {
    param.ledbar[i] = dummyLedbarParam;
  }
  param_access = &param;
}

void set_pattern(unsigned int pattern) {
  if (pattern != param.auton.pattern) {
    param.auton.pattern = pattern;
    log_debug("Pattern : %d", pattern);
  }
}

void set_gravity(int8_t gravity8) {
  param.auton.gravity = gravity8 * 100 / INT8_MAX;
  log_debug("Gravity : %d", param.auton.gravity);
}

void set_hue_auto_shift(bool HasToBeEnabled) {
  if (HasToBeEnabled != param.auton.isHueAutoShiftEnabled) {
    param.auton.isHueAutoShiftEnabled = HasToBeEnabled;
    log_debug("Hue auto shift : %s", HasToBeEnabled ? "Enabled" : "Disabled");
    if (!HasToBeEnabled) {
      for (size_t i = 0; i < LED_NCHANS; ++i) {
        param.ledbar[i].hueAutoShift = 0;
      }
    }
  }
}

void set_sensitivity(int channel, int8_t sensitivity8) {
  float sensitivity = pow(1.065, sensitivity8 - INT8_MAX / 2);
  if (channel >= LED_NCHANS) {
    param.auton.sensitivity = sensitivity;
  } else {
    param.ledbar[channel].sensitivity = sensitivity;
  }
  log_debug("Sensitivity : %f", sensitivity);
}

void set_hue_base(int channel, int8_t hueBase8) {
  uint16_t hueBase = hueBase8 * HUEBASE_MAX / INT8_MAX;
  if (channel < LED_NCHANS) {
    param.ledbar[channel].hueBase = hueBase;
  } else {
    for (size_t i = 0; i < LED_NCHANS; ++i) {
      param.ledbar[i].hueBase = hueBase;
    }
  }
  log_debug("Hue base : %u", hueBase);
}

void set_hue_interval(int channel, int8_t hueInterval8) {
  int16_t hueInterval = hueInterval8 - ((INT8_MAX + 1) / 2);
  if (-30 <= hueInterval && hueInterval <= 30) {
    hueInterval = hueInterval * (HUEINTERVAL_MAX + 1) / 30;
  } else if (hueInterval <= -30) {
    hueInterval = 22 * (hueInterval + 30) - HUEINTERVAL_MAX;
  } else {
    hueInterval = 22 * (hueInterval - 30) + HUEINTERVAL_MAX;
  }

  if (channel < LED_NCHANS) {
    param.ledbar[channel].hueInterval = hueInterval;
  } else {
    for (size_t i = 0; i < LED_NCHANS; ++i) {
      param.ledbar[i].hueInterval = hueInterval;
    }
  }
  log_debug("Hue interval [%2d] : %d", channel, hueInterval);
}

void set_hue_auto_shift_interval(int channel, int8_t hueInterval8) {
  int16_t hueInterval = hueInterval8 - ((INT8_MAX + 1) / 2);
  if (-30 <= hueInterval && hueInterval <= 30) {
    hueInterval = hueInterval * (HUEINTERVAL_MAX + 1) / 30;
  } else if (hueInterval <= -30) {
    hueInterval = 22 * (hueInterval + 30) - HUEINTERVAL_MAX;
  } else {
    hueInterval = 22 * (hueInterval - 30) + HUEINTERVAL_MAX;
  }

  if (channel < LED_NCHANS) {
    param.ledbar[channel].hueAutoShiftInterval = hueInterval;
  } else {
    for (size_t i = 0; i < LED_NCHANS; ++i) {
      param.ledbar[i].hueAutoShiftInterval = hueInterval;
    }
  }
  log_debug("Hue auto shift interval [%2d] : %d", channel, hueInterval);
}

void set_hue_auto_shift_speed(int channel, int8_t hueSpeed8) {
  float hueSpeed = pow(1.065, hueSpeed8 - INT8_MAX / 2);
  if (channel < LED_NCHANS) {
    param.ledbar[channel].hueAutoShiftSpeed = hueSpeed;
  } else {
    for (size_t i = 0; i < LED_NCHANS; ++i) {
      param.ledbar[i].hueAutoShiftSpeed = hueSpeed;
    }
  }
  log_debug("Hue auto shift speed [%2d] : %d", channel, hueSpeed);
}

void set_luminosity(int channel, int8_t luminosity8) {
  uint8_t luminosity = luminosity8 * UINT8_MAX / INT8_MAX;
  if (channel < LED_NCHANS) {
    param.ledbar[channel].luminosity = luminosity;
  } else {
    for (size_t i = 0; i < LED_NCHANS; ++i) {
      param.ledbar[i].luminosity = luminosity;
    }
  }
  log_debug("Luminosity : %u", luminosity);
}

void set_saturation(int channel, int8_t saturation8) {
  uint8_t saturation = saturation8 * UINT8_MAX / INT8_MAX;
  if (channel < LED_NCHANS) {
    param.ledbar[channel].saturation = saturation;
  } else {
    for (size_t i = 0; i < LED_NCHANS; ++i) {
      param.ledbar[i].saturation = saturation;
    }
  }
  log_debug("Saturation : %u", saturation);
}

/***************************************************************************************************
 * Internal Function Definitions
 **************************************************************************************************/
