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

(c) 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>
#include <tchar.h>
#pragma hdrstop

#include "Train_Control.h"
#include "Setup_Control.h"
#include "Utility.h"
#include "Comm_Thread.h"

#include <algorithm>	// STL
#include <dir.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include "Clipbrd.hpp"

//
// This form may be auto or manual create
//
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "QuitButton"
#pragma resource "*.dfm"

extern String bitswapRX(String S);
extern String bitswapTX(String S);
extern String Convert16B8BNumber(String W);
extern String Convert8B16BNumber(String W);

extern unsigned char bintodec8(String W) ;
extern String dectobin8(int num);

TUtilities *Utilities;
//---------------------------------------------------------------------------
__fastcall TUtilities::TUtilities(TComponent* Owner)
	: TForm(Owner)
{
//
// read MRU from the Registry
RegFileRootKey = MainForm->RegFileRootKey;
// read MRU from registry if they exist
TRegIniFile * const RegFile = new TRegIniFile(RegFileRootKey);
assert(RegFile != NULL);
__try {

	MRUComboBox->ItemIndex = -1;
	for (int idx = 0 ; idx < MRUMAX ; idx++) {
        String S = RegFile->ReadString("MRU", "MRU" + String(idx + 1), "");
		if (!S.IsEmpty()) {
            MRUComboBox->Items->Append(S);
            } else {
            break;
            }
    	}
    MRUComboBox->ItemIndex = RegFile->ReadInteger("MRU", "MRUItemIndex", -1);
	}
__finally {
	// Deallocate RegFile
	delete RegFile;
	}
}
//---------------------------------------------------------------------------
__fastcall TUtilities::~TUtilities(void)
{
//
if (MainForm->bSaveRegistryInfo) {
    // write MRU to registry
    TRegIniFile * const RegFile = new TRegIniFile(RegFileRootKey);
    assert(RegFile != NULL);
    __try {
        int Cnt = MRUComboBox->Items->Count;
        if (Cnt > 0) {
            for (int idx = 0 ; idx < Cnt ; idx++) {
                RegFile->WriteString("MRU", "MRU" + String(idx + 1), MRUComboBox->Items->Strings[idx]);
                }
            }
        RegFile->WriteInteger("MRU", "MRUItemIndex", MRUComboBox->ItemIndex);
        }
    __finally {
        // Deallocate RegFile
        delete RegFile;
        }
	}
}
//---------------------------------------------------------------------------
void __fastcall TUtilities::D_DecChange(TObject *Sender)       // Decimal to Encoded
{
if (!D_Dec->Text.IsEmpty()){
    D_Bin->Text = dectobin8(D_Dec->Text.ToInt());  // to 8 bit Binary 	
    H_Bin->Text = "0x" + IntToHex(D_Dec->Text.ToInt(), 2);   // to Hex	
    C_Encoded->Text = bitswapTX(D_Bin->Text);  // to encoded Binary
    H_Encoded->Text = "0x" + IntToHex(bintodec8(C_Encoded->Text), 2);  // to encoded Hex
	Encoded->Text = Convert8B16BNumber(C_Encoded->Text);  // to encoded
    }
}
//---------------------------------------------------------------------------
void __fastcall TUtilities::EncodedExit(TObject *Sender)    // Encoded to Decimal
{
// Force Upper Case
	Encoded->Text = Encoded->Text.UpperCase();
// Convert to Decimal
	C_Encoded->Text = Convert16B8BNumber(Encoded->Text); // to encoded Binary
    H_Encoded->Text = "0x" + IntToHex(bintodec8(C_Encoded->Text), 2);  // to encoded Hex
    D_Bin->Text = bitswapRX(C_Encoded->Text);  // to Binary
    D_Dec->Text = bintodec8(D_Bin->Text);	// to Decimal
    H_Bin->Text = "0x" + IntToHex(D_Dec->Text.ToInt(), 2);   // to Hex	
}
//---------------------------------------------------------------------------
void __fastcall TUtilities::XORINChange(TObject *Sender)
{
// do an XOR
unsigned int p1;
unsigned int p2;
p1 = _tcstoul(XOR1IN->Text.c_str(), NULL , 16);
p2 = _tcstoul(XOR2IN->Text.c_str(), NULL , 16);
int p3 = p1 ^ p2;
XOROUT->Text = IntToHex(p3, 4);
}
//---------------------------------------------------------------------------
void __fastcall TUtilities::HexConChange(TObject *Sender)
{
// Convert to Integer
if (!HexCon->Text.IsEmpty()) {
    IntOut->Text = _tcstoul(HexCon->Text.c_str(), NULL , 16);
	} else {
    IntOut->Text = "0";
    }
}
//---------------------------------------------------------------------------
void __fastcall TUtilities::IntConChange(TObject *Sender)
{
// Convert to Hex
if (!IntCon->Text.IsEmpty()) {
	HexOut->Text = IntToHex(IntCon->Text.ToInt(), 4);
    } else {
    HexOut->Text = "0";
    }
}
//---------------------------------------------------------------------------
void __fastcall TUtilities::EncodedKeyPress(TObject *Sender, char &Key)
{
if (Key == VK_RETURN) {
	EncodedExit(Encoded);
	}	
}
//---------------------------------------------------------------------------
void __fastcall TUtilities::HideButtonClick(TObject *Sender)
{
Hide();	
}
//---------------------------------------------------------------------------

