#include "sample1.h"

#include XColor_i
#include XFileDialog_i
#include XString_i
#include XMessageBox_i
#include XDragEvent_i
#include XDragHandler_i
#include XDragItem_i
#include XFile_i
#include XFrame_i
#include XToolBar_i
#include XPushButton_i

#include <stdlib.h>
#include <string.h>
/* This is the code for sample1, a simple text-editor */


class MyMLE: public XMultiLineEdit
{
      MyAppWindow * owner;
   public:
      MyMLE( MyAppWindow * w, XRect * r): XMultiLineEdit( w, r, MY_MLE, MLE_HORZSCROLL | MLE_VERTSCROLL | WIN_VISIBLE) { owner = w; }
      void DoControl(XControlEvent*);
};

/* we want to accept files wich are dropped on our window, so we need */
/* a handler wich can handle this messages for drag/drop. we need to derive */
/* a class from class XDragHandler and overwrite the method HandleEvent */
/* and the constructor */
class MyDragHandler: public XDragHandler
{
   public:
      MyDragHandler( XWindow * w): XDragHandler( w ) { ;}
      void HandleEvent(XDragEvent*);
};


/* here the method HandleEvent is overridden, so we can handle drag/drop events*/
void MyDragHandler :: HandleEvent ( XDragEvent * event)
{
   switch( event->GetEventID())
      {
         /* the mousepointer is over the MLE holding one or more objects */
         case DRG_DRAGOVER:
            {
               SHORT i;
               XDragItem item;
               /* ask for every object the type and format */
               for(i=0; i < event->QueryDragItemCount(); i ++)
                 {
                    event->QueryDragItem( &item, i);
                    if(item.VerifyItemType( DRG_M_FILE ) == FALSE)
                       {
                          /* no textfile, we will not accept these objects */
                          event->SetAcceptMode( DRG_NEVERDROP);
                          return;
                       }
                 }
               event->SetAcceptMode( DRG_DROP);       //ok, can be dropped
               event->SetOperation( DO_COPY);         //we will work with a copy
             }
             return;
         /* one or more object are dropped, because weīve tested the format (see above) */
         /* we donīt have to test it here again, the object will be files */
         case DRG_DROP:
            {
               XDragItem item;
               XString name, container;
               SHORT i;

               /* query for every object the information we need */
               for(i=0; i < event->QueryDragItemCount(); i++)
                  {
                     event->QueryDragItem( &item, i);
                     item.Accept();                        //let the sender know that we accept the object

                     item.QueryName( &name);               //query the filename
                     item.QueryContainerName( &container); //query the directory
                     container+= name;                     //make a complete path

                     /* because the framecontrol of the framewindow is the new */
                     /* parent of the window, its a little bit complicated to get */
                     /* a pointer of the framewindow (our AppWindow) */

                     XFrame * f= (XFrame*) GetWindow()->QueryWindow( WIN_PARENT);
                     MyAppWindow * appWin = (MyAppWindow*) f->QueryWindow( WIN_PARENT);
                     appWin->LoadFile( container );        //load the file
                  }
            }
            return;
      }
}


/* here the mainwindow will be created */
MyAppWindow :: MyAppWindow( XResourceLibrary * resLib, XResource * r ): XFrameWindow( r, "Sample1", XFrameWindow::defaultStyle | FRM_ICON)
{
   XRect rec( 100, 100, 500, 350);
   SetSize( &rec );
   /* we create a MLE-control; because the MLE is used as client we dont want a border */
   /* and donīt use the defaults (see <xmle.h>) */
   XRect rec2;
   mle = new MyMLE( this, &rec2 );

   /*set backgroundcolor to white*/
   XColor col( COL_WHITE);
   mle->SetBackgroundColor( &col );

   /* the MLE is used as a new client-area, so sizing and moving is automaticaly done */
   /* attention: MyAppWindow is no longer parent of the mle!!! if you ask the mle for */
   /* its parent youīll get a pointer to the framwindows frame-control and you must ask */
   /* the frame-control for its parent to get a pointer to the framewindow! */
   SetClient( mle );

   /* we want a menubar, it is defined in the resources of the exe-file with the id IDM_MAIN */
   XResource rs( IDM_MAIN, resLib);
   menu = new XMenuBar( this, &rs);

   /* we put a string into the MLE */
   mle->SetText( "this is our MLE where you can edit your text...");

   /*we generate our drag-handler and attach it to the MLE */
   MyDragHandler * myDragHandler = new MyDragHandler( mle );

   /* setup our needed flags */
   saved = TRUE;
   loaded = FALSE;

   /*the mle get the focus */
   mle->SetFocus();
}


/* this is the overridden method DoCmmand from XFrameWindow. all commands */
/* from the menu (or toolbars in later samples) will be placed here. */
void MyAppWindow :: DoCommand( LONG command )
{
   switch ( command )
      {
         case IDM_OPEN:
           {
               /* display the filedialog defined by the system */
               /* set the file-suffix and title of the dialog */
               XFileDialog fileDlg(this, "*.TXT", NULL, NULL, FD_OPEN | FD_CENTER | FD_MULTIPLESEL);

               /* the user selected a file */
               if( fileDlg.GetCommand() == USER_OK)
                 {
                    XString fileName;
                    SHORT i, files = fileDlg.QueryFileCount();  //how much files are selected?
                    for(i=0; i < files; i++)
                       {
                          fileDlg.GetFileName( &fileName, i );  //get filename and path for every file
                          LoadFile( fileName);                  //load the file
                       }
                 }
            }
            break;
         case IDM_CLOSE:
            /* the user selected close, so we try to close the window */
            /* the (overridden) method QueryForClose is called automaticaly (see below)*/
            delete this;
            return;
         case IDM_SAVE:
            SaveFile();
            return;
       }
}


