
/**************************************************************************

    This file is part of notepad95, a text editor for fvwm95.
    Copyright (C) 1997, Harald Radke.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

**************************************************************************/



#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <X11/Xatom.h>
#include <xclass/OXMsgBox.h>
#include <xclass/OMimeTypes.h>
#include <xclass/OXFileDialog.h>

#include "main.h"
#include "OXDialogs.h"

OMimeTypes *MimeTypeList;  // currently we need this for OXFileDialog

char *filetypes[] = { "All files",      "*",
                      "Document files", "*.doc",
                      "Text files",     "*.txt",
                      NULL,             NULL };

//----------------------------------------------------------------------
  OXClient *clientX;

  search_struct search;

int main(int argc, char **argv)
{
  char mimerc[PATH_MAX];

  clientX = new OXClient;

  search.direction = True;
  search.caseSensitive = False;
  search.buffer = NULL;


  OXAppMainFrame mainWindow(clientX->GetRoot(), 10, 10);

  sprintf(mimerc, "%s/.mime.types", getenv("HOME"));
  MimeTypeList = new OMimeTypes(clientX, mimerc);

  mainWindow.Resize(640, 400);
  mainWindow.MapWindow();
  if (argc > 1)
    mainWindow.LoadFile(argv[1]);

  clientX->Run();

}

OXAppMainFrame::OXAppMainFrame(const OXWindow *p, int w, int h) :
  OXMainFrame(p, w, h) {
  char tmp[BUFSIZ];


  _menuBarLayout = new OLayoutHints(LHINTS_TOP | LHINTS_LEFT | LHINTS_EXPAND_X, 
                                    0, 0, 1, 1);
  _menuBarItemLayout = new OLayoutHints(LHINTS_TOP | LHINTS_LEFT,
                                    0, 4, 0, 0);

  _menuFile = new OXPopupMenu(_client->GetRoot());
  _menuFile->AddEntry(new OHotString("&New"), M_FILE_NEW);
  _menuFile->AddSeparator();
  _menuFile->AddEntry(new OHotString("&Open..."), M_FILE_OPEN);
  _menuFile->AddEntry(new OHotString("&Save"), M_FILE_SAVE);
  _menuFile->AddEntry(new OHotString("Save &as..."), M_FILE_SAVEAS);
  _menuFile->AddSeparator();
  _menuFile->AddEntry(new OHotString("&Print..."), M_FILE_PRINT);
  _menuFile->AddSeparator();
  _menuFile->AddEntry(new OHotString("E&xit"), M_FILE_EXIT);

//  _menuFile->DisableEntry(M_FILE_PRINT);

  _menuEdit = new OXPopupMenu(_client->GetRoot());
  _menuEdit->AddEntry(new OHotString("&Undo"), M_EDIT_UNDO);
  _menuEdit->AddSeparator();
  _menuEdit->AddEntry(new OHotString("&Cut"), M_EDIT_CUT);
  _menuEdit->AddEntry(new OHotString("C&opy"), M_EDIT_COPY);
  _menuEdit->AddEntry(new OHotString("&Paste"), M_EDIT_PASTE);
  _menuEdit->AddEntry(new OHotString("&Delete"), M_EDIT_DELETE);
  _menuEdit->AddSeparator();
  _menuEdit->AddEntry(new OHotString("&Select all"), M_EDIT_SELECTALL);

  _menuEdit->DisableEntry(M_EDIT_CUT);
  _menuEdit->DisableEntry(M_EDIT_COPY);
  _menuEdit->DisableEntry(M_EDIT_DELETE);
  _menuEdit->DisableEntry(M_EDIT_UNDO);
  _menuEdit->DisableEntry(M_EDIT_PASTE);

  _menuSearch = new OXPopupMenu(_client->GetRoot());
  _menuSearch->AddEntry(new OHotString("&Search..."), M_SEARCH_SEARCH);
  _menuSearch->AddEntry(new OHotString("Search &again"), M_SEARCH_AGAIN);
  _menuSearch->AddSeparator();
  _menuSearch->AddEntry(new OHotString("&Goto..."), M_SEARCH_GOTO);


  _menuHelp = new OXPopupMenu(_client->GetRoot());
  _menuHelp->AddEntry(new OHotString("&Contents"), M_HELP_CONTENTS);
  _menuHelp->AddEntry(new OHotString("&About"), M_HELP_ABOUT);

  _menuHelp->DisableEntry(M_HELP_CONTENTS);
  _menuHelp->DisableEntry(M_HELP_ABOUT);

  _menuFile->Associate(this);
  _menuEdit->Associate(this);
  _menuSearch->Associate(this);
  _menuHelp->Associate(this);

  _menuBar = new OXMenuBar(this, 1, 1, HORIZONTAL_FRAME);
  _menuBar->AddPopup(new OHotString("&File"), _menuFile, _menuBarItemLayout);
  _menuBar->AddPopup(new OHotString("&Edit"), _menuEdit, _menuBarItemLayout);
  _menuBar->AddPopup(new OHotString("&Search"), _menuSearch, _menuBarItemLayout);
  _menuBar->AddPopup(new OHotString("&?"), _menuHelp, _menuBarItemLayout);

  AddFrame(_menuBar, _menuBarLayout);
  _te = new OXTextEdit(this, 10, 10, 1);
  AddFrame(_te, new OLayoutHints(LHINTS_EXPAND_X | LHINTS_EXPAND_Y));
  _status = new OXCompositeFrame(this, 60, 20, HORIZONTAL_FRAME | SUNKEN_FRAME);
  AddFrame(_status, new OLayoutHints(LHINTS_BOTTOM | LHINTS_EXPAND_X,
                                     0, 0, 3, 0));
  _lstatus = new OXLabel(_status, new OString(""));
  _status->AddFrame(_lstatus, new OLayoutHints(LHINTS_TOP | LHINTS_LEFT,
                                               2, 0, 1, 1));

  SetWindowName("Notepad");
  SetClassHints("Notepad", "Notepad");
  SetWindowName("noname - Editor");
  filename = new char[strlen("noname")+1];
  strcpy(filename, "noname");
  printer = new char[strlen("lp0")+1];
  strcpy(printer, "lp");
  printProg = new char[strlen("lpr")+1];
  strcpy(printProg, "lpr");
  MapSubwindows();

  timer = new OTimer(this, 100);
 }

