// ------------------------------- //
// -------- Start of File -------- //
// ------------------------------- //
// ----------------------------------------------------------- // 
// C++ Source Code File Name: testprog.cpp 
// C++ Compiler Used: MSVC 4.2 
// Produced By: Doug Gaer 
// File Creation Date: 12/16/1997 
// Date Last Modified: 10/15/1998
// ----------------------------------------------------------- // 
// ------------- Program Description and Details ------------- // 
// ----------------------------------------------------------- // 
/*
This is a a test program for the Variable Block Database 
file manger class built using the wxWindows 1.68 GUI library.
*/
// ----------------------------------------------------------- //
#include "ehandler.hpp"
#include "vbdfile.hpp"
#include "float64.hpp"
#include "vbdstats.hpp"

#ifdef __GNUG__
#pragma implementation
#pragma interface
#endif

// For compilers that support precompilation, includes "wx.h".
#include "wx_prec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx.h"
#endif

// Define new frame types
class MyTextWindow;

// File menu functions
void Run(MyTextWindow &textWin);

// View menu functions
void Clear(MyTextWindow &textWin);

// Control key macro
#define CONTROL(c) ((c) & 037)

// General character string utilities
char *StringCat(const char *s1=" ", const char *s2= " ", const char *s3=" ");
char *StringCat(char *s1=" ", char *s2= " ", char *s3=" ");

// (V)ariable (B)lock (D)atabse components
VBDFilePtr f(new VBDFile);  
const char *FName = "testfile.vbd";
void VBDFileStats(MyTextWindow &textWin);

class Part
{ 
public:
  Part(INT32 i = 0, FLOAT64 p = 0) { id = i; price = p; }

public:
  INT32 id; 
  FLOAT64 price;
};

// Define a new text subwindow that can respond to drag-and-drop
class MyTextWindow: public wxTextWindow
{
  public:
  MyTextWindow(wxFrame *frame, int x=-1, int y=-1, int width=-1, int height=-1,
               long style=0):
    wxTextWindow(frame, x, y, width, height, style) { DragAcceptFiles(TRUE); }

  void OnDropFiles(int n, char *files[], int x, int y) { LoadFile(files[0]); }
  void OnChar(wxKeyEvent& event);
};

// Define a new application type
class MyApp: public wxApp
{
public:
  wxFrame *OnInit();
};

// Define a new frame type
class MyFrame: public wxFrame
{
public:
  MyFrame(wxFrame *frame, char *title, int x, int y, int w, int h);

public:
  void OnMenuCommand(int id);
  Bool OnClose();

public:
  MyTextWindow *textWin;  // Text window for main frame
  MyTextWindow *StextWin; // Text window for sub frame
};

// Declare frame, subframe and menu objects
MyFrame *frame = 0;
wxMenuBar *menu_bar = 0;
wxFrame *subframe = 0;

// Identification for the all main menu functions
enum {
  // File menu constants
  FILE_QUIT = 1,
  FILE_RUN,
  FILE_VBDSTATS,

  // Edit menu constants
  EDIT_CUT,   
  EDIT_COPY,  
  EDIT_PASTE, 

  // View menu constants
  VIEW_CLEAR,
  VIEW_STATWIN,

  // Help menu constants
  HELP_ABOUT
};

// Program name and subframe information displayed in the frame 
const char *ProgName = "Variable Block Database Test program";
const char *TSubName = "VBD Statistics window";

// Version number for this windows program 
const char *VerNumber = "1027.101";

// This statement initializes the whole application and calls OnInit
MyApp myApp;

// A macro needed for some compilers (AIX) that need 'main' to be defined
// in the application itself.
IMPLEMENT_WXWIN_MAIN

// `Main program' equivalent, creating windows and returning main app frame
wxFrame *MyApp::OnInit(void)
{
  // Create the main frame window
  frame = new MyFrame(NULL, (char *)ProgName, 50, 50, 400, 300);

  // Give this frame a status line
  frame->CreateStatusLine(1);
  
  // Give it an icon
#ifdef wx_msw
  frame->SetIcon(new wxIcon("vbdbase"));
#endif
#ifdef wx_x
  frame->SetIcon(new wxIcon("vbdbase.xbm"));
#endif

  // File menu 
  wxMenu *file_menu = new wxMenu;
  file_menu->Append(FILE_RUN, "&Run","Execute main application");
  file_menu->Append(FILE_VBDSTATS, "VBD file &Stats", 
		    "Display VBD file statistics");
  file_menu->AppendSeparator();
  file_menu->Append(FILE_QUIT, "E&xit"," Exit this program");

  // Edit menu
  wxMenu *edit_menu = new wxMenu;
  edit_menu->Append(EDIT_CUT, "Cut\tCtrl+X", "Cut text and copy to clipboard");
  edit_menu->Append(EDIT_COPY, "Copy\tCtrl+C", "Copy text to clipboard");
  edit_menu->Append(EDIT_PASTE, "Paste\tCtrl+V", "Paste text from clipboard");
  
  // View menu
  wxMenu *view_menu = new wxMenu;
  view_menu->Append(VIEW_CLEAR, "&Clear Window", "Clear this text window");
  view_menu->Append(VIEW_STATWIN, "View Stats Windows",
		    "Toggel statistics window ON/OFF", TRUE);
  
  // Help menu
  wxMenu *help_menu = new wxMenu;
  help_menu->Append(HELP_ABOUT, "&About", "Info about this program");
  
  // Make all the menu bars  
  menu_bar = new wxMenuBar;
  menu_bar->Append(file_menu, "&File");
  menu_bar->Append(edit_menu, "&Edit");
  menu_bar->Append(view_menu, "&View");
  menu_bar->Append(help_menu, "&Help");
  frame->SetMenuBar(menu_bar);

  // Associate the menu bar with the frame
  frame->SetMenuBar(menu_bar);

  // Create a text window in the main frame
  frame->textWin = new MyTextWindow(frame, 0, 250, 400, 250,
				    wxNATIVE_IMPL);
  frame->textWin->DragAcceptFiles(TRUE);

  // Create a subframe 
  subframe = new wxFrame(NULL, (char *)TSubName, 300, 300, 400, 300);
  int width, height;
  subframe->GetClientSize(&width, &height);

  // Make a text window in the subframe
  frame->StextWin = new MyTextWindow(subframe, 0, 0, width, height,
				     wxNATIVE_IMPL);

  // Show the frames
  frame->Show(TRUE);
  frame->SetStatusText((char *)ProgName);
  subframe->Show(FALSE);
  
  // Return the main frame window
  return frame;
}

MyFrame::MyFrame(wxFrame *frame, char *title, int x, int y, int w, int h):
  wxFrame(frame, title, x, y, w, h)
{
  textWin = StextWin = 0;
}

// Define the behaviour for the frame closing
Bool MyFrame::OnClose(void)
{
  if(textWin) delete textWin;
  if(StextWin) delete StextWin;
  if(subframe) subframe->Close(TRUE);
  Show(FALSE);
  return TRUE;
}

void MyFrame::OnMenuCommand(int id)
// Intercept menu commands
{
  switch (id) {
    case FILE_QUIT:
      if (OnClose()) delete this;
      break;

    case FILE_RUN:
      Run(*textWin);
      break;
      
    case FILE_VBDSTATS:
      menu_bar->Check(VIEW_STATWIN, TRUE);
      VBDFileStats(*StextWin);
      break;

    case EDIT_CUT:
      textWin->Cut();
      break;

    case EDIT_COPY:
      textWin->Copy();
      break;
      
    case EDIT_PASTE:
      textWin->Paste();
      break;

    case VIEW_CLEAR:
      Clear(*textWin);
      break;

    case VIEW_STATWIN:
      if (menu_bar->Checked(id))
	subframe->Show(TRUE);
      else
	subframe->Show(FALSE);
      break;
      
    case HELP_ABOUT:
      char *mesg = StringCat(ProgName, "\nVersion Number ", VerNumber);
      wxMessageBox(mesg, "About testprog", wxOK|wxCENTRE);
      break;
  }
}

void MyTextWindow::OnChar(wxKeyEvent& event)
{
  if(event.keyCode == CONTROL('x')) {
    Cut(); 
    frame->SetStatusText("Cut text and copied to clipboard");
  }

  if(event.keyCode == CONTROL('c')) {
    Copy(); 
    frame->SetStatusText("Copied text from clipboard");
  }

  if(event.keyCode == CONTROL('v')) {
    Paste(); 
    frame->SetStatusText("Pasted text from clipboard");
  }

  wxTextWindow::OnChar(event);  // Process the default behavior
}

void Run(MyTextWindow& textWin)
{
  textWin.Clear();
  int exists;
  
  if(!VBDFile::Exists(FName)) {
    textWin << "Creating new file..." << "\n";
    f->Create(FName);
    exists = 0;
    textWin << "Reference count = " << (int)f->Count() << "\n";
  }
  else {
    textWin << "Opening existing file..." << "\n";
    f->Open(FName); 
    exists = 1;
    textWin << "Reference count = " << (int)f->Count() << "\n";
  }
  
  textWin << "\n";

  FAU addr;
  if(!exists) {
    textWin << "Adding object to VBD file..." << "\n";
    Part part(17, 42.97);   // In-memory copy of part to be stored
    textWin << "Size of object = " << (int)sizeof(Part) << "\n";
    addr = f->Alloc(sizeof(Part)); // Allocate room for part #1
    f->Write(&part, sizeof(Part), addr);
    textWin << "Reference count = " << (int)f->Count() << "\n";
    textWin << "\n";
    VBStats(&textWin, f, addr);
    textWin << "Deleting the object from the VBD file..." << "\n";
    f->Delete(addr);
    textWin << "Reference count = " << (int)f->Count() << "\n";
  }
  else {
    f->Open(FName); // Open() closes first
    textWin << "Reference count = " << (int)f->Count() << "\n";
    Part buf;
    textWin << "Reading the first object from the VBD file..." << "\n";
    addr = f->FindFirstVB();
    f->Read(&buf, sizeof(Part), addr + sizeof(VBHeader));
    textWin << "Reference count = " << (int)f->Count() << "\n";
    textWin << "Part: <" << buf.id << ", " << buf.price << ">" << "\n";
  }
  
  textWin << "\n";

  textWin << "Testing vb find functions..." << "\n";
  FAU vb = f->FindFirstVB();
  FAU obj = f->FindFirstObject(); // First object that has not been deleted
  if(vb) textWin << "First vb address = " << vb << "\n";
  if(obj) textWin << "First Object's address = " << obj << "\n";
  
  vb = f->FindNextVB(vb); 
  obj = f->FindNextObject(vb); // Next object that has not been deleted
  if(vb) textWin << "Next vb address = " << vb << "\n";
  if(obj) textWin << "Next Object's address =  " << obj << "\n";

  textWin << "\n";
  textWin << "Closing file automatically using VBDFile destructor..." << "\n";
}

void Clear(MyTextWindow& textWin)
{
  textWin.Clear();
}

void VBDFileStats(MyTextWindow &textWin)
{
  subframe->Show(TRUE);
  textWin.Clear();

  if(!VBDFile::Exists(FName)) {
    textWin << (char *)FName << " file does not exist.\n";
    textWin << "Select File/Run from main menu to create it.\n" ;
    return;
  }
  else 
    f->Open(FName);

  VBDStats(&textWin, f);
}

char *StringCat(const char *s1, const char *s2, const char *s3)
{
  int len = strlen(s1) + strlen(s2) + strlen(s3);
  char *comp = new char[len+1];
  comp[len+1] = '\0';
  strcpy(comp, s1);
  strcat(comp, s2);
  strcat(comp, s3);
  return comp;
}

char *StringCat(char *s1, char *s2, char *s3)
{
  int len = strlen(s1) + strlen(s2) + strlen(s3);
  char *comp = new char[len+1];
  comp[len+1] = '\0';
  strcpy(comp, s1);
  strcat(comp, s2);
  strcat(comp, s3);
  return comp;
}
// ----------------------------------------------------------- //
// ------------------------------- //
// --------- End of File --------- //
// ------------------------------- //

