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

#include <vcl.h>
#pragma hdrstop

#include "MainForm.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmMain *frmMain;

/*
  Constructor
*/
__fastcall TfrmMain::TfrmMain(TComponent* Owner) : TForm(Owner)
{
  Filename_ = "";         // No filename yet
  AppName_ = "Notepad#";  // Display in the title bar
  Dirty_ = false;         // No changes yet
}
//---------------------------------------------------------------------------

/*
  If the user wants to open another file or create a new one, this
  method should be called to handle the saving of the current file.
  If the user doesn't wish to save the file or successfully saves it,
  the function returns true. If the user cancels the save, the function
  returns false. This lets the calling function take the appropriate action.
*/
bool TfrmMain::CheckAndSave(void)
{
    // If the document has changed (i.e. it's dirty), prompt the
    // user with a dialog box asking whether or not to save it.
  if (Dirty_)
  {
    AnsiString msg;

      // There is no filename yet, nothing to display in the dialog
    if (Filename_ == "")
      msg = "Save changes?";
    else
    {
        // Just display the filename (no path) in the dialog
      AnsiString file = ExtractFileName(Filename_);
      msg = Format("Save changes to %s?", ARRAYOFCONST((file)));
    }

      // Show dialog and wait for user to press a key (Yes, No, Cancel)
    int key = MessageDlg(msg, mtWarning, TMsgDlgButtons() << mbYes << mbNo << mbCancel, 0);

      // User canceled, no action was taken
    if (key == mrCancel)
      return false;
      // User said yes, so try to save it
    else if (key == mrYes)
    {
        // If this returns false, the user canceled the save action
      if (!SaveFile(Filename_))
        return false;
    }
  }
    // We've saved, if necessary, and took the correct action
  return true;
}

/*
  Load a file named "filename" into the TMemo component. Probably need
  some error checking here if the user is allowed to enter an invalid
  filename.
*/
bool TfrmMain::LoadFile(const AnsiString &filename)
{
    // Check if we need to save first
  if (CheckAndSave())
  {
      // Load the file into the memo
    mmoEditor->Lines->LoadFromFile(filename);

    Filename_ = filename; // We have a valid filename
    Dirty_ = false;       // No changes yet
    UpdateTitleBar();     // Display filename in title bar
    UpdateStatusBar();    // Show state of file (e.g. Dirty)
    return true;          // Loaded the file
  }
  return false;           // Canceled
}

/*
  Writes the contents of the TMemo component to a disk file. Probably need
  some error checking here if the user is allowed to enter an invalid
  filename.
*/
bool TfrmMain::SaveFile(const AnsiString &filename)
{
    // Assume we got a "real" filename
  AnsiString fname = filename;

    // If it's empty, the document has never been saved
  if (filename == "")
  {
      // Ask the user for a name for the file
    if (actFileSaveAs->Dialog->Execute())
      fname = actFileSaveAs->Dialog->FileName;
    else
      return false; // User canceled the operation
  }
    // Write the document to the disk
  mmoEditor->Lines->SaveToFile(fname);
  Filename_ = fname;  // Update the filename (the user provided one)
  Dirty_ = false;     // The document is now clean
  UpdateTitleBar();   // Display filename in the title bar
  UpdateStatusBar();  // Show state of file (e.g. Dirty)
  return true;
}

/*
  Puts the name of the file (if there is one) and the application name
  into the title bar
*/
void TfrmMain::UpdateTitleBar(void)
{
  if (Filename_ != "")
    Caption = ExtractFileName(Filename_) + " - " + AppName_;
  else
    Caption = AppName_;
}

/*
  If the file is dirty, put the word "Dirty" in a status panel. Otherwise,
  clear it.
*/
void TfrmMain::UpdateStatusBar(void)
{
  if (Dirty_)
    barStatus->Panels->Items[0]->Text = " Dirty";
  else
    barStatus->Panels->Items[0]->Text = "";
}