OXAppMainFrame::~OXAppMainFrame() {
  delete _status;
  delete _lstatus;
  delete _te;
  delete _menuBarLayout;
  delete _menuBarItemLayout;
  delete _menuFile;
  delete _menuEdit;
  delete _menuSearch;
  delete _menuHelp;
}

void OXAppMainFrame::LoadFile(char* fname= NULL) 
{
  OFileInfo fi;
  char *p, tmp[1024];
  
  fi.filename = NULL;

 if (fname == NULL)
 {
  fi.MimeTypesList = MimeTypeList;
  fi.file_types = filetypes;

  new OXFileDialog(_client->GetRoot(), this, FDLG_OPEN, &fi);

  fname = fi.filename;
 }
 if (fname) 
 {
  if (!_te->LoadFile(fname)) 
  {
    sprintf (tmp, "Error opening file \"%s\"", fname);
    new OXMsgBox(_client->GetRoot(), this, new OString("Editor"),
                 new OString(tmp), MB_ICONSTOP, ID_OK);
 
   if (fi.filename != NULL)   
    delete fi.filename;
  }
  else
  {
   if ((p = strrchr(fname, '/')) == NULL) 
   {
    p = fname;
   } 
   else 
   {   
    ++p;
   }
   sprintf(tmp, "%s: %d lines read.", p, _te->ReturnLineCount());
   _lstatus->SetText(new OString(tmp));
   _status->Layout();
   delete filename;
   filename= new char[strlen(p)+1];
   filename= strcpy(filename, p);
   SetWindowName(filename);
  }
 }
_te->Layout();
}

void OXAppMainFrame::SaveFile(char *filename) {
char *p, tmp[1024];

  if (!_te->SaveFile(filename)) {
    sprintf (tmp, "Error saving file \"%s\"", filename);
    new OXMsgBox(_client->GetRoot(), this, new OString("Editor"),
                 new OString(tmp), MB_ICONSTOP, ID_OK);
    return;
  }

  if ((p = strrchr(filename, '/')) == NULL) {
    p = filename;
  } else {
    ++p;
  }
  sprintf(tmp, "%s: %d lines wrote.", p, _te->ReturnLineCount());
  _lstatus->SetText(new OString(tmp));
  _status->Layout();

     SetWindowName(filename);

}