void __fastcall TUtilities::CreateEncodedTableClick(TObject *Sender)
{
MainForm->CRCBuffer->Lines->Append("Decimal");
MainForm->CRCBuffer->Lines->Append("   Hex");
MainForm->CRCBuffer->Lines->Append("       Encoded Binary (BitSwap)");
MainForm->CRCBuffer->Lines->Append("                Encoded Hex (BitSwap)");
MainForm->CRCBuffer->Lines->Append("                     8B16 Converted Hex");

for (int i = 0 ; i <= 255 ; i++) {
	D_Dec->Text = i;	// Put in Table
    D_Bin->Text = dectobin8(D_Dec->Text.ToInt());  // to 8 bit Binary	
    H_Bin->Text = "0x" + IntToHex(D_Dec->Text.ToInt(), 2);   // to Hex		// Put in Table	
    C_Encoded->Text = bitswapTX(D_Bin->Text);  // to encoded Binary 			// Put in Table
    H_Encoded->Text = "0x" + String::IntToHex(bintodec8(C_Encoded->Text), 2);  // to encoded Hex 			// Put in Table
	Encoded->Text = Convert8B16BNumber(C_Encoded->Text);  // to encoded 			// Put in Table

	MainForm->CRCBuffer->SelAttributes->Color = clBlack;
    String TableLine;
    TableLine = D_Dec->Text + " " +  H_Bin->Text + " " + C_Encoded->Text + " " + H_Encoded->Text  + " " + Encoded->Text;
	MainForm->CRCBuffer->Lines->Append(TableLine);
	}
}
//---------------------------------------------------------------------------

void __fastcall TUtilities::HextoStringClick(TObject *Sender)
{
StringOut->Text = MainForm->sDecodeString(HexStringIn->Text, false);
}
//---------------------------------------------------------------------------

void __fastcall TUtilities::MRUButtonClick(TObject *Sender)
{
// don't insert a duplicate string
int idx = MRUComboBox->Items->IndexOf(MRUComboBox->Text);
if (idx == -1) {
	MRUComboBox->Items->Insert(0, MRUComboBox->Text);
    MRUComboBox->ItemIndex = 0;
	if (MRUComboBox->Items->Count > MRUMAX) MRUComboBox->Items->Delete(MRUMAX);
    }
}
//---------------------------------------------------------------------------

void __fastcall TUtilities::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 TUtilities::Operation_Controls_LabelClick(TObject *Sender)
{
LocalTransparencyOverride = !LocalTransparencyOverride;	// Toggle transparency locally
}
//---------------------------------------------------------------------------
// Workaround for SetLayeredWindowAttributes() to make transparent windows
extern lpfnSetLayeredWindowAttributes m_pSetLayeredWindowAttributes;
//---------------------------------------------------------------------------
void __fastcall TUtilities::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 TUtilities::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 TUtilities::AddrInChange(TObject *Sender)
{
// Address Field Changed
int address, byteno;
// Convert to Integer
if (!AddrIn->Text.IsEmpty()) {
    address = _tcstoul(AddrIn->Text.c_str(), NULL , 16);
	} else {
    address = 0;
    }
if (!ByteIn->Text.IsEmpty()) {
    byteno = ByteIn->Text.ToInt();
    } else {
    byteno = 1;
    }
qOut->Text = IntToHex(RAMTOQ(address, byteno), 4);
}
//---------------------------------------------------------------------------

void __fastcall TUtilities::ByteInChange(TObject *Sender)
{
// Byte Number Field Changed
AddrInChange(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TUtilities::qInChange(TObject *Sender)
{
// q command Field Changed
int qcommand;
// Convert to Integer
if (!AddrIn->Text.IsEmpty()) {
    qcommand = _tcstoul(qIn->Text.c_str(), NULL , 16);
	} else {
    qcommand = 0;
    }
AddrOut->Text = IntToHex(QTORAM(qcommand), 4);
ByteOut->Text = QTOBYTE(qcommand);
}
//---------------------------------------------------------------------------
/*
//
// Convert a RAM address (0 - 0x3FF) and byte number (0-3) into a "q" command address
//
#define RAMTOQ(address, byteno) ( ((byteno) << 14) | (((address) & 0x0001) << 13 | ((address) & 0xFFE) >> 1) ^ 0x1F80)
//
// Convert a 'q' command address into a RAM address (0-0x3FF) and byte number (0-3)
//
#define QTORAM(qc)  ((((qc & 0x2000) >> 13) | ((qc & 0x01FF) << 1)) ^ 0x0300)
#define QTOBYTE(qc) ((qc & 0xC000) >> 14)
//---------------------------------------------------------------------------
*/
