// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include <cstring>

#include "Common/Common.h"
#include "Common/CommonTypes.h"
#include "Core/HW/WiimoteEmu/Attachment/Guitar.h"
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"

namespace WiimoteEmu
{
static const u8 guitar_id[] = {0x00, 0x00, 0xa4, 0x20, 0x01, 0x03};

static const u16 guitar_fret_bitmasks[] = {
    Guitar::FRET_GREEN, Guitar::FRET_RED,    Guitar::FRET_YELLOW,
    Guitar::FRET_BLUE,  Guitar::FRET_ORANGE,
};

static const char* const guitar_fret_names[] = {
    "Green", "Red", "Yellow", "Blue", "Orange",
};

static const u16 guitar_button_bitmasks[] = {
    Guitar::BUTTON_MINUS, Guitar::BUTTON_PLUS,
};

static const u16 guitar_strum_bitmasks[] = {
    Guitar::BAR_UP, Guitar::BAR_DOWN,
};

Guitar::Guitar(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Guitar"), _reg)
{
  // frets
  groups.emplace_back(m_frets = new Buttons(_trans("Frets")));
  for (auto& guitar_fret_name : guitar_fret_names)
    m_frets->controls.emplace_back(new ControlGroup::Input(guitar_fret_name));

  // strum
  groups.emplace_back(m_strum = new Buttons(_trans("Strum")));
  m_strum->controls.emplace_back(new ControlGroup::Input("Up"));
  m_strum->controls.emplace_back(new ControlGroup::Input("Down"));

  // buttons
  groups.emplace_back(m_buttons = new Buttons("Buttons"));
  m_buttons->controls.emplace_back(new ControlGroup::Input("-"));
  m_buttons->controls.emplace_back(new ControlGroup::Input("+"));

  // stick
  groups.emplace_back(m_stick = new AnalogStick(_trans("Stick"), DEFAULT_ATTACHMENT_STICK_RADIUS));

  // whammy
  groups.emplace_back(m_whammy = new Triggers(_trans("Whammy")));
  m_whammy->controls.emplace_back(new ControlGroup::Input(_trans("Bar")));

  // set up register
  // id
  memcpy(&id, guitar_id, sizeof(guitar_id));
}

void Guitar::GetState(u8* const data)
{
  wm_guitar_extension* const gdata = (wm_guitar_extension*)data;
  gdata->bt = 0;

  // calibration data not figured out yet?

  // stick
  {
    ControlState x, y;
    m_stick->GetState(&x, &y);

    gdata->sx = static_cast<u8>((x * 0x1F) + 0x20);
    gdata->sy = static_cast<u8>((y * 0x1F) + 0x20);
  }

  // TODO: touch bar, probably not
  gdata->tb = 0x0F;  // not touched

  // whammy bar
  ControlState whammy;
  m_whammy->GetState(&whammy);
  gdata->whammy = static_cast<u8>(whammy * 0x1F);

  // buttons
  m_buttons->GetState(&gdata->bt, guitar_button_bitmasks);
  // frets
  m_frets->GetState(&gdata->bt, guitar_fret_bitmasks);
  // strum
  m_strum->GetState(&gdata->bt, guitar_strum_bitmasks);

  // flip button bits
  gdata->bt ^= 0xFFFF;
}

bool Guitar::IsButtonPressed() const
{
  u16 buttons = 0;
  m_buttons->GetState(&buttons, guitar_button_bitmasks);
  m_frets->GetState(&buttons, guitar_fret_bitmasks);
  m_strum->GetState(&buttons, guitar_strum_bitmasks);
  return buttons != 0;
}
}