void OXAppMainFrame::SaveFileAs() {
OFileInfo fi;
char *p, tmp[1024];

 fi.MimeTypesList = MimeTypeList;
 fi.file_types = filetypes;
 new OXFileDialog(_client->GetRoot(), this, FDLG_SAVE, &fi);
 if (fi.filename) 
 {
  SaveFile(fi.filename);
  delete filename;
  filename = new char[strlen(fi.filename+1)];
  strcpy(filename, fi.filename); 
 }
}


int OXAppMainFrame::IsSaved()
{
 char tmp[1024];
 sprintf(tmp,"File has changed ! Save ?");
 int ret;
 if (_te->IsSaved() == True)
  return ID_NO;
 else 
 {
  new OXMsgBox(_client->GetRoot(), this, new OString("Editor"),
                 new OString(tmp), MB_ICONEXCLAMATION, 
               ID_YES | ID_NO | ID_CANCEL,
                 &ret );

  return ret; 
 }
}

void OXAppMainFrame::Print()
{
 OText *text;
 OLongPosition pos;
 pos.x = pos.y = 0;
 int ret;
 long count;
 char tmp[1024];
 char *textBuffer;
 new OXPrintBox(clientX->GetRoot(),this, 400, 150,&printer,&printProg, &ret);
 if (ret == True)
 {
  text = _te->GetText();
  sprintf(tmp, "%s -P%s",printProg, printer); //, filename);
  FILE *p = popen(tmp, "w");
  while(pos.y < text->RowCount())
  {
   count = text->GetLineLength(pos.y);
   textBuffer = new char[count+1];
   textBuffer = text->GetLine(pos,count);
   textBuffer[count] = '\n';
   fwrite(textBuffer, sizeof(char), count+1, p);
   delete textBuffer;
   pos.y++;
  }
  pclose(p);
  sprintf(tmp, "printed: %s", filename);
  _lstatus->SetText(new OString(tmp));
  _status->Layout();

 }      
}

int OXAppMainFrame::HandleClientMessage(XClientMessageEvent *event)
{
 OXCompositeFrame::HandleClientMessage(event);
 
  if ((event->format == 32) && (event->data.l[0] == WM_DELETE_WINDOW))
  {
   switch (IsSaved()) {
      case ID_CANCEL:
         break;
      case ID_YES:
         if (strcmp(filename, "noname") == 0)
            SaveFileAs();
          else
            SaveFile(filename);
      case ID_NO: 
       CloseWindow(); 
    } 
  }
  return True;
}

int OXAppMainFrame::HandleFocusChange(XFocusChangeEvent *event)
{                       
                /* Set the Input Focus to the Text Entry Widget */ 
        if ((event->mode == NotifyNormal) && (event->detail != NotifyPointer) &&
            (event->type == FocusIn))
        {
         XSetInputFocus(GetDisplay(), _te->GetId(), 
                         RevertToParent, CurrentTime);
                
        }
        return True;    
}

void OXAppMainFrame::Clear()
{
 _te->Clear();
 delete filename;
 filename = new char[strlen("noname")+1];
 strcpy(filename, "noname");
 SetWindowName("noname - Editor");
  _lstatus->SetText(new OString("New File"));
  _status->Layout();

}

void OXAppMainFrame::Search(int ret)
{
 char tmp[1024];
  if ((ret == False) || (search.buffer == NULL))
   new OXSearchBox(clientX->GetRoot(),this, 400, 150, &search, &ret);
  if (ret == True)  
   if (!(_te->Search(search.buffer, search.direction, search.caseSensitive)))
   {
    sprintf (tmp, "Couldn't find \"%s\" ", search.buffer);
    new OXMsgBox(_client->GetRoot(), this, new OString("Editor"),
    new OString(tmp), MB_ICONEXCLAMATION, ID_OK);
   }
  else
  {
   _menuEdit->EnableEntry(M_EDIT_CUT);
   _menuEdit->EnableEntry(M_EDIT_COPY);
   _menuEdit->EnableEntry(M_EDIT_DELETE);
  }
 }

void OXAppMainFrame::Goto()
{
 long ret;
 char tmp[1024];
   new OXGotoBox(clientX->GetRoot(),this, 400, 150, &ret);
  if (ret > -1)
   if (!(_te->Goto(ret)))
   {
    sprintf (tmp, "No such line !");
    new OXMsgBox(_client->GetRoot(), this, new OString("Editor"),
    new OString(tmp), MB_ICONEXCLAMATION, ID_OK);
   }
}

