/* Copyright (C) 1996,1997 Robert H”hne, see COPYING.RH for details */
/* This file is part of RHIDE. */
#define Uses_TEvent
#define Uses_TStreamableClass
#define Uses_MsgBox
#define Uses_TKeys
#define Uses_TIDEEditWindow
#define Uses_TFileDialog
#define Uses_TProgram
#define Uses_TDeskTop
#define Uses_MsgBox
#define Uses_editCommands
#define Uses_TIndicator

#define Uses_TIDEFileEditor
#define Uses_ideCommands
#define Uses_ideFunctions
#include <libide.h>
#include <utime.h>
#include <sys/stat.h>
#include <sys/timeb.h>
#include <stdio.h>
#include <unistd.h>

#define Uses_tvutilFunctions
#include <libtvuti.h>

TIDEFileEditor::~TIDEFileEditor()
{
  string_free(bname);
}

int TIDEFileEditor::use_syntax = 1;

int (*TIDEFileEditor::externalFormatLine)(TCEditor *,void *, unsigned, int,
                                   unsigned short, unsigned, unsigned short,
                                   unsigned ) = NULL;

void TIDEFileEditor::formatLine( void *DrawBuf,
			  unsigned LinePtr,
			  int Width,
			  unsigned short Colors,
                          unsigned lineLen,
                          unsigned short Attr,
                          unsigned lineNo // needed for RHIDE
			)
{
  if (externalFormatLine &&
      externalFormatLine(this,DrawBuf,LinePtr,Width,Colors,lineLen,
                         Attr,lineNo)) return;
  FormatLinePtr(DrawBuf,LinePtr,Width,Colors,lineLen,Attr,lineNo);
}


void TIDEFileEditor::setFormatLine()
{
  char *ext,*dir;
  shlState ftype;
  if (bname) string_free(bname);
  split_fname(fileName,dir,bname,ext);
  string_cat(bname,ext);
  string_free(dir);
  if (!use_syntax)
    ftype = shlNoSyntax;
  else
  switch (get_file_type(ext))
  {
    case FILE_C_SOURCE:
    case FILE_C_SOURCE_I:
    case FILE_CC_SOURCE:
    case FILE_CC_SOURCE_II:
    case FILE_HEADER:
      ftype = shlCSyntax;
      break;
    case FILE_PASCAL_SOURCE:
      ftype = shlPascalSyntax;
      break;
    default:
      ftype = shlNoSyntax;
      break;
  }
  string_free(ext);
//  if (ftype != SyntaxHL)
  {
    SetHighlightTo(ftype);
    FormatLinePtr = formatLinePtr;
    formatLinePtr = (void (TCEditor::*)
                    (void *, unsigned, int, unsigned short, unsigned,
                     unsigned short, unsigned ))&formatLine;
    update(ufView);
  }
//  else
//  {
//    formatLinePtr = (void (TCEditor::*)
//                    (void *, unsigned, int, unsigned short, unsigned,
//                     unsigned short, unsigned ))&formatLine;
//  }
}

TIDEFileEditor::TIDEFileEditor(const TRect & rect,TScrollBar *ahscrollbar,
				TScrollBar *avscrollbar,TIndicator *aindicator,
				const char *aFileName) :
  TCFileEditor(rect,ahscrollbar,avscrollbar,aindicator,aFileName)
{
  struct stat st;
  FormatLinePtr=formatLinePtr; // is set by TCEditor::TCEditor
  if( aFileName == 0 )
      fileName[0] = EOS;
  else
  {
    strcpy( fileName, aFileName );
    if( isValid )
      isValid = loadFile();
  }
  if (*fileName && stat(fileName,&st) == 0)
  {
    edittime = st.st_mtime;
#if 0
    if (!(st.st_mode & S_IWUSR))
#else
    if (access(fileName,W_OK) != 0)
#endif
    {
      messageBox(mfWarning|mfOKButton,
        _("Warning: %s is write protected"),fileName);
    }
  }
  else
  {
    struct timeb tb;
    ftime(&tb);
#ifdef __DJGPP__
    edittime = tb.time & ~(1UL); //round up to a 2 sec boundary
#endif
  }
  helpCtx = hcIDEFileEditor;
  BaseName(fileName,bname);
  setFormatLine();
}

TStreamable *TIDEFileEditor::build()
{
  return new TIDEFileEditor(streamableInit);
}

TIDEFileEditor::TIDEFileEditor(StreamableInit) :
  TCFileEditor(streamableInit),
  bname(NULL)
{
}

