//
// Created by rhetenor on 14.12.18.
//

#include <utility/helper_functions.hpp>
#include "output/detail/DriverBoardPinController.h"

#include "output/items/DriverBoardItem.h"

#include "utility/config.h"

namespace flippR_driver
{
namespace output
{
namespace detail
{

DriverBoardPinController::DriverBoardPinController(std::shared_ptr<std::mutex> output_item_mutex) :
  output_item_mutex(std::move(output_item_mutex))
{
  CLOG(DEBUG, OUTPUT_LOGGER) << "Created DriverBoardPinController.";
}

void DriverBoardPinController::activate(items::DriverBoardItem &driver_board_item)
{
  std::lock_guard<std::mutex> guard(*output_item_mutex);

  this->deselect_all_muxes();

  uint8_t address = driver_board_item.get_address();

  this->select_address(address);
  write_pin(this->data_pin, true);

  this->select_mux(address/8);

  this->deselect_all_muxes();
}

void DriverBoardPinController::deactivate(items::DriverBoardItem &driver_board_item)
{
  std::lock_guard<std::mutex> guard(*output_item_mutex);

  this->deselect_all_muxes();

  uint8_t address = driver_board_item.get_address();

  this->select_address(address);
  write_pin(this->data_pin, false);

  this->select_mux(address/8);

  this->deselect_all_muxes();
}

void DriverBoardPinController::select_address(uint8_t address)
{
  address = address % 8;
  write_pin(this->address_pins[0], address & 0b001);
  write_pin(this->address_pins[1], address & 0b010);
  write_pin(this->address_pins[2], address & 0b100);
}

void DriverBoardPinController::select_mux(uint8_t mux)
{
  write_pin(this->mux_enable_pins[mux], 0);
}

void DriverBoardPinController::deselect_all_muxes()
{
  for(auto pin : mux_enable_pins)
  {
    write_pin(pin, 1);
  }
}

void DriverBoardPinController::clear()
{
  CLOG(DEBUG, OUTPUT_LOGGER) << "Clear Driver Board items!";
  write_pin(data_pin, 0);

  for(auto mux : mux_enable_pins)
  {
    select_mux(mux);
    for(uint8_t i = 0; i<8; i++)
    {
      select_address(i);
    }
    this->deselect_all_muxes();
  }
}

void DriverBoardPinController::set_address_pins(std::array<uint8_t, 3> address_pins)
{
  this->address_pins = address_pins;

  for(auto pin : address_pins)
  {
    initialize_output_pin(pin);
    write_pin(pin, 1);
  }

  CLOG(DEBUG, OUTPUT_LOGGER) << "Pin addresses for driver board set to: " + help::make_list_string<std::array<uint8_t, 3>>(address_pins);
}
void DriverBoardPinController::set_mux_pins(std::array<uint8_t, 13> mux_enable_pins)
{
  this->mux_enable_pins = mux_enable_pins;

  for(auto pin : mux_enable_pins)
  {
    initialize_output_pin(pin);
    write_pin(pin, 1);
  }

  CLOG(DEBUG, OUTPUT_LOGGER) << "Pin addresses for multiplexers set to: " + help::make_list_string<std::array<uint8_t, 13>>(mux_enable_pins);
}
void DriverBoardPinController::set_data_pin(uint8_t data_pin)
{
  this->data_pin = data_pin;

  CLOG(DEBUG, OUTPUT_LOGGER) << "Set data pin to: " << std::to_string(run_pin);

  initialize_output_pin(data_pin);

  write_pin(data_pin, 0);
}
void DriverBoardPinController::set_run_pin(uint8_t run_pin)
{
  this->run_pin = run_pin;

  CLOG(DEBUG, OUTPUT_LOGGER) << "Set run pin to: " << std::to_string(run_pin);

  initialize_output_pin(run_pin);
  write_pin(run_pin, 0);
}



}
}
}