//---------------------------------------------------------------------------
// Main Form
//---------------------------------------------------------------------------
#include <vcl.h>
#include <ShellApi.h>
#include <Printers.hpp>
#include <iostream>
#include <fstream>
#pragma hdrstop
//---------------------------------------------------------------------------
#include "CPanel.h"
#include "Graph.h"
#include "Param.h"
#include "Preview.h"
#include "New.h"
#include "Version.h"
#include "main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

TFMain *FMain;
//---------------------------------------------------------------------------
const char * Version = "QCAD - 2.00";
const char * QCADHP = "http://qcad.sourceforge.jp/";
//---------------------------------------------------------------------------
/**
 * Constructor
 * Initialize
 */
__fastcall
TFMain::TFMain(TComponent* Owner) : TForm(Owner) {

  //Accept Dropping files.
  DragAcceptFiles(Handle,true);
  Application->HelpFile = ExtractFileDir(Application->ExeName)+"\\qcad.hlp";

  qDraw = new QDraw(Image->Canvas);
  qManager = new QManager();
  qBits = new QBits();
  ChangeSize(qManager->GetLineNumber(),qManager->GetColumnNumber());
  qManager->DrawAll(qDraw);
  UpdateCaption();
  htmlhelp = Htmlhelp::GetInstance();
}
//---------------------------------------------------------------------------
/**
 * Destructer
 */
void __fastcall
TFMain::FormClose(TObject *Sender, TCloseAction &Action) {
  delete qBits;
  delete qDraw;
  delete qManager;
}
//---------------------------------------------------------------------------
void
TFMain::UpdateCaption(void) {
  AnsiString FileName = qManager->GetFileName().c_str();
  if (FileName =="") {
    if (qManager->IsModified()) {
      Caption = "QCAD * NewCircuit";
    } else {
      Caption = "QCAD - NewCircuit";
    }
  } else {
    if (qManager->IsModified()) {
      Caption = "QCAD * "+FileName;
    } else {
      Caption = "QCAD - "+FileName;
    }
  }
}
//---------------------------------------------------------------------------
/**
 * Change Circuit Size
 */
void
TFMain::ChangeSize(int Line,int Column) {

  int GridSize = qDraw->GetGridSize();
  int LineNumber = Line;
  int ColumnNumber = Column;
  Image->Picture = NULL;
  Image->Height = LineNumber * GridSize + GridSize;
  Image->Width = ColumnNumber * GridSize + GridSize*2;
  Image->Canvas->Brush->Color = clWhite;
  Image->Canvas->FillRect(Rect(0,0,Image->Width,Image->Height));

  ClientWidth = Image->Width;
  ClientHeight = Image->Height+ToolBar->Height;

  if (ClientWidth > MAX_WIDTH) {
    ClientWidth = MAX_WIDTH;
  }
  if (ClientHeight > MAX_HEIGHT) {
    ClientHeight = MAX_HEIGHT;
  }
  qDraw->SetCanvas(Image->Canvas);
  UpdateCaption();
}
//---------------------------------------------------------------------------
void
TFMain::EraseCircuit(int mx, int my) {
  QCircuit *qc = qManager->GetCircuitInclude(mx,my);
  if (qc==NULL || mx == 0) {
    return;
  }
  qManager->RemoveCircuit(qc);
  qManager->DrawAll(qDraw);
  UpdateCaption();
}
//---------------------------------------------------------------------------
void
TFMain::SelectCircuit(int mx, int my) {
  QCircuit *qc = qManager->GetCircuitInclude(mx,my);

  if (qc == NULL) {
    qManager->RemoveSelect(qDraw);
    return;
  }

  if (GetAsyncKeyState(VK_CONTROL)<0) {
    qManager->AddSelect(qc, qDraw);
  } else {
    qManager->RemoveSelect(qDraw);
    qManager->AddSelect(qc, qDraw);
  }
}
//---------------------------------------------------------------------------
void
TFMain::PutCircuit(int mx, int my) {
  FParam->CreateCircuit(FCPanel->GetCircuit(),mx,my,qDraw,qManager);
  qManager->DrawAll(qDraw);
  UpdateCaption();
}
//---------------------------------------------------------------------------
void
TFMain::ModifyCircuit(void) {

  qManager->RemoveSelect(qDraw);
  int mx = qDraw->GetPosX(MX);
  int my = qDraw->GetPosY(MY);

  QCircuit *qc = qManager->GetCircuitInclude(mx, my);
  if (qc==NULL) {
    return;
  }

  FParam->ModifyCircuit(qc,qManager);
  qManager->DrawAll(qDraw);
  UpdateCaption();
}
//---------------------------------------------------------------------------
void
TFMain::WMDropFiles(TWMDropFiles &Msg) {

  Show();
  SetFocus();
  SetForegroundWindow(Handle);

  char filename[MAX_PATH+1];
  int FileNum = DragQueryFile((void*)Msg.Drop,-1,NULL,0);
  if (FileNum!=1) {
    ShowMessage("QCAD does not support multi-file drop.");
    return;
  }

  DragQueryFile((void*)Msg.Drop,0,filename,sizeof(filename));
  DragFinish((void*)Msg.Drop);

  AnsiString FileName = filename;
  AnsiString Ext = ExtractFileExt(FileName);

  if (Ext == ".qdt") {
    ImportResult(FileName.c_str());
  } else if (Ext == ".qcd") {
    OpenFile(FileName.c_str());
  } else {
    ShowMessage("QCAD does not support this file type.");
  }
}
//---------------------------------------------------------------------------
/**
 * Save
 * return value
 * true : File is saved
 * false : File is not saved(Canceled)
 */