/*
  This function extracts the position of the caret from the TMemo component,
  formats a string, and displays it in a status panel.
*/
void TfrmMain::FormatCaretPos(void)
{
    // Get the position of the caret in the memo
  TPoint pt = mmoEditor->CaretPos;

    // Format the text
  AnsiString msg = Format(" Ln %d, Col %d", ARRAYOFCONST((pt.y + 1, pt.x + 1)));

    // Put it into the right-most panel in the status bar
  barStatus->Panels->Items[2]->Text = msg;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Event Handlers
///////////////////////////////////////////////////////////////////////////////
/*
  This handles the "New" action and is hooked up to the
  File | New menu item.
*/
void __fastcall TfrmMain::actFileNewExecute(TObject *Sender)
{
    // Check to see if there is a file already opened and if
    // it needs to be saved or not. Returns true if it's OK
    // to clear the current document
  if (CheckAndSave())
  {
    mmoEditor->Clear(); // Empty the contents of the memo
    Filename_ = "";     // New documents have no name yet
    Dirty_ = false;     // Obviously it's unchanged
    UpdateTitleBar();   // Set title bar
    UpdateStatusBar();  // Set status bar (e.g. dirty)
  }
}
//---------------------------------------------------------------------------

/*
  Handles the "Open" action.
*/
void __fastcall TfrmMain::actFileOpenExecute(TObject *Sender)
{
    // Check to see if there is a file already opened and if
    // it needs to be saved or not. Returns true if it's OK
    // to clear the current document
  if (CheckAndSave())
  {
    bool tempDirty = Dirty_; // save state
    Dirty_ = false;          // temporarily mark it clean
    if (dlgFileOpen->Execute())
    {
      LoadFile(dlgFileOpen->FileName);
    }
    else
      Dirty_ = tempDirty;    // if the user canceled the File | Open
                             // reset the state of the existing document
  }
}
//---------------------------------------------------------------------------

/*
  Handles the "Save" action and is hooked up to the File | Save menu item.
*/
void __fastcall TfrmMain::actFileSaveExecute(TObject *Sender)
{
  SaveFile(Filename_);
}
//---------------------------------------------------------------------------

/*
  This handles the "Save As" action item and is hooked up to
  the File | Save As... menu item. Since the "Save As" action is
  a standard action (one of the predefined actions), it has its own
  Save dialog, so we don't have to display it manually. This event
  occurs after the user has already chosen a filename. If the
  user canceled the dialog, we don't need to respond to anything.
*/
void __fastcall TfrmMain::actFileSaveAsAccept(TObject *Sender)
{
    // The user has chosen a filename, so we will save it to that filename.
  SaveFile(actFileSaveAs->Dialog->FileName);
}
//---------------------------------------------------------------------------

/*
  Handles the "Exit" action and is hooked up to the File | Exit menu item.
*/
void __fastcall TfrmMain::actFileExitExecute(TObject *Sender)
{
  Close(); // Closing the main form causes the app to close "gracefully"
}
//---------------------------------------------------------------------------

/////////////////////////////////////////////////////////////////////////////
// The event handlers below are not actions.
/////////////////////////////////////////////////////////////////////////////

/*
  Handles the OnCreate event (WM_CREATE message when the form is created.)
*/
void __fastcall TfrmMain::FormCreate(TObject *Sender)
{
    // Force the TMemo to occupy the entire window
  mmoEditor->Align = alClient;
}
//---------------------------------------------------------------------------

/*
  This event occurs whenever the contents of the TMemo component change.
*/
void __fastcall TfrmMain::mmoEditorChange(TObject *Sender)
{
  Dirty_ = true;     // The contents have changed, so mark it dirty
  UpdateStatusBar(); // Update the status bar to reflect the state
}
//---------------------------------------------------------------------------

/*
  This event occurs whenever the form is resized.
*/
void __fastcall TfrmMain::FormResize(TObject *Sender)
{
    // We want the middle panel to be sized relative to the width
    // of the form. To see what happens to the status bar without
    // this code, comment the line out, run the program, and
    // resize the form. You'll get the idea of the behavior.
    // I do this because I want the right-most panel to always be
    // able to display the postion of the caret.
  barStatus->Panels->Items[1]->Width = Width - 200;
}
//---------------------------------------------------------------------------

/*
  This event occurs whenever a keyup happens in the TMemo component.
*/
void __fastcall TfrmMain::mmoEditorKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
{
    // Update the display of the caret's position
  FormatCaretPos();
}
//---------------------------------------------------------------------------

/*
  This event occurs whenever a keydown happens *anywhere* on the form. In order
  for the form to intercept all keydowns (regardless of the component the key
  down was sent to) you have to enable the KeyPreview property of the form.
  You can do that in the Object Inspector at design time, or in the
  constructor at runtime.
*/
void __fastcall TfrmMain::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
    // Update the display of the caret's position
  FormatCaretPos();
}
//---------------------------------------------------------------------------