//---------------------------------------------------------------------------
/*
Remote Train Control Program for Windows

© Copyright 2015 by Mark DiVecchio

    This file is part of Remote Train Control.

    Remote Train Control is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Remote Train Control is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Remote Train Control.  If not, see <http://www.gnu.org/licenses/>.

*/
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "Engine_Commands.h"
#include "Train_Control.h"
#include "Setup_Control.h"
#include "Debug_Controls.h"
#include "Comm_Thread.h"
#include "Clipbrd.hpp"

//---------------------------------------------------------------------------
#include <math.h>
#include <stdio.h>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "_GClass"
#pragma link "AbSwitch"
#pragma link "AbVSlide"
#pragma link "HideButton"
#pragma link "AbCBitBt"
#pragma link "AbDial"
#pragma link "ColorButton"
#pragma resource "*.dfm"

TEngineCommands *EngineCommands;

extern TCommThread * ptrTIUCommThread;				// pointer to TIU communications thread
//---------------------------------------------------------------------------
__fastcall TEngineCommands::TEngineCommands(TComponent* Owner)
	: TForm(Owner)
{
// always manually created because one these Forms can be created for each running Engine
assert(false);	// never called since I used the overloaded constructor below
}
//---------------------------------------------------------------------------
__fastcall TEngineCommands::TEngineCommands(TComponent* Owner, int Remote, int Consist, int TIU, String ConName, char * ptrLUEngineList)
    : TForm(Owner)
{
// grab the Remote, Engine/LashUp, TIU numbers and Consist Name and LashUpEngineList
RemoteNo = Remote;
assert(RemoteNo >= 0 && RemoteNo <= REMOTEMAX);
ConsistNo =  Consist;
assert(ConsistNo >= (Setup->AllowZero->Checked? 0 : 1) && ConsistNo <= LASHUPMAX);	// 0 factory reset, 1-99, 100 "all engine operation, 101-120 LashUps
TIUNo = TIU;
assert(TIUNo >= 1 && TIUNo <= TIUMAX);
ConsistName = ConName;
assert((ConsistNo >= 101 && ptrLUEngineList != NULL) || (ConsistNo <= ALLENGINE && ptrLUEngineList == NULL));
LashUpEngineListOp = NULL;

if (ConsistNo <= ENGINEMAX) {	// Engines Factory Reset, 0-99
	// Normal Engine
   	// no LashUpEngineList for regular engines
	Operation_Controls_Label->Caption = "Controls for Engine " + String(ConsistNo) + " - " +
		ConsistName + " - TIU " + String(TIUNo);
    } else {
    if (ConsistNo >= LASHUPMIN) {	// LashUps
	    // LashUp Engines
    	LashUpEngineListOp = new char [LASHUP_ENGINE_LIST_LENGTH];
	    assert(LashUpEngineListOp != NULL);
	    assert(ptrLUEngineList[0] != '\0');
	    strncpy(LashUpEngineListOp, ptrLUEngineList, LASHUP_ENGINE_LIST_LENGTH);	// LashUp information
		Operation_Controls_Label->Caption = "Controls for LashUp " + String(ConsistNo - 100) + " - " +
			ConsistName + " - TIU " + String(TIUNo);
        } else {
        // All Engine Operation 100
 		Operation_Controls_Label->Caption = "Controls for All Engine Operation - TIU " + String(TIUNo);
        }
    }
this->Caption = Operation_Controls_Label->Caption;

WhistleSlider->Value = 0;
}
//---------------------------------------------------------------------------