bool
TFMain::Save(void) {
  AnsiString FileName = qManager->GetFileName().c_str();
  if (FileName=="") {
    SaveDialog->Filter = "QCAD Files(*.qcd)|*.qcd|All Files(*.*)|*.*";
    SaveDialog->DefaultExt = "qcd";
    SaveDialog->FileName = "";
    if (!SaveDialog->Execute()) {
      return false;
    }
    FileName = SaveDialog->FileName;
  }
  qManager->SaveToFile(FileName.c_str());
  UpdateCaption();
  return true;
}
//---------------------------------------------------------------------------
/**
 * Save Query
 * return value
 * true: One can proceed.
 * false: Process is canceled.
 */
bool
TFMain::SaveQuery(void) {
  if (!qManager->IsModified()) {
    return true;
  }

  int r = MessageBox(Handle, "File is modified, save it before quit?","QCAD - Alert",MB_YESNOCANCEL);

  if (r == IDYES) {
    return Save();
  } else if (r == IDNO) {
    return true;
  }
  return false;
}
//---------------------------------------------------------------------------
void
TFMain::ImportResult(char *FileName) {

  qBits->LoadFromFile(FileName);
  qManager->CalcAll(qBits);

  FGraph->Show();
  FGraph->Execute(qBits);
}
//---------------------------------------------------------------------------
void
TFMain::OpenFile(AnsiString FileName) {
  qManager->LoadFromFile(FileName.c_str());
  ChangeSize(qManager->GetLineNumber(),qManager->GetColumnNumber());
  qManager->DrawAll(qDraw);
  UpdateCaption();
}
//---------------------------------------------------------------------------
// Events of Menu
//---------------------------------------------------------------------------
/**
 * New Circuit
 */
void __fastcall
TFMain::MMNewClick(TObject *Sender) {
  if (!SaveQuery()) {
    return;
  }
  if (!FNew->Execute(qManager->GetLineNumber(),qManager->GetColumnNumber())) {
    return;
  }

  ChangeSize(FNew->GetLineNumber(),FNew->GetColumnNumber());
  qManager->Init(FNew->GetLineNumber(),FNew->GetColumnNumber());
  qManager->DrawAll(qDraw);
  UpdateCaption();
}
//---------------------------------------------------------------------------
/**
 * Open
 */
void __fastcall
TFMain::MMOpenClick(TObject *Sender) {
  OpenDialog->Filter = "QCAD Files(*.qcd)|*.qcd|All Files(*.*)|*.*";
  OpenDialog->DefaultExt = "qcd";
  if (!OpenDialog->Execute()) {
    return;
  }
  OpenFile(OpenDialog->FileName);
}
//---------------------------------------------------------------------------
/**
 * Save
 */
void __fastcall
TFMain::MMSaveClick(TObject *Sender) {
  Save();
}
//---------------------------------------------------------------------------
/**
 * Save as
 */
void __fastcall
TFMain::MMSaveAsClick(TObject *Sender) {
  SaveDialog->Filter = "QCAD Files(*.qcd)|*.qcd|All Files(*.*)|*.*";
  SaveDialog->DefaultExt = "qcd";
  SaveDialog->FileName = "";
  if (!SaveDialog->Execute()) {
    return;
  }
  qManager->SetFileName(SaveDialog->FileName.c_str());
  Save();
}
//---------------------------------------------------------------------------
/**
 * Save as EPS file
 */
void __fastcall
TFMain::MMSaveAsPSClick(TObject *Sender) {

  SaveDialog->Filter = "PostScriptFiles(*.eps)|*.eps|All Files(*.*)|*.*";
  SaveDialog->DefaultExt = "eps";
  SaveDialog->FileName = "";
  if (!SaveDialog->Execute()) {
    return;
  }
  qManager->SaveAsEPS(SaveDialog->FileName.c_str());
}
//---------------------------------------------------------------------------
/**
 * Save as Bitmap File
 */
