/*
  ICS Telnet Client - C++Builder translation of the Delphi demo OverbyteIcsTelnetClient1.pas
  (demos-delphi-vcl), ICS V9.8.

  A basic telnet terminal built on the TTnEmulVT component (terminal emulation plus telnet
  connection). Host, port and window position are kept in the ICS ini file.

  How this C++ version differs from the Delphi original, apart from syntax:
  - OnLocalEcho of the terminal is wired up (the Delphi handler exists but is never bound).
  - The ini file object is held in std::unique_ptr, so it is freed on every exit path.
*/

#include <vcl.h>
#pragma hdrstop

#include <memory>

// OverbyteIcsEmulVT.hpp redeclares the AutoResize property as "AutoReSize" (a Pascal case-only
// difference, Source\OverbyteIcsEmulVT.pas:543), which C++ rejects: spell it as the base class does.
#define AutoReSize AutoResize
#include "OverbyteIcsTelnetClient1.h"
#undef AutoReSize
#include "OverbyteIcsIniFiles.hpp"
#include "OverbyteIcsUtils.hpp"
#include "OverbyteIcsWSocket.hpp"

#pragma package(smart_init)
#pragma link "OverbyteIcsEmulVT"
#pragma resource "*.dfm"

TTelnetForm *TelnetForm;

namespace {

const String SectionWindow = "Window";
const String KeyTop        = "Top";
const String KeyLeft       = "Left";
const String KeyWidth      = "Width";
const String KeyHeight     = "Height";
const String SectionData   = "Data";
const String KeyHostName   = "HostName";
const String KeyPort       = "Port";

} // namespace

__fastcall TTelnetForm::TTelnetForm(TComponent *Owner)
    : TForm(Owner)
{
}

void __fastcall TTelnetForm::FormCreate(TObject *Sender)
{
    Caption = Caption + IcsVerLitSample;   // common ICS sample caption: version and date
    FIniFileName = GetIcsIniFileName();
    TnEmulVT1->IniFilename = FIniFileName;
    // the Delphi form declares this handler but never binds it, so its status text never showed
    TnEmulVT1->OnLocalEcho = TnEmulVT1LocalEcho;
    StatusLabel->Caption = "Not connected";
    TnEmulVT1->RestoreOptions();
}

void __fastcall TTelnetForm::FormShow(TObject *Sender)
{
    if (FInitialized)
        return;
    FInitialized = true;

    {
        // PreserveAnsi must be passed in C++ (Pascal default TRUE is not in the .hpp)
        std::unique_ptr<TIcsIniFile> ini(new TIcsIniFile(FIniFileName, true));
        HostNameEdit->Text = ini->ReadString(SectionData, KeyHostName, "localhost");
        PortEdit->Text = ini->ReadString(SectionData, KeyPort, "telnet");

        Width = ini->ReadInteger(SectionWindow, KeyWidth, Width);
        Height = ini->ReadInteger(SectionWindow, KeyHeight, Height);
        Top = ini->ReadInteger(SectionWindow, KeyTop, (Screen->Height - Height) / 2);
        Left = ini->ReadInteger(SectionWindow, KeyLeft, (Screen->Width - Width) / 2);
    }

    TnEmulVT1->Clear();
    TnEmulVT1->WriteStr("\033[?7h");   // ESC [ ? 7 h: auto-wrap mode; other terminal settings go here
    TWSAData winsockData = WinsockInfo();
    StatusLabel->Caption = String(IcsStrPas(winsockData.szDescription));
}

void __fastcall TTelnetForm::FormClose(TObject *Sender, TCloseAction &Action)
{
    std::unique_ptr<TIcsIniFile> ini(new TIcsIniFile(FIniFileName, true));
    ini->WriteString(SectionData, KeyHostName, HostNameEdit->Text);
    ini->WriteString(SectionData, KeyPort, PortEdit->Text);
    ini->WriteInteger(SectionWindow, KeyTop, Top);
    ini->WriteInteger(SectionWindow, KeyLeft, Left);
    ini->WriteInteger(SectionWindow, KeyWidth, Width);
    ini->WriteInteger(SectionWindow, KeyHeight, Height);
    ini->UpdateFile();
}

void __fastcall TTelnetForm::ConnectButtonClick(TObject *Sender)
{
    StatusLabel->Caption = "Connecting";
    Refresh();
    ConnectButton->Enabled = false;
    try {
        TnEmulVT1->Disconnect();
        TnEmulVT1->Port = PortEdit->Text;
        TnEmulVT1->HostName = HostNameEdit->Text;
        TnEmulVT1->RestoreOptions();
        // An unknown host name can take 2 or 3 minutes if the DNS feature is enabled
        TnEmulVT1->Connect();
    }
    catch (Exception &) {
        ConnectButton->Enabled = true;
        throw;
    }
}

void __fastcall TTelnetForm::DisconnectButtonClick(TObject *Sender)
{
    TnEmulVT1->Disconnect();
}

void __fastcall TTelnetForm::TnEmulVT1SessionConnected(TObject *Sender)
{
    DisconnectButton->Enabled = true;
    StatusLabel->Caption = "Connected";
    TnEmulVT1->LocalEcho = LocalEchoCheckBox->Checked;
}

void __fastcall TTelnetForm::TnEmulVT1SessionClosed(TObject *Sender)
{
    DisconnectButton->Enabled = false;
    ConnectButton->Enabled = true;
    StatusLabel->Caption = "Not connected";
}

void __fastcall TTelnetForm::FormResize(TObject *Sender)
{
    TnEmulVT1->Width = ClientWidth;
    TnEmulVT1->Height = ClientHeight - TnEmulVT1->Top;
}

void __fastcall TTelnetForm::SendButtonClick(TObject *Sender)
{
    TnEmulVT1->SendStr("Hello world !\r\n");
    ActiveControl = TnEmulVT1;
}

void __fastcall TTelnetForm::OptionsButtonClick(TObject *Sender)
{
    TnEmulVT1->HostName = HostNameEdit->Text;
    TnEmulVT1->EditOptions();
    TnEmulVT1->LocalEcho = LocalEchoCheckBox->Checked;
    ActiveControl = TnEmulVT1;
}

void __fastcall TTelnetForm::TnEmulVT1LocalEcho(TObject *Sender)
{
    if (TnEmulVT1->GetLocalEcho())
        StatusLabel->Caption = "Remote will not echo";
    else
        StatusLabel->Caption = "Remote will echo";
}

void __fastcall TTelnetForm::LocalEchoCheckBoxClick(TObject *Sender)
{
    TnEmulVT1->LocalEcho = LocalEchoCheckBox->Checked;
    ActiveControl = TnEmulVT1;
}

void __fastcall TTelnetForm::RequestLocalEchoOnButtonClick(TObject *Sender)
{
    TnEmulVT1->RequestLocalEcho(true);
    ActiveControl = TnEmulVT1;
}

void __fastcall TTelnetForm::RequestLocalEchoOffButtonClick(TObject *Sender)
{
    TnEmulVT1->RequestLocalEcho(false);
    ActiveControl = TnEmulVT1;
}
