//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "wclBluetooth"
#pragma link "wclBluetooth"
#pragma resource "*.dfm"

#ifdef _WIN64
#pragma comment(lib, "wclCommon.a")
#pragma comment(lib, "wclCommunication.a")
#pragma comment(lib, "wclBluetoothFrameworkR.a")
#else
#pragma comment(lib, "wclCommon.lib")
#pragma comment(lib, "wclCommunication.lib")
#pragma comment(lib, "wclBluetoothFrameworkR.lib")
#endif

TfmMain *fmMain;
//---------------------------------------------------------------------------
__fastcall TfmMain::TfmMain(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------
TwclBluetoothRadio* TfmMain::GetRadio()
{
  TwclBluetoothRadio* Radio;
  int Res = wclBluetoothManager->GetClassicRadio(Radio);
  if (Res != WCL_E_SUCCESS)
  {
    MessageDlg("Get working radio failed: 0x" + IntToHex(Res, 8), mtError,
      TMsgDlgButtons() << mbOK, 0);
    return NULL;
  }
  return Radio;
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::FormCreate(TObject *Sender)
{
  wclBluetoothManager->Open();
  ClearAccel();
  ClearIr();
  ClearExtensions();
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::FormDestroy(TObject *Sender)
{
  wclWiiRemoteClient->Disconnect();
  wclBluetoothManager->Close();
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::wclBluetoothManagerDiscoveringStarted(
      TObject *Sender, const TwclBluetoothRadio *Radio)
{
    lvDevices->Items->Clear();
    Trace("Discovering started");
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::wclBluetoothManagerDeviceFound(TObject *Sender,
      const TwclBluetoothRadio *Radio, const __int64 Address)
{
    TListItem* Item = lvDevices->Items->Add();
    Item->Caption = IntToHex(Address, 12);
    Item->SubItems->Add("");
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::wclBluetoothManagerDiscoveringCompleted(
      TObject *Sender, const TwclBluetoothRadio *Radio, const int Error)
{
    for (int i = 0; i < lvDevices->Items->Count; i++)
    {
      TListItem* Item = lvDevices->Items->Item[i];
      __int64 Addr = StrToInt64("$" + Item->Caption);

      String Name;
      int Res = ((TwclBluetoothRadio*)Radio)->GetRemoteName(Addr, Name);
      if (Res != WCL_E_SUCCESS)
        Name = "Error: 0x" + IntToHex(Res, 8);
      Item->SubItems->Strings[0] = Name;
    }

    Trace("Discovering completed with result", Error);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btDiscoverClick(TObject *Sender)
{
  TwclBluetoothRadio* Radio = GetRadio();
  if (Radio != NULL)
  {
    int Res = Radio->Discover(10, dkClassic);
    if (Res != WCL_E_SUCCESS)
      ShowMessage("Discover failed; 0x" + IntToHex(Res, 8));
  }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btConnectClick(TObject *Sender)
{
  if (wclWiiRemoteClient->State != csDisconnected)
    ShowMessage("Wii Remote is connected");
  else
  {
    TwclBluetoothRadio* Radio = GetRadio();
    if (Radio != NULL)
    {
      if (lvDevices->Selected == NULL)
        ShowMessage("Select device");
      else
      {
        wclWiiRemoteClient->Address = StrToInt64("$" + lvDevices->Selected->Caption);
        int Res = wclWiiRemoteClient->Connect(Radio);
        if (Res != WCL_E_SUCCESS)
          ShowMessage("Unable connect: 0x" + IntToHex(Res, 8));
      }
    }
  }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btDisconnectClick(TObject *Sender)
{
  int Res = wclWiiRemoteClient->Disconnect();
  if (Res != WCL_E_SUCCESS)
    ShowMessage("Unable disconnect: 0x" + IntToHex(Res, 8));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::wclWiiRemoteClientConnect(TObject *Sender,
      const int Error)
{
  if (Error != WCL_E_SUCCESS)
    Trace("Connection failed", Error);
  else
  {
    Trace("Connected");
    SetLeds();
  }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::wclWiiRemoteClientDisconnect(TObject *Sender,
      const int Reason)
{
  Trace("Disconnected. Reason", Reason);

  laBattLevel->Caption = "0.00";
  cbLed1->Checked = false;
  cbLed2->Checked = false;
  cbLed3->Checked = false;
  cbLed4->Checked = false;

  cbA->Checked = false;
  cbB->Checked = false;
  cbPlus->Checked = false;
  cbHome->Checked = false;
  cbMinus->Checked = false;
  cbOne->Checked = false;
  cbTwo->Checked = false;
  cbUp->Checked = false;
  cbDown->Checked = false;
  cbLeft->Checked = false;
  cbRight->Checked = false;

  ClearAccel();
  ClearIr();
  ClearExtensions();
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::wclWiiRemoteClientStatusChanged(TObject *Sender,
      const double Batt, const TwclWiiRemoteLeds Leds)
{
  Trace("Status changed");

  laBattLevel->Caption = FormatFloat("0.00", Batt);

  cbLed1->Checked = Leds.Led1;
  cbLed2->Checked = Leds.Led2;
  cbLed3->Checked = Leds.Led3;
  cbLed4->Checked = Leds.Led4;
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btClearClick(TObject *Sender)
{
  lbLog->Clear();
}
//---------------------------------------------------------------------------
void TfmMain::Trace(String Msg)
{
  lbLog->Items->Add(Msg);
}
//---------------------------------------------------------------------------
void TfmMain::Trace(String Msg, int Res)
{
  Trace(Msg + ": 0x" + IntToHex(Res, 8));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btGetStatusClick(TObject *Sender)
{
  int Res = wclWiiRemoteClient->GetStatus();
  if (Res != WCL_E_SUCCESS)
    ShowMessage("Get status failed; 0x" + IntToHex(Res, 8));
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btGetLedsClick(TObject *Sender)
{
  if (wclWiiRemoteClient->State != csConnected)
    ShowMessage("Not connected");
  else
  {
    cbLed1->Checked = wclWiiRemoteClient->Leds.Led1;
    cbLed2->Checked = wclWiiRemoteClient->Leds.Led2;
    cbLed3->Checked = wclWiiRemoteClient->Leds.Led3;
    cbLed4->Checked = wclWiiRemoteClient->Leds.Led4;
  }
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btSetLedsClick(TObject *Sender)
{
  SetLeds();
}
//---------------------------------------------------------------------------
void TfmMain::SetLeds()
{
  int Res = wclWiiRemoteClient->SetLeds(cbLed1->Checked, cbLed2->Checked,
    cbLed3->Checked, cbLed4->Checked);
  if (Res != WCL_E_SUCCESS)
    ShowMessage("Set LEDs failed: 0x" + IntToHex(Res, 8));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::wclWiiRemoteClientButtonsChanged(TObject *Sender,
      const TwclWiiRemoteButtons &Buttons)
{
  cbA->Checked = Buttons.A;
  cbB->Checked = Buttons.B;
  cbPlus->Checked = Buttons.Plus;
  cbHome->Checked = Buttons.Home;
  cbMinus->Checked = Buttons.Minus;
  cbOne->Checked = Buttons.One;
  cbTwo->Checked = Buttons.Two;
  cbUp->Checked = Buttons.Up;
  cbDown->Checked = Buttons.Down;
  cbLeft->Checked = Buttons.Left;
  cbRight->Checked = Buttons.Right;
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclWiiRemoteClientAccelChanged(TObject *Sender,
      const TwclWiiRemoteAccel &Accel)
{
  laX->Caption = IntToStr(Accel.Values.X);
  laY->Caption = IntToStr(Accel.Values.Y);
  laZ->Caption = IntToStr(Accel.Values.Z);
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btEnableAccelClick(TObject *Sender)
{
  int Res = wclWiiRemoteClient->EnableAccel();
  if (Res != WCL_E_SUCCESS)
    ShowMessage("Enable accelerometer failed: 0x" + IntToHex(Res, 8));
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btDisableAccelClick(TObject *Sender)
{
  int Res = wclWiiRemoteClient->DisableAccel();
  if (Res != WCL_E_SUCCESS)
    ShowMessage("Disable accelerometer failed: 0x" + IntToHex(Res, 8));
  else
    ClearAccel();
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclWiiRemoteClientIrChanged(TObject *Sender,
      const TwclWiiRemoteIrSensors &Ir)
{
  switch (Ir.Mode)
  {
    case wiiIrOff:
      ClearIr();
      break;
    case wiiIrBasicMode:
      laIrMode->Caption = "Basic";
      break;
    case wiiIrExtendedMode:
      laIrMode->Caption = "Extended";
      break;
    case wiiIrFullMode:
      laIrMode->Caption = "Full";
      break;
    default:
      laIrMode->Caption = "Unknown";
      break;
  }

  if (Ir.Mode != wiiIrOff)
  {
    switch (Ir.Sensitivity)
    {
      case wiiIrLevelOff:
        laIrSensitivity->Caption = "Off";
        break;
      case wiiIrLevel1:
        laIrSensitivity->Caption = "Level 1";
        break;
      case wiiIrLevel2:
        laIrSensitivity->Caption = "Level 2";
        break;
      case wiiIrLevel3:
        laIrSensitivity->Caption = "Level 3";
        break;
      case wiiIrLevel4:
        laIrSensitivity->Caption = "Level 4";
        break;
      case wiiIrLevel5:
        laIrSensitivity->Caption = "Level 5";
        break;
      case wiiIrLevelMax:
        laIrSensitivity->Caption = "Maximum";
        break;
      default:
        laIrSensitivity->Caption = "Unknown";
        break;
    }

    if (Ir.Sensors[0].Found)
    {
      laSensor0Position->Caption = IntToStr(Ir.Sensors[0].Position.X) + "; " +
        IntToStr(Ir.Sensors[0].Position.Y);
      laSensor0Size->Caption = IntToStr(Ir.Sensors[0].Size);
      laSensor0Found->Caption = "True";
    }
    else
    {
      laSensor0Position->Caption = "0; 0";
      laSensor0Size->Caption = "0";
      laSensor0Found->Caption = "False";
    }

    if (Ir.Sensors[1].Found)
    {
      laSensor1Position->Caption = IntToStr(Ir.Sensors[1].Position.X) + "; " +
        IntToStr(Ir.Sensors[1].Position.Y);
      laSensor1Size->Caption = IntToStr(Ir.Sensors[1].Size);
      laSensor1Found->Caption = "True";
    }
    else
    {
      laSensor1Position->Caption = "0; 0";
      laSensor1Size->Caption = "0";
      laSensor1Found->Caption = "False";
    }

    if (Ir.Sensors[2].Found)
    {
      laSensor2Position->Caption = IntToStr(Ir.Sensors[2].Position.X) + "; " +
        IntToStr(Ir.Sensors[2].Position.Y);
      laSensor2Size->Caption = IntToStr(Ir.Sensors[2].Size);
      laSensor2Found->Caption = "True";
    }
    else
    {
      laSensor2Position->Caption = "0; 0";
      laSensor2Size->Caption = "0";
      laSensor2Found->Caption = "False";
    }

    if (Ir.Sensors[3].Found)
    {
      laSensor3Position->Caption = IntToStr(Ir.Sensors[3].Position.X) + "; " +
        IntToStr(Ir.Sensors[3].Position.Y);
      laSensor3Size->Caption = IntToStr(Ir.Sensors[3].Size);
      laSensor3Found->Caption = "True";
    }
    else
    {
      laSensor3Position->Caption = "0; 0";
      laSensor3Size->Caption = "0";
      laSensor3Found->Caption = "False";
    }
  }
}
//---------------------------------------------------------------------------
void TfmMain::ClearAccel()
{
  laX->Caption = "0";
  laY->Caption = "0";
  laZ->Caption = "0";
}
//---------------------------------------------------------------------------
void TfmMain::ClearIr()
{
  laIrMode->Caption = "Off";
  laIrSensitivity->Caption = "Off";

  laSensor0Position->Caption = "0; 0";
  laSensor0Size->Caption = "0";
  laSensor0Found->Caption = "False";

  laSensor1Position->Caption = "0; 0";
  laSensor1Size->Caption = "0";
  laSensor1Found->Caption = "False";

  laSensor2Position->Caption = "0; 0";
  laSensor2Size->Caption = "0";
  laSensor2Found->Caption = "False";

  laSensor3Position->Caption = "0; 0";
  laSensor3Size->Caption = "0";
  laSensor3Found->Caption = "False";
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btEnableIrClick(TObject *Sender)
{
  int Res = wclWiiRemoteClient->SetIrSensitivity(wiiIrLevelMax);
  if (Res != WCL_E_SUCCESS)
    ShowMessage("Enable IR failed: 0x" + IntToHex(Res, 8));
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btDisableIrClick(TObject *Sender)
{
  int Res = wclWiiRemoteClient->SetIrSensitivity(wiiIrLevelOff);
  if (Res != WCL_E_SUCCESS)
    ShowMessage("Disable IR failed: 0x" + IntToHex(Res, 8));
  else
    ClearIr();
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btRumbleOnClick(TObject *Sender)
{
  int Res = wclWiiRemoteClient->SetRumble(True);
  if (Res != WCL_E_SUCCESS)
    ShowMessage("Set Rumble ON failed; 0x" + IntToHex(Res, 8));
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btRumbleOffClick(TObject *Sender)
{
  int Res = wclWiiRemoteClient->SetRumble(False);
  if (Res != WCL_E_SUCCESS)
    ShowMessage("Set Rumble OFF failed; 0x" + IntToHex(Res, 8));
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclWiiRemoteClientExtensionAttached(
      TObject *Sender)
{
  String Ext;
  switch (wclWiiRemoteClient->Extension)
  {
    case wiiNoExtension:
      Ext = "wiiNoExtension";
      break;
    case wiiNunchuk:
      Ext = "wiiNunchuk";
      laNunchukState->Caption = "Attached";
      break;
    case wiiClassicController:
      Ext = "wiiClassicController";
      break;
    case wiiGuitar:
      Ext = "wiiGuitar";
      break;
    case wiiDrums:
      Ext = "wiiDrums";
      break;
    case wiiBalanceBoard:
      Ext = "wiiBalanceBoard";
      laBalanceBoardState->Caption = "Attached";
      break;
    default:
      Ext = "Unknonw";
      break;
  }

  Trace("Extension attached: " + Ext);
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclWiiRemoteClientExtensionDetached(
      TObject *Sender)
{
  Trace("Extension detached");
  ClearExtensions();
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclWiiRemoteClientNunchukChanged(TObject *Sender,
      const TwclWiiRemoteNunchuk &Nunchuk)
{
  laNunchukX->Caption = IntToStr(Nunchuk.Accel.Values.X);
  laNunchukY->Caption = IntToStr(Nunchuk.Accel.Values.Y);
  laNunchukZ->Caption = IntToStr(Nunchuk.Accel.Values.Z);

  laNunchukJoyX->Caption = IntToStr(Nunchuk.Joystick.X);
  laNunchukJoyY->Caption = IntToStr(Nunchuk.Joystick.Y);

  cbNunchukC->Checked = Nunchuk.C;
  cbNunchukZ->Checked = Nunchuk.Z;
}
//---------------------------------------------------------------------------
void TfmMain::ClearNunchuk()
{
  laNunchukState->Caption = "Detached";

  laNunchukX->Caption = "0";
  laNunchukY->Caption = "0";
  laNunchukZ->Caption = "0";

  laNunchukJoyX->Caption = "0";
  laNunchukJoyY->Caption = "0";

  cbNunchukC->Checked = false;
  cbNunchukZ->Checked = false;
}
//---------------------------------------------------------------------------
void TfmMain::ClearExtensions()
{
  ClearNunchuk();
  ClearBalanceBoard();
}
//---------------------------------------------------------------------------
void TfmMain::ClearBalanceBoard()
{
  laBalanceBoardState->Caption = "Detached";

  laBbTopRight->Caption = "0";
  laBbTopLeft->Caption = "0";
  laBbBottomRight->Caption = "0";
  laBbBottomLeft->Caption = "0";
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::wclWiiRemoteClientBalanceBoardChanged(
      TObject *Sender, const TwclWiiRemoteBalanceBoard &Board)
{
  laBbTopRight->Caption = FormatFloat("0.00", Board.SensorsKg.TopRight);
  laBbTopLeft->Caption = FormatFloat("0.00", Board.SensorsKg.TopLeft);
  laBbBottomRight->Caption = FormatFloat("0.00", Board.SensorsKg.BottomRight);
  laBbBottomLeft->Caption = FormatFloat("0.00", Board.SensorsKg.BottomLeft);
}
//---------------------------------------------------------------------------