void __fastcall
TFMain::MMSaveAsBMPClick(TObject *Sender) {
  SaveDialog->Filter = "BitmapFiles(*.bmp)|*.bmp|All Files(*.*)|*.*";
  SaveDialog->DefaultExt = "bmp";
  SaveDialog->FileName = "";
  if (!SaveDialog->Execute()) {
    return;
  }
  Image->Picture->Bitmap->HandleType = bmDIB;
  Image->Picture->Bitmap->PixelFormat = pf8bit;
  Image->Picture->Bitmap->SaveToFile(SaveDialog->FileName);
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::MMCircuitPanelClick(TObject *Sender) {
  FCPanel->Show();
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::MMPrintClick(TObject *Sender) {

  if (!PrintDialog->Execute())return;

  TPrinter *p = Printer();
  int x = GetDeviceCaps(p->Handle, LOGPIXELSX);
  int y = GetDeviceCaps(p->Handle, LOGPIXELSY);
  int gridx = 10  * x / qManager->GetColumnNumber();
  int gridy = int(7.4 * y / qManager->GetLineNumber());

  QDraw *qPrintDraw  = new QDraw(p->Canvas);
  p->Orientation = poLandscape;
  p->BeginDoc();
  if (gridx < gridy) {
    qPrintDraw->SetGridSize(gridx);
  } else {
    qPrintDraw->SetGridSize(gridy);
  }
  qManager->DrawAllPrinter(qPrintDraw);

  p->EndDoc();
  delete qPrintDraw;
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::MMPrintSetupClick(TObject *Sender) {

  TPrinter *p = Printer();
  p->Orientation = poLandscape;

  if (!PrinterSetupDialog->Execute()) {
    return;
  }
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::MMExitClick(TObject *Sender) {
  Close();
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::MMUndoClick(TObject *Sender) {
  qManager->Undo(qDraw);
  UpdateCaption();
}
//---------------------------------------------------------------------------
/**
 * Remove
 */
void __fastcall
TFMain::MMRemoveClick(TObject *Sender) {
  qManager->RemoveSelectedCircuits(qDraw);
  UpdateCaption();
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::MMRunClick(TObject *Sender) {

  if (qManager->GetLineNumber()>20) {
    int r = MessageBox(Handle,
                       "You are going to calculate a large circuit.\n"
                       "It may require huge memory and time.\n"
                       "Are you sure to execute?","QCAD - Alert",MB_YESNO);

    if (r == IDNO)return;
  }

  qBits->Allocate(qManager->GetLineNumber());
  qManager->CalcAll(qBits);

  FGraph->Execute(qBits);
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::MMImportResultClick(TObject *Sender) {
  OpenDialog->Filter = "QCAD Results(*.qdt)|*.qdt|All Files(*.*)|*.*";
  OpenDialog->DefaultExt = "qdt";
  if (!OpenDialog->Execute()) {
    return;
  }
  char *FileName = OpenDialog->FileName.c_str();
  ImportResult(FileName);
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::MMHelpClick(TObject *Sender) {
  AnsiString HtmlHelp = ExtractFileDir(Application->ExeName) + "\\qcadhelp.chm";
  if(!FileExists(HtmlHelp)){
    ShowMessage("Cannot find help file " + HtmlHelp);
  }else{
    htmlhelp->ShowHtmlHelp(this->Handle,HtmlHelp.c_str());
  }
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::MMAboutClick(TObject *Sender) {
  FVersion->ShowModal();
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::ImageMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) {
  MX = X;
  MY = Y;
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::FormMouseWheel(TObject *Sender, TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled) {
  const double d = 0.5;
  if (!VertScrollBar->Visible) {
    return;
  }
  int pos = VertScrollBar->Position;
  pos -= (int)(WheelDelta*d);

  if (pos < 0) {
    pos = 0;
  }
  if (pos > VertScrollBar->Range) {
    pos = VertScrollBar->Range;
  }
  VertScrollBar->Position = pos;
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::ImageDblClick(TObject *Sender) {
  ModifyCircuit();
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::ImageClick(TObject *Sender) {
  int mx = qDraw->GetPosX(MX);
  int my = qDraw->GetPosY(MY);
  if (mx<0 || mx>=qManager->GetColumnNumber()) {
    return;
  }
  if (my<0 || my>=qManager->GetLineNumber()) {
    return;
  }
  if (FCPanel->GetCircuit() == CP_ERASE) {
    EraseCircuit(mx,my);
  } else if (FCPanel->GetCircuit() == CP_ARROW) {
    SelectCircuit(mx,my);
  } else {
    PutCircuit(mx,my);
  }

}
//---------------------------------------------------------------------------
void __fastcall
TFMain::FormDeactivate(TObject *Sender) {
  qManager->RemoveSelect(qDraw);
}
//---------------------------------------------------------------------------

void __fastcall
TFMain::FormCloseQuery(TObject *Sender, bool &CanClose) {
  if (!SaveQuery()) {
    CanClose = false;
  }
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::MMPreViewPrintClick(TObject *Sender) {
  FPreview->Execute(qManager);
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::MMShowAllClick(TObject *Sender) {
  MMShowAll->Checked = true;
}
//---------------------------------------------------------------------------
void __fastcall
TFMain::MMShowNonZeroClick(TObject *Sender) {
  MMShowNonZero->Checked = true;
}
//---------------------------------------------------------------------------