__fastcall TEngineCommands::~TEngineCommands(void)
{
//
if (LashUpEngineListOp) {
	delete[] LashUpEngineListOp;
	LashUpEngineListOp = NULL;
	}
}
//---------------------------------------------------------------------------
void __fastcall TEngineCommands::SwingingBellSwitchStatusChanged(
      TObject *Sender)
{
// FSB Swinging Bell Command
if (SwingingBellSwitch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab24", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab25", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    }
}
//---------------------------------------------------------------------------
void __fastcall TEngineCommands::SmokeWhistleSwitchStatusChanged(
      TObject *Sender)
{
// FSW Smoke Whistle Command
if (SmokeWhistleSwitch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab22", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab23", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    }
}
//---------------------------------------------------------------------------
void __fastcall TEngineCommands::ProtoWhistleSwitchStatusChanged(
      TObject *Sender)
{
// SPW Proto Whistle Command
if (ProtoWhistleSwitch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab20", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    WhistleSlider->Enabled = true;
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab21", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	WhistleSlider->Enabled = false;
    }
// use Thumbwheel to vary Whistle frequency	
}
//---------------------------------------------------------------------------
void __fastcall TEngineCommands::HideButtonClick(TObject *Sender)
{
Hide();			      // Same as setting Visible to false
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::ab1ab0SwitchStatusChanged(TObject *Sender)
{
// ab1-ab0 Command
if (ab1ab0Switch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab1", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab0", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::ab3ab2SwitchStatusChanged(TObject *Sender)
{
// ab3-ab2 Command
if (ab3ab2Switch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab3", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab2", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::ab5ab4SwitchStatusChanged(TObject *Sender)
{
// ab5-ab4 Command
if (ab5ab4Switch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab5", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab4", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::ab7ab6SwitchStatusChanged(TObject *Sender)
{
// ab7-ab6 Command
if (ab7ab6Switch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab7", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab6", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::WhistleSliderValueChange(TObject *Sender)
{
LOCKEM();
// ab26 - ab27 - ab28 - ab29 Commands
const int iW = WhistleSlider->Value + 26;
// Convert value into chars
char str[10];
(void) snprintf(str, sizeof str, "ab%d", iW);
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, str, TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::ab1C1DSwitchStatusChanged(TObject *Sender)
{
// ab1C-ab1D Command
if (ab1C1DSwitch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab1C", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab1D", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::ab1E1FSwitchStatusChanged(TObject *Sender)
{
// ab1E-ab1F Command
if (ab1E1FSwitch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab1E", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab1F", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::AltHornSwitchStatusChanged(
      TObject *Sender)
{
// n243 Alternate Horn Command
if (AltHornSwitch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "n243", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	}
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::ab9ab8SwitchStatusChanged(
      TObject *Sender)
{
// ab9-ab8 Command
if (ab9ab8Switch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab9", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "ab8", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::abBabASwitchStatusChanged(
      TObject *Sender)
{
// abB-abA Command
if (abBabASwitch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "abB", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "abA", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::abDabCSwitchStatusChanged(
      TObject *Sender)
{
// abD-abC Command
if (abDabCSwitch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "abD", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "abC", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::abFabESwitchStatusChanged(TObject *Sender)
{
// abF-abE Command
if (abFabESwitch->Checked) {
	// On
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "abF", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
	} else {
	// Off
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "abE", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::SXSButtonMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
// Send CM_SXS message to ourselves which will perform this function
(void) PostMessage(ParentHandle, CM_SXS, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::CoorsDoorsOpenClick(TObject *Sender)
{
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "n121", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::CoorsDoorsCloseClick(TObject *Sender)
{
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "n122", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::CoorsColorButtonMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
// Handle the Coors Start and Stop Button
if (CoorsColorButton->Tag == 0) {
	// Turn On
	// Coors Delivery Start
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "u3", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    CoorsColorButton->Tag = 1;
    CoorsColorButton->Caption = "Delivery Stop";
    } else {
    // Turn Off
	// Coors Delivery Stop
	(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "u0", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
    CoorsColorButton->Tag = 0;
    CoorsColorButton->Caption = "Delivery Start";
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::AllLightsOffButtonClick(TObject *Sender)
{
// all lights off
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "aa0", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::DefaultLightsButtonClick(TObject *Sender)
{
// all lights on
(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, "aa842F", TIUNo, RemoteNo, 11, SHORT_WAIT, RECORD_OK, LashUpEngineListOp, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::CopyrightClick(TObject *Sender)
{
// Copy the Form to the clipboard.
// In BCB4.0, there is no SetSize method associated with TBitmap
// so we have to use Width and Height separately.
//
// see:
// https://stackoverflow.com/questions/3190777/how-do-i-copy-a-form-as-an-image-to-the-clipboard
//
Graphics::TBitmap * bm;
bm = new Graphics::TBitmap;
try
	{
    #if __BORLANDC__ >= 0x720
	// Defined for CB10.1 C++ programs that use the VCL.
	bm->SetSize(ClientWidth, ClientHeight);
    #else
    bm->Width = ClientWidth;
    bm->Height = ClientHeight;
    #endif
	BitBlt(bm->Canvas->Handle, 0, 0, ClientWidth, ClientHeight, Canvas->Handle, 0, 0, SRCCOPY);
    Clipboard()->Assign(bm);
    }
__finally
	{
	delete bm;
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::Operation_Controls_LabelClick(
      TObject *Sender)
{
LocalTransparencyOverride = !LocalTransparencyOverride;	// Toggle transparency locally
}
//---------------------------------------------------------------------------
// Workaround for SetLayeredWindowAttributes() to make transparent windows
extern lpfnSetLayeredWindowAttributes m_pSetLayeredWindowAttributes;
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::FormActivate(TObject *Sender)
{
#if __BORLANDC__ >= 0x720      // CB10.1 only
AlphaBlend = false; // Remove Transparency
#else
// Remove WS_EX_LAYERED from this window styles
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) & ~WS_EX_LAYERED);
#endif	
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::FormDeactivate(TObject *Sender)
{
if (Setup->TransparentSpin->Value == Setup->TransparentSpin->MaxValue) return;	// Off
if (LocalTransparencyOverride) return;
#if __BORLANDC__ >= 0x720      // CB10.1 only
AlphaBlendValue = (255 * Setup->TransparentSpin->Value) / 100;
AlphaBlend = true;  // Add Transparency
#else
// Set WS_EX_LAYERED on this window
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) | WS_EX_LAYERED);
//SetLayeredWindowAttributes
m_pSetLayeredWindowAttributes(Handle, NULL, (255 * Setup->TransparentSpin->Value) / 100, LWA_ALPHA);
#endif
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::SendButtonClick(TObject *Sender)
{
// Send the command entered in the command line
int ExpectedCount = 11;
AnsiString MyCommandLine = CommandLine->Text;
char First = MyCommandLine[1];  // NOTE: AnsiString are 1-based !!
char Second;
if (MyCommandLine.Length() > 1) {
	Second = MyCommandLine[2];
    } else {
    Second = ' ';
    }
// set the Expected response byte count
if (First == '!') {
    ExpectedCount = 21;
    } else if (First == 'x') {
        ExpectedCount = 15;
        } else if (First == 'I' && Second == '0') {
            ExpectedCount = 39;
            } else if (First == 'I') {   // all other 'I' commands
                ExpectedCount = 173;
                } else if (First == 'D' && Second == 'q') {
                    ExpectedCount = 17;
                    } else if (First == 'q') {
                        ExpectedCount = 21;
                        }

(void)ptrTIUCommThread->Send_String_FIFO(ConsistNo, MyCommandLine.c_str(), TIUNo, RemoteNo, ExpectedCount, LONG_WAIT, NO_RECORD, LashUpEngineListOp, NULL, NULL);
}
//---------------------------------------------------------------------------

void __fastcall TEngineCommands::CommandLineKeyDown(TObject *Sender,
      WORD &Key, TShiftState Shift)
{
// if ENTER is pressed, Send the command
if (Key == VK_RETURN) {
    SendButtonClick(CommandLine);
    } else if (Key == VK_ESCAPE) {
        // if escape is pressed, clear the command line
        CommandLine->Clear();
        }

}
//---------------------------------------------------------------------------