int OXAppMainFrame::HandleTimer (OTimer *t)
{
 if (t != timer)
  return True;
 if (XGetSelectionOwner(GetDisplay(), XA_PRIMARY) == None)
  _menuEdit->DisableEntry(M_EDIT_PASTE);
 else
  _menuEdit->EnableEntry(M_EDIT_PASTE); 
 delete timer;
 timer = new OTimer(this, 100);
 return True;
}

int OXAppMainFrame::ProcessMessage(long msg, long parm1, long parm2) {
  int ret = False;
  char tmp[1024];
  OLongPosition pos;
  switch (GET_MSG(msg)) {

    case XC_VIEW:
      switch(GET_SUBMSG(msg)) {
       
        case VIEW_DATACHANGE:
         pos = _te->GetCurrentPos();
          sprintf(tmp,"Line: %d Column: %d", pos.y+1, pos.x+1 );
         _lstatus->SetText(new OString(tmp));
         _status->Layout();

         break;

        case VIEW_ISMARKED:
          if (parm2 == True)
          {
           _menuEdit->EnableEntry(M_EDIT_CUT);
           _menuEdit->EnableEntry(M_EDIT_COPY);
           _menuEdit->EnableEntry(M_EDIT_DELETE);         
          }
          else
          {
           _menuEdit->DisableEntry(M_EDIT_CUT);   
           _menuEdit->DisableEntry(M_EDIT_COPY);  
           _menuEdit->DisableEntry(M_EDIT_DELETE);
          }
         break;

        case VIEW_F3:
         Search(True);
         break;
       
        case VIEW_CLICK3:
           int x_root = parm2 & 0xFFFF;
           int y_root = (parm2 >> 16) & 0xFFFF;
           _menuEdit->PlaceMenu(x_root, y_root, True, True);
         break;
      }
      break;

    case XC_COMMAND:    // buttons and menu commands
      switch(GET_SUBMSG(msg)) {

        case CM_MENUSELECT:
          break;

        case CM_MENU:
          switch(parm1) {

            case M_FILE_NEW:
                switch (IsSaved()) {
                 case ID_CANCEL:
                  break;
                 case ID_YES:
                  if (strcmp(filename, "noname") == 0)
                   SaveFileAs();
                  else
                   SaveFile(filename);
                 case ID_NO:
                  Clear();
              }
              break;

            case M_FILE_OPEN:
                switch (IsSaved()) {
                 case ID_CANCEL:
                  break;
                 case ID_YES:
                  if (strcmp(filename, "noname") == 0)
                   SaveFileAs();
                  else
                   SaveFile(filename);
                 case ID_NO:
                  LoadFile();
                   break;
              }
              break;

            case M_FILE_SAVE:
               if (strcmp(filename, "noname") == 0)
                SaveFileAs();
               else
                SaveFile(filename); 
               break;

            case M_FILE_SAVEAS:
                SaveFileAs();
               break;   

            case M_FILE_EXIT:
                switch (IsSaved()) {
                 case ID_CANCEL:
                  break;   
                 case ID_YES:
                  if (strcmp(filename, "noname") == 0)
                   SaveFileAs();
                  else   
                   SaveFile(filename);
                 case ID_NO:
                 delete _client;
                 exit(0);
              }  
              break;

            case M_FILE_PRINT:
               Print();
               break;


            case M_EDIT_CUT:
                if (_te->Cut() == True)
                  _menuEdit->EnableEntry(M_EDIT_PASTE);
                break; 
            case M_EDIT_COPY:
                if (_te->Copy() == True)
                  _menuEdit->EnableEntry(M_EDIT_PASTE);
                break;
            case M_EDIT_PASTE:
                _te->Paste();
                break;
            case M_EDIT_DELETE:
                _te->Delete();            
                break;
            case M_EDIT_SELECTALL:
                
                if (_te->SelectAll()== True)
                {
                 _menuEdit->EnableEntry(M_EDIT_CUT);
                 _menuEdit->EnableEntry(M_EDIT_COPY);
                 _menuEdit->EnableEntry(M_EDIT_DELETE);
                }
                break;

            case M_SEARCH_AGAIN:
              Search(True);
              break;
            case M_SEARCH_SEARCH:
              Search(False);
              break;
            case M_SEARCH_GOTO:
              Goto();             
            default:
             break;

          } // switch(parm1)
          break;

        default:
          break;

      } // switch(GET_SUBMSG(msg))
      break;

    default:
      break;

  } // switch(GET_MSG(msg))

  return True;
}
