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

#include <vcl.h>
#pragma hdrstop

#include "ChatClientMainForm.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "IdBaseComponent"
#pragma link "IdComponent"
#pragma link "IdTCPClient"
#pragma link "IdTCPConnection"
#pragma link "IdAntiFreeze"
#pragma link "IdAntiFreezeBase"
#pragma resource "*.dfm"
TfrmChatClientMain *frmChatClientMain;

// For Unicode support
#define ENCODING
TEncoding* CharacterEncoding = TIdTextEncoding::UTF8;

//---------------------------------------------------------------------------
__fastcall TfrmChatClientMain::TfrmChatClientMain(TComponent* Owner) : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TfrmChatClientMain::FormCreate(TObject *Sender)
{
  mmoHistory->Align = alClient;
}
//---------------------------------------------------------------------------
void __fastcall TfrmChatClientMain::btnConnectClick(TObject *Sender)
{
  try
  {
    try
    {
        // If we're already connect, disconnect from the server
      if (tcpClient->Connected())
      {
        DisconnectFromServer();
      }
      else // we're not connected, so connect to the server
      {
        ConnectToServer(); // this is a blocking call
      }
    }
    catch (const Exception& e)
    {
      ShowMessage(e.Message);
    }
  }
  __finally
  {
    if (tcpClient->Connected())
      btnConnect->Caption = "Disconnect";
    else
      btnConnect->Caption = "Connect";
  }
}
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
void TfrmChatClientMain::ConnectToServer(void)
{
  tcpClient->Host = lstServer->Text;
  tcpClient->Port = (short)ledtPort->Text.ToInt();
  btnConnect->Caption = "Disconnect";
  tcpClient->Connect();
}
//---------------------------------------------------------------------------
void TfrmChatClientMain::DisconnectFromServer(void)
{
  btnConnect->Caption = "Connect";
  if (tcpClient->Connected())
  {
    tcpClient->Disconnect();
  }
}
//---------------------------------------------------------------------------
// Send text command to the server and to the output window
void TfrmChatClientMain::SendCommand(const String& command)
{
  if (tcpClient->Connected())
  {
    String msg = "SEND " + command;
    tcpClient->Socket->WriteLn(msg);

    String out = "[" + FClientIP + ":" + FClientPort + "] " + command;
    UpdateOutput(out, dirSEND);
  }
  else
  {
    UpdateOutput("Not connected [" + command + "]");
  }
}

void TfrmChatClientMain::UpdateOutput(const String& s, TDirection dir)
{
  String d = "";
  TColor attr = clBlack;
  if (dir == dirSEND)
  {
    d = "SEND --> ";
    attr = clBlue;
  }
  else if (dir == dirRECV)
  {
    d = "RECV <-- ";
    attr = clRed;
  }

  d = "";

  /*
      This works differently than I expected. If you set the attributes, and
      then Add() lines to the control, everything works fine. But, if you
      Insert() the lines, you need to insert them before setting the attribute.
      If you don't, you'll get the new attribute applied to the item at index
      0, which will be scrolled down to index 1 after the insert and will have
      the new attribute applied.
  */
  String str = d + s;
  mmoHistory->Lines->BeginUpdate();
  if (chkInsertLinesAtTop->Checked)
  {
      // Insert the line
    mmoHistory->Lines->Insert(0, str);

      // Select the line and then apply the color (attributes) to the selection
    mmoHistory->SelStart = 0;
    mmoHistory->SelLength = str.Length();
    mmoHistory->SelAttributes->Color = attr;
  }
  else
  {
    mmoHistory->SelAttributes->Color = attr;
    mmoHistory->Lines->Add(str);
  }
  mmoHistory->Lines->EndUpdate();
}

void __fastcall TfrmChatClientMain::btnSendClick(TObject *Sender)
{
  SendCommand(ledtCommand->Text);
}
//---------------------------------------------------------------------------
void __fastcall TfrmChatClientMain::tcpClientConnected(TObject *Sender)
{
  //////////////////////////////////////////////////////////////////////////////
  // This block of code is executed once when the client first connects.
  String s = "Connected to " + lstServer->Text;
  UpdateOutput(s, dirNEITHER);
  s = "Remote " + tcpClient->Socket->Binding->PeerIP + ":" + tcpClient->Socket->Binding->PeerPort;

  FClientIP = tcpClient->Socket->Binding->IP;
  FClientPort = tcpClient->Socket->Binding->Port;

  UpdateOutput(s, dirNEITHER);
  s = "Local " + tcpClient->Socket->Binding->IP + ":" + tcpClient->Socket->Binding->Port;
  UpdateOutput(s, dirNEITHER);
  //////////////////////////////////////////////////////////////////////////////

  #ifdef ENCODING
    tcpClient->IOHandler->DefStringEncoding = CharacterEncoding;
  #endif

    // Continue to process all messages from the server until we disconnect
  while (tcpClient->Connected())
  {
      // See if there is a message from the server
    String s = tcpClient->Socket->ReadLn("", 50);
    if (tcpClient->Socket->ReadLnTimedout)
    {
      // This will occur when there is no message waiting
    }
    else if (s != "")
    {
      if (!CompareText(s.SubString(1, 4), "MESG"))
      {
          // TODO: Clean this up. Kind of a hack to parse the string
        TStringList *list = new TStringList;
        list->DelimitedText = s;
        list->Delimiter = ' ';

          // Don't display our own message
        if (list->Strings[1] == FClientIP + ":" + FClientPort)
        {
          delete list;
          continue;
        }

        String out = "[" + list->Strings[1] + "]";
        for (int j = 2; j < list->Count; j++)
          out += " " + list->Strings[j];

        UpdateOutput(out, dirRECV);
        delete list;
      }
      else
      {
        UpdateOutput(s, dirNEITHER);
      }
    }
    else
    {
      // do something?
    }
  }
}
//---------------------------------------------------------------------------
void __fastcall TfrmChatClientMain::FormClose(TObject *Sender, TCloseAction &Action)
{
  DisconnectFromServer();
}
//---------------------------------------------------------------------------
void __fastcall TfrmChatClientMain::ledtCommandKeyPress(TObject *Sender, wchar_t &Key)
{
  if (Key == VK_RETURN)
  {
    SendCommand(ledtCommand->Text);
    Key = 0;
  }
}
//---------------------------------------------------------------------------