// ------------------------------- //
// -------- Start of File -------- //
// ------------------------------- //
// ----------------------------------------------------------- // 
// C++ Source Code File Name: testprog.cpp 
// C++ Compiler Used: MSVC 4.2, HP CPP 10.24 
// Produced By: Doug Gaer 
// File Creation Date: 12/16/1997 
// Date Last Modified: 05/26/1998
// Copyright (c) 1997 Douglas M. Gaer
// ----------------------------------------------------------- // 
// ------------- Program Description and Details ------------- // 
// ----------------------------------------------------------- // 
/*
This is a test program for the RefCount class built using the
wxWindows GUI Library version 1.68.

The VBD C++ classes are copyright (c) 1997, by Douglas M. Gaer.
All those who put this code or its derivatives in a commercial
product MUST mention this copyright in their documentation for
users of the products in which this code or its derivative
classes are used. Otherwise, you have the freedom to redistribute
verbatim copies of this source code, adapt it to your specific
needs, or improve the code and release your improvements to the
public provided that the modified files carry prominent notices
stating that you changed the files and the date of any change.

THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
CORRECTION.
*/
// ----------------------------------------------------------- // 
#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

#include <string.h>
#include "refcount.hpp"

// Reference counted (S)tring class
class refString :  public CountedObject
{ 
public:
  refString() { str = 0; }
  refString(char *s) { Store(s); }
  refString(int sz);
  ~refString() { delete str; }    
  refString(const refString &s) { Store(s.str); }

  refString &operator=(const refString &s) {
    if(this != &s) {
      str = 0;
      Store(s.str);
    }
    return *this;
  }

public:
  void Store(char *s);
  char *c_str() const { return str; } 

public:
  friend int operator==(const refString &a, const refString &b) {
    return strcmp(a.str, b.str) == 0;
  }

  friend int operator<(const refString &a, const refString &b) {
    return strcmp(a.str, b.str) < 0;
  }

  friend int operator>(const refString &a, const refString &b) {
    return strcmp(a.str, b.str) > 0;
  }

  friend int operator!=(const refString &a, const refString &b) {
    return strcmp(a.str, b.str) != 0;
  }
  
private:
  char *str;
};

refString::refString(int sz)
{
  str = new char[sz+1];
  str[sz] = '\0';
}

void refString::Store(char *s)
{
  size_t len = strlen(s);
  str = new char[len+1];
  str[len] = '\0';
  strcpy(str, s);
}

// Reference counted (S)tring class pointer
typedef RefCount<refString> refStringPtr;

// Define a new frame
class MyTextWindow;

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

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

// 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]); }
};

// 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();

  // Override OnActivate to allow LoadAccelerators call to work
  void OnActivate(Bool) { }

public:
  MyTextWindow *textWin;
};

// Declare a frame
MyFrame *frame = 0;
wxMenuBar *menu_bar = 0;

// Identification for the all main menu functions
enum {
  FILE_QUIT = 1,
  FILE_RUN,
  EDIT_CUT,   // Must match definition in .rc file for accelerated key
  EDIT_COPY,  // Must match definition in .rc file for accelerated key
  EDIT_PASTE, // Must match definition in .rc file for accelerated key
  VIEW_CLEAR,
  HELP_ABOUT
};

// Program name displayed in main frame window
const char *ProgName = "RefCount Class Test Program";

// 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->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");
  
  // 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);

  frame->textWin = new MyTextWindow(frame, 0, 250, 400, 250,
					wxNATIVE_IMPL);
  frame->textWin->DragAcceptFiles(TRUE);

  // Show the frame
  frame->Show(TRUE);
  frame->SetStatusText((char *)ProgName);

  // Load the menu accelerators mapped out in the .rc file
  frame->LoadAccelerators("menus_accel") ;
 
  // 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 = 0;
}

// Define the behaviour for the frame closing
Bool MyFrame::OnClose(void)
{
  if(textWin) delete textWin;
  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 EDIT_CUT:
      textWin->Cut();
      break;
    case EDIT_COPY:
      textWin->Copy();
      break;
      
    case EDIT_PASTE:
      textWin->Paste();
      break;

    case VIEW_CLEAR:
      Clear(*textWin);
      break;


    case HELP_ABOUT:
      wxMessageBox((char *)ProgName, "About", wxOK|wxCENTRE);
      break;
  }
}

void Run(MyTextWindow& textWin)
{
  textWin.Clear();
  textWin << "Dnamically creating refString object pointers on the heap..."
	  << "\n";
  refStringPtr s1(new refString);
  refStringPtr s2(new refString);
  
  textWin << "Object pointer s1 reference count = "
	  << (int)s1->Count() << "\n";
  textWin << "Object pointer s2 reference count = "
	  << (int)s2->Count() << "\n";
  
  // Call to overloaded ! operator in RefCount class
  if(!s1) textWin << "Cannot allocate memory" << "\n";
  
  // Call to overloaded -> operator in RefCount class
  s1->Store("This is refString object's data");

  // Call to overloaded * operator in RefCount class
  textWin << s1->c_str() << "\n"; 
  
  textWin << "\n";

  textWin << "Assigning reference counted objects pointers s2 = s1..." << "\n";
  s2 = s1;
  textWin << s2->c_str() << "\n";
  textWin << "Object s1 reference count = "
	  << (int)s1->Count() << "\n";
  textWin << "Object s2 reference count = "
	  << (int)s2->Count() << "\n";

  textWin << "\n";
  
  textWin << "Copying reference counted objects pointers s3(s1)..." << "\n";
  refStringPtr s3(s1);
  textWin << s3->c_str() << "\n";
  textWin << "Object pointer s1 reference count = "
	  << (int)s1->Count()
	  << "\n";
  textWin << "Object pointer s2 reference count = "
	  << (int)s2->Count()
	  << "\n";
  textWin << "Object pointer s3 reference count = "
	  << (int)s3->Count()
	  << "\n";
  
  textWin << "\n";
  
  textWin << "Testing overloaded * operator in RefCount class..." << "\n";
  textWin << "Creating refString object str..." << "\n";
  refString str = *s1;
  textWin << str.c_str() << "\n";

  textWin << "\n";
  
  textWin << "Releasing object poiner s1 reference count..." << "\n";
  s1->Release();
  textWin << "Object pointer s1 reference count = "
	  << (int)s1->Count()  << "\n";
  textWin << "Object pointer s2 reference count = "
	  << (int)s2->Count() << "\n";
  textWin << "Object pointer s3 reference count = "
	  << (int)s3->Count() << "\n";
  
  textWin << "\n";
  textWin << "Automatic destructor call to destroy object str..." << "\n";
}

void Clear(MyTextWindow& textWin)
{
  textWin.Clear();
}
// ----------------------------------------------------------- //
// ------------------------------- //
// --------- End of File --------- //
// ------------------------------- //