void TIDEFileEditor::handleEvent(TEvent & event)
{
  int savecmd = 0;
  int save_as = 0;
  Boolean old_modified = modified;

  if (event.what == evCommand &&
      event.message.command == cmSave &&
      modified == False)
  {
    clearEvent(event);
    return;
  }
  if (event.what == evCommand &&
      (event.message.command == cmSave ||
       event.message.command == cmSaveAs))
  {
    savecmd = 1;
    if (event.message.command == cmSaveAs || !*fileName)
      save_as = 1;
  }
  else
    savecmd = 0;
//  lock();
  if (!savecmd) modified = False; // when not saving, check for new modification
  TCFileEditor::handleEvent(event);
  if (event.what == evCommand) // the event was not handled
  {
    if (!savecmd)
    {
      if (old_modified != modified)
      {
        modified = old_modified;
        indicator->setValue(curPos, modified);
      }
    }
    return;
  }
  switch (event.what)
  {
    case evBroadcast:
      switch (event.message.command)
      {
        case cmTurnSyntaxOff:
          use_syntax = 0;
          setFormatLine();
          break; // do not clear the event
        case cmTurnSyntaxOn:
          use_syntax = 1;
          setFormatLine();
          break; // do not clear the event
        default:
          break;
      }
      break;
    default:
      break;
  }
  if (savecmd) setFormatLine(); // may be the name has changed
  if (savecmd && modified == False)  // saving was successfull
  {
    struct utimbuf ut;
    ut.modtime = edittime;
    utime(fileName,&ut);
    if (save_as) // send a message, that the filename has changed
      message(TProgram::application,evBroadcast,cmEditorFilenameChanged,this);
    // clear all undo information ???
  }
  if (modified == True && !savecmd) // it was a real modification
  {
    struct timeb tb;
    ftime(&tb);
    edittime = tb.time & ~(1UL); //round up to a 2 sec boundary
    message(TProgram::application,evBroadcast,cmEditorModified,(void *)edittime);
  }
  if (!savecmd && old_modified == True && modified == False)
  {
    modified = old_modified;
    indicator->setValue(curPos, modified);
  }
  if (event.what == evBroadcast && event.message.command == cmRedraw)
  {
    if (exposed()) update(ufView);
  }
//  unlock();
}

Boolean TIDEFileEditor::valid( ushort command )
{
    Boolean retval;
    struct utimbuf ut;
    if( command == cmValid )
        return isValid;
    else
        {
        if( modified == True )
            {
            int d;
            if( *fileName == EOS )
                d = edSaveUntitled;
            else
                d = edSaveModify;

            switch( editorDialog( d, fileName ) )
                {
                case cmYes:
                    retval = save();
                    if (retval == True)
                    {
                      ut.modtime = edittime;
                      utime(fileName,&ut);
                    }
                    return retval;
                case cmNo:
                    modified = False;
                    return True;
                case cmCancel:
                    return False;
                }
            }
        }
    return True;
}

void goto_line(TCFileEditor *editor,int line)
{
  editor->lock();
  editor->MoveCursorTo(0,line-1);
  editor->trackCursor(True);
  editor->selStartF = (uint32)(editor->curLinePtr-editor->buffer);
  editor->selEndF   = editor->nextLine(editor->selStartF);
#if 0
  editor->update(ufView | ufFound);
#else
  editor->update(ufUpdate | ufFound | ufLine);
#endif
  editor->unlock();
}

static ushort TIDEFileEditor_Version = 0;

void TIDEFileEditor::write( opstream& os )
{
    TCFileEditor::write( os );
    os << TIDEFileEditor_Version;
}

void * TIDEFileEditor::read(ipstream & is)
{
  struct stat st;
  ushort version;
  TCFileEditor::read( is );
  is >> version;
  if (stat(fileName,&st) == 0)
  {
    edittime = st.st_mtime;
#if 0
    if (!(st.st_mode & S_IWUSR))
#else
    if (access(fileName,W_OK) != 0)
#endif
    {
      messageBox(mfWarning|mfOKButton,
        _("Warning: %s is write protected"),fileName);
    }
  }
  else
  {
    struct timeb tb;
    ftime(&tb);
    edittime = tb.time & ~(1UL); //round up to a 2 sec boundary
  }
  BaseName(fileName,bname);
  FormatLinePtr=formatLinePtr; // is set by TCFileEditor::read
  setFormatLine();
  return this;
}