/* when contents of window-controls change, we will get an event of the class */
/* XControlEvent where we can ask for information about the event and the sending */
/* window. in later examples the other types of events  will be shown */
void MyMLE :: DoControl( XControlEvent * event )
{
   //ask for the id of the sending window and the type of event
   if( event->GetEventID() == WIN_CHANGED )
      {
         //sender is the MLE, event is that the text will be changed
         if( owner->saved == TRUE)
            {
               XString s;
               owner->GetText( &s );
               s += " - changed";
               owner->SetText( s );
               owner->saved = FALSE;
            }
       }
}


/* this is an overridden method of XFrameWindow, it is called if the user try to close the */
/* framewindow with the close-button or with ALT-F4. Return TRUE if the window can be closed, */
/* otherwise return FALSE */
BOOL MyAppWindow :: QueryForClose( void )
{
   if(saved == FALSE)    //text changed
      {
         XMessageBox msb( "Text changed - discard?", "Close Window", MB_YESNO|MB_WARNING|MB_MOVEABLE);
         if( msb.GetCommand() == MBID_NO)
            return FALSE;  //donīt close the window
      }
  return TRUE;
}


/* load a file */
BOOL MyAppWindow :: LoadFile ( char * p)
{
   // is there already a file loaded or has the user entered some text?
   if(loaded == FALSE && saved == TRUE)
      {
         //no, we load the file in the window of the current thread
         XFile loadfile;

         /* now open the file, fail if given filename is not existing */
         /* open the file for read-access, dont allow any other programm to use the file while it is open*/
         if( loadfile.Open( p, 0, XFILE_FAIL_IF_NEW | XFILE_OPEN_EXISTING, XFILE_SHARE_DENYNONE | XFILE_READONLY ) == 0)
           {
              XString s;
              //seek to the end
              loadfile.Seek( 0, XFILE_END);
              //how long is the file?
              LONG size = loadfile.QueryPointerPos()+1;
              //seek to the beginning
              loadfile.Seek( 0, XFILE_BEGIN);
              //allocated memory in the XString and read the complete file
              loadfile.Read ( s.GetBuffer( (ULONG)size), size);
              //set the XString content to the mle
              mle->SetText( s );
              //dontīforget to close the file
              loadfile.Close();
              loaded = TRUE;
              path = p;
              mle->SetFocus();
              GetText( &s );
              s+= " - ";
              s+= p;
              SetText( s );
              return TRUE;
            }
         else
            {
               XMessageBox( p, "couldnīt open File!", MB_OK|MB_ERROR);
               return FALSE;
            }
      }
   else
     {
         //there is a file loaded, or the user has entered some text, so
         // we create a new thread which will load the file
         MyThread * th = new MyThread( p);
         th->Run();
         return TRUE;
     }
}


BOOL MyAppWindow :: SaveFile( void )
{
   XFile savefile;
   XString s;
   ULONG size = mle->GetText( &s );

   /* now open the file, create a new one if the given filename is not existing, otherwise overwrite */
   /* it. open the file for write-access, dont allow any other programm to use the file while it is open*/
   if( savefile.Open( path, size, XFILE_CREATE_IF_NEW | XFILE_REPLACE_EXISTING, XFILE_SHARE_DENYNONE | XFILE_WRITEONLY) == 0)
      {
         /* set the file-cursor to the beginning of the file */
         savefile.Seek( 0, FILE_BEGIN);


         /* xfile needs a void-pointer to the data and the size of the datablock, it returns */
         /* the size of written bytes*/
         savefile.Write (( char*) s, size);

         /* close the file */
         savefile.Close();
         saved = TRUE;
         return TRUE;
      }
   else
      {
         XMessageBox( "could not open file", "error", MB_OK| MB_ERROR);
         return FALSE;
      }
}


/* this is the overriden method Init() from XThread. here we can setup */
/* the data for every thread and generate its objects*/
void MyThread :: Init(void)
{
   resLib = new XResourceLibrary( this );  //create a resourcelibary out of the exe-file
   XResource res( IDM_MAIN, resLib);
   appWindow = new MyAppWindow( resLib, &res );  //create new framewindow (see above)

   if(iniFile)                             //a file was specified in the constructur
      appWindow->LoadFile(iniFile);        // so we load the file
}


/* our thread-constructor, p can be a pointer to a filename of a file to load */
MyThread :: MyThread( char * p)
{
  if( p )
     {
        iniFile = (char*) malloc( strlen(p) + 1);
        strcpy( iniFile, p);
     }
  else
     p = NULL;
}


int main ( int argc, void ** argv)
{
  if( argc > 1)  //there were filenames in the commandline
     {
        SHORT i;
        for(i=1; i < argc; i++)
           {
               MyThread * thread = new MyThread( (char*) argv[i] ); //start for every file a new thread
               thread->Run();                                       //let the thread run
           }
     }
  else
     {
        MyThread * thread = new MyThread();      //create a thread
        thread->Run();                           //let the thread run
     }

  XThread :: RunThreads();                       //let all threads work
}
