//---------------------------------------------------------------------------
/*
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/>.

*/
// Home Page : http://www.silogic.com/trains/RTC_Running.html
//---------------------------------------------------------------------------
#include <vcl.h>
#include <tchar.h>
#pragma hdrstop

#include "Engine_Commands.h"
#include "Train_Control.h"
//#include "AIU_Control.h"
#include "Op_Control.h"

#include "Engine_Status_Thread.h"
#include "Engine_Status.h"

#include "Volume_Control.h"
#include "Setup_Control.h"
#include "Debug_Controls.h"
#include "Clipbrd.hpp"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "_GClass"
#pragma link "AbCBitBt"
#pragma link "AbLED"
#pragma link "AbNumEdit"
#pragma link "HideButton"
#pragma resource "*.dfm"

extern bool SuperTIUMode, TIUSuperMode[TIUMAX];         // Flags to indicate if Super TIU Mode is active

// NOTE: this is public static variable, you can never use
// this when you create multiple instances of a Form
//TEngineStatus *EngineStatus;

//---------------------------------------------------------------------------
__fastcall TEngineStatus::TEngineStatus(TComponent* Owner)
	: TForm(Owner)
{
// never called since I used the overloaded constructor below
assert(false);	// never called since I used the overloaded constructor below
}
//---------------------------------------------------------------------------
__fastcall TEngineStatus::TEngineStatus(TComponent* Owner, HWND Parent, int Remote, int Engine, int TIU, String EngName)
    : TForm(Owner)
{
// grab the Remote, Engine, TIU numbers and Engine Name
RemoteNo = Remote;
assert(RemoteNo >= 0 && RemoteNo <= REMOTEMAX);
EngineNo =  Engine;
assert(EngineNo >= (Setup->AllowZero->Checked? 0 : 1) && EngineNo <= ENGINEMAX);	// 0 factory reset, 1-99
TIUNo = TIU;
assert(TIUNo >= 1 && TIUNo <= TIUMAX);
EngineName = EngName;
ParentHandle = Parent;	// not used

LocalTransparencyOverride = false;
ptrEngineStatusThread = NULL;

//
if (Setup->DisableEmergencyStopButton->Checked) {
	ESTOP->Visible = false;
    ESTOP->Enabled = false;
    ESTOP->Hint = "Disabled in Setup";
    ESTOP->Cursor = crNo;
    }
Engine_Status_Label->Caption = "Engine " + String(EngineNo) + " - " +
		EngineName + (SuperTIUMode && TIUSuperMode[TIUNo-1] ? String(" SuperTIUMode") : " - TIU " + String(TIUNo));

this->Caption = "Status : " + Engine_Status_Label->Caption;

#if __BORLANDC__ >= 0x720		// CB10.1 Only
Speed->Alignment = taCenter;
InstantSpeed->Alignment = taCenter;
DTO->Alignment = taCenter;
#endif

// Read preferences from the Registry
RegFileRootKey = MainForm->RegFileRootKey;
// Read Preferences from registry if they exist
TRegIniFile * const RegFile = new TRegIniFile(RegFileRootKey);
assert(RegFile != NULL);
__try {
	UpdateRateSpin->Value = RegFile->ReadInteger("EngineStatus", "EngineStatusCount" + String(TIUNo) + String(EngineNo), UpdateRateSpin->ValueAsInt);
	StatusUpdate->Checked = RegFile->ReadInteger("EngineStatus", "StatusUpdate" + String(TIUNo) + String(EngineNo), StatusUpdate->Checked);
	SpeedUpdate->Checked = RegFile->ReadInteger("EngineStatus", "SpeedUpdate" + String(TIUNo) + String(EngineNo), SpeedUpdate->Checked);
	InstantSpeedUpdate->Checked = RegFile->ReadInteger("EngineStatus", "InstantSpeedUpdate" + String(TIUNo) + String(EngineNo), InstantSpeedUpdate->Checked);
	DTOUpdate->Checked = RegFile->ReadInteger("EngineStatus", "DTOUpdate" + String(TIUNo) + String(EngineNo), DTOUpdate->Checked);
    }
__finally {
	// Deallocate RegFile
	delete RegFile;
    }

StartButton->Enabled = true;	// enable the start button
StopButton->Enabled = false;
}
//---------------------------------------------------------------------------
__fastcall TEngineStatus::~TEngineStatus(void)
{
// Stop the Engine Status Thread
if (ptrEngineStatusThread) {
	ptrEngineStatusThread->Terminate();	// thread will not free on terminate
	ptrEngineStatusThread->WaitFor();	// using WaifFor() with FreeOnTerminate causes "the handle is invalid (6)" error
    delete ptrEngineStatusThread;		// Free thread memory
    ptrEngineStatusThread = NULL;
    }
if (MainForm->bSaveRegistryInfo) {
    // write preferences to the Registry
    TRegIniFile * const RegFile = new TRegIniFile(RegFileRootKey);
    assert(RegFile != NULL);
    __try {
        RegFile->WriteInteger("EngineStatus", "EngineStatusCount" + String(TIUNo) + String(EngineNo), UpdateRateSpin->ValueAsInt);
        RegFile->WriteInteger("EngineStatus", "StatusUpdate" + String(TIUNo) + String(EngineNo), StatusUpdate->Checked);
        RegFile->WriteInteger("EngineStatus", "SpeedUpdate" + String(TIUNo) + String(EngineNo), SpeedUpdate->Checked);
        RegFile->WriteInteger("EngineStatus", "InstantSpeedUpdate" + String(TIUNo) + String(EngineNo), InstantSpeedUpdate->Checked);
        RegFile->WriteInteger("EngineStatus", "DTOUpdate" + String(TIUNo) + String(EngineNo), DTOUpdate->Checked);
        }
    __finally {
        // Deallocate RegFile
        delete RegFile;
        }
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineStatus::HideButtonClick(TObject *Sender)
{
Hide();	      				// Same as setting Visible to false
StopButtonClick(Sender);	// stop updates and terminate thread	
}
//---------------------------------------------------------------------------

void __fastcall TEngineStatus::ESTOPClick(TObject *Sender)
{
// emergency stop
// Send CM_EMERGENCYSTOP message to MainForm
(void) PostMessage(MainForm->Handle, CM_EMERGENCYSTOP, 0, 0);	
}
//---------------------------------------------------------------------------

void __fastcall TEngineStatus::StartButtonClick(TObject *Sender)
{
if (ptrEngineStatusThread) return;	// thread already running
// Start Thread
// Create suspended - in BCB 4.0, the thread constructor does not wait for lower level constructors itself.
// The Execute() routine actually runs before some lower level construction is finished.
// Don't put constructions in the thread constructor. if you have to, start the thread suspended and then start it running
// per Remy LeBeau (TeamB) it is a Known bug that was fixed in BCB 6.0
ptrEngineStatusThread = new TEngineStatusThread(true, this, Handle, EngineNo, TIUNo, RemoteNo, UpdateRateSpin->ValueAsInt * 1000L, true);
// FreeOnTerminate is not set in constructor so we must delete the thread when we are done
assert(ptrEngineStatusThread);				// make sure that construction worked
StartButton->Enabled = false;
StopButton->Enabled = true;
HideButton->Enabled = false;
LED->Checked = true;
#if __BORLANDC__ >= 0x720
ptrEngineStatusThread->Start();			// start the thread for CB10.1
#else
ptrEngineStatusThread->Resume();			// start the thread for BCB4.0 - use deprecated in CB10.1, use Start() instead
#endif
}
//---------------------------------------------------------------------------

void __fastcall TEngineStatus::StopButtonClick(TObject *Sender)
{
// Stop Thread
if (ptrEngineStatusThread) {
	ptrEngineStatusThread->Terminate();	// thread will not free on terminate
	ptrEngineStatusThread->WaitFor();	// using WaifFor() with FreeOnTerminate causes "the handle is invalid (6)" error
    delete ptrEngineStatusThread;		// Free thread memory
    ptrEngineStatusThread = NULL;
    }
StartButton->Enabled = true;
StopButton->Enabled = false;
HideButton->Enabled = true;
LED->Checked = false;
}
//---------------------------------------------------------------------------

void __fastcall TEngineStatus::Engine_Status_LabelClick(TObject *Sender)
{
LocalTransparencyOverride = !LocalTransparencyOverride;	// Toggle transparency locally	
}
//---------------------------------------------------------------------------
// Workaround for SetLayeredWindowAttributes() to make transparent windows
extern lpfnSetLayeredWindowAttributes m_pSetLayeredWindowAttributes;
//---------------------------------------------------------------------------
void __fastcall TEngineStatus::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);
// Ask the window and its children to repaint
//Repaint();
#endif	
}
//---------------------------------------------------------------------------

void __fastcall TEngineStatus::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 TEngineStatus::FormShow(TObject *Sender)
{
// ENG_PS may be changed and should be updated when this form is shown
// We must know if the engine is PS2 or PS3 before we can display Instantaneous Engine Speed
if (MainForm->EngineData->Cells[ENG_PS][EngineNo].ToInt() < PS2) {
    InstantSpeed->Enabled = false;
    InstantSpeedUpdate->Enabled = false;
    InstantSpeedLabel->Enabled = false;
    InstantUnitLabel->Enabled = false;
	} else {
    InstantSpeed->Enabled = true;
    InstantSpeedUpdate->Enabled = true;
    InstantSpeedLabel->Enabled = true;
    InstantUnitLabel->Enabled = true;
    }
}
//---------------------------------------------------------------------------

void __fastcall TEngineStatus::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;
    }
}
//---------------------------------------------------------------------------


