/*

  This is a part of the Project Frontier's Source code.

  Copyright (C) 1994-1998 Francis Gastellu
                      aka Lone Runner/Aegis

  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#define Uses_TRect
#define Uses_TMenuBar
#define Uses_TSubMenu
#define Uses_TMenuItem
#define Uses_TKeys
#define Uses_fpstream
#define Uses_TView
#define Uses_TPalette
#define Uses_MsgBox
#define Uses_TFileDialog
#define Uses_TApplication
#define Uses_TDeskTop
#define Uses_TStaticText
#define Uses_TDialog
#define Uses_TEventQueue
#define Uses_TEditor
#define Uses_TStatusLine
#define Uses_TStatusDef
#define Uses_TStatusItem
#define Uses_TCheckBoxes
#define Uses_TSItem
#define Uses_TButton
#define Uses_TLabel
#define Uses_TInputLine

#include <tv.h>

#include "tvcmds.h"
#include "gadgets.h"
#include "fileview.h"
#include <alloc.h>
#include <stdlib.h>

#include "pp.h"
#include "pphlp.h"

#include <strstrea.h>

#include "ctxt.h"

#if !defined( __TAGGER_H )
#include "tagger.h"
#endif  // __TAGGER_H

#if !defined( __MESSAGE_H )
#include "message.h"
#endif  // __MESSAGE_H

struct DialogData
{
    ushort checkBoxData;
};

void reminder(int chance);

extern int winused[100];
extern char registered;
DialogData ParamsDialog;

extern char creatPPE;
extern char creatBAK;
extern char saveBefore;
extern char SwapCompil;
extern char SwapShell;
extern char SwapRun;
extern char autoSaveDesktop;
extern char autoLoadDesktop;
extern char emacsHeader;
extern int autoindentmode;
extern int alwaysflat;
extern int flatxnn;
extern unsigned int screenSaverTimeout;

extern int Disarr;
extern int Nouvar;
extern TCollection *tagList;
extern Boolean Tagger;
extern TMessageViewer *messageViewer;
extern TView *messageView;
extern TView *TaggerView;
extern TDialog *TagDialog;
extern TTaggerWindow *TaggerWindow;

extern char messageFile[256];

static void closeView(TView *p, void *p1)
{
    message(p, evCommand, cmClose, p1);
}

//
// loadDesktop() function
//

void TEditorApp::loadDesktop(fpstream &s)
{
	TView  *p;
	int a;
	char *signature;

	signature = (char *)malloc(25);

	float prjVersion=0;

	if (deskTop->valid(cmClose))
	{
	deskTop->forEach(::closeView, 0);  // Clear the desktop
	s.readBytes((void *)signature,strlen(CTXT_HEADER));
	if (strncmp(signature,CTXT_HEADER,strlen(CTXT_HEADER)-7))
		{
		nk:
		messageBox(CTXT_NOTCTXT,mfError|mfOKButton);
				free(signature);
		return;
		}
	char ver[4]="   ";
	strncpy(ver,&signature[22],3);
	prjVersion = atof(ver);
	if (prjVersion < 2) goto nk;
	for (a=0;a<10;a++)
		s >> winused[a];
	TRect r;
	if (prjVersion == 2.2f)
	{
	s >> a;
	if ((Boolean)a)
		{
		openMessages(messageFile,a);
		s >> r.a.x;
		s >> r.a.y;
		s >> r.b.x;
		s >> r.b.y;
		messageView->locate(r);
		}

	tagList->freeAll();
	s >> a;
	if ((Boolean)a)
		{
		openTags(a);
		s >> r.a.x;
		s >> r.a.y;
		s >> r.b.x;
		s >> r.b.y;
		TaggerView->locate(r);
		}
	s >> a;
	char line[255];
	for (int b=0;b<a;b++)
		{
		s.readString(line,254);
		tagList->insert( newStr(line));
		}
	if (Tagger) TaggerWindow->update();
	}
	if (prjVersion == 2.0f)
	{
	s >> a;
	if ((Boolean)a) openMessages(messageFile,0);
	}

	do {
	   s >> p;
	   deskTop->insertBefore(validView(p), deskTop->last);
	   p->makeFirst();
	   }
	   while (p != 0);
	free(signature);
	}
}


TMenuBar *TEditorApp::initMenuBar( TRect r )
{

	 TSubMenu& sub1 = *new TSubMenu( "~ð~", kbAltSpace ) +
	*new TMenuItem( "A~b~out PowerPPL", cmAbout, kbNoKey) +
		 newLine() +
	*new TMenuItem( "~V~ideo mode", cmVideoMode, kbNoKey, hcNoContext, "" ) +
		 newLine() +
	*new TMenuItem( "~A~scii table", cmAscii, kbAltM, hcNoContext, "Alt-M") +
	*new TMenuItem( "C~o~lor Chart", cmColor, kbAltA, hcNoContext, "Alt-A") +
	*new TMenuItem( "~C~alculator", cmCalc, kbNoKey) +
	*new TMenuItem( "Ca~l~endar", cmCalendar, kbNoKey);

	  TSubMenu& sub2 = *new TSubMenu( "~F~ile", kbAltF ) +
	*new TMenuItem( "~O~pen", cmOpen, kbF3 ) +
	*new TMenuItem( "~N~ew", cmNew, kbNoKey ) +
	*new TMenuItem( "~S~ave", cmSave, kbF2, hcNoContext, "F2" ) +
	*new TMenuItem( "S~a~ve as...", cmSaveAs, kbNoKey ) +
		 newLine() +
	*new TMenuItem( "~C~hange dir...", cmChangeDrct, kbNoKey ) +
	*new TMenuItem( "~D~OS shell", cmDosShell, kbNoKey ) +
		 newLine() +
	*new TMenuItem( "E~x~it", cmQuit, kbAltX, hcNoContext, "Alt-X" );

	  TSubMenu& sub3 = *new TSubMenu( "~E~dit", kbAltE ) +
	*new TMenuItem( "~U~ndo", cmUndo, kbNoKey, hcNoContext, "Alt-U" ) +
		 newLine() +
	*new TMenuItem( "Cu~t~", cmCut, kbShiftDel, hcNoContext, "Shift-Del" ) +
	*new TMenuItem( "~C~opy", cmCopy, kbCtrlIns, hcNoContext, "Ctrl-Ins" ) +
	*new TMenuItem( "~P~aste", cmPaste, kbShiftIns, hcNoContext, "Shift-Ins" ) +
	*new TMenuItem( "~C~lear", cmClear, kbCtrlDel, hcNoContext, "Ctrl-Del" ) +
		 newLine() +
	*new TMenuItem( "~S~how clipboard", cmShowClip, kbNoKey ) +
	*new TMenuItem( "~A~dd tag", cmAddTag, kbCtrlF3, hcNocontext, "Ctrl-F3" ) +
	*new TMenuItem( "~N~ext tag", cmNextTag, kbCtrlF4, hcNocontext, "Ctrl-F4" );

	  TSubMenu& sub4 = *new TSubMenu( "~S~earch", kbAltS ) +
	*new TMenuItem( "~F~ind...", cmFind, kbNoKey ) +
	*new TMenuItem( "~R~eplace...", cmReplace, kbNoKey ) +
	*new TMenuItem( "~S~earch again", cmSearchAgain, kbNoKey );

	  TSubMenu& sub5 = *new TSubMenu( "~C~ompile", kbAltC ) +
	*new TMenuItem( "~C~ompile", cmCompile, kbF9, hcNoContext, "F9" );
//	*new TMenuItem( "~D~ecompile", cmDecompile, kbAltF9, hcNoContext, "Alt-F9" ) +
//		 newLine() +

//	*new TMenuItem( "~P~arameters", cmParams, kbNoKey);

	  TSubMenu& sub7 = *new TSubMenu( "~W~indow", kbAltW ) +
	*new TMenuItem( "~S~ize/move",cmResize, kbCtrlF5, hcNoContext, "Ctrl-F5" ) +
	*new TMenuItem( "~Z~oom", cmZoom, kbF5, hcNoContext, "F5" ) +
	*new TMenuItem( "~T~ile", cmTile, kbNoKey ) +
	*new TMenuItem( "C~a~scade", cmCascade, kbNoKey ) +
	*new TMenuItem( "~N~ext", cmNext, kbF6, hcNoContext, "F6" ) +
	*new TMenuItem( "~P~revious", cmPrev, kbShiftF6, hcNoContext, "Shift-F6" ) +
	*new TMenuItem( "~C~lose", cmClose, kbAltF3, hcNoContext, "Alt-F3" ) +
		 newLine() +
	*new TMenuItem( "~U~ser screen", cmUserScreen, kbAltF5, hcNoContext, "Alt-F5") +
	*new TMenuItem( "Ta~g~s", cmTags, kbCtrlF2, hcNoContext, "Ctrl-F2") +
	*new TMenuItem( "~M~essage", cmMessage, kbNoKey);

	  TSubMenu& sub9 = *new TSubMenu( "~P~roject", kbAltP ) +
	*new TMenuItem( "~O~pen project...", cmOpenProject, kbNoKey, hcNoContext ) +
	*new TMenuItem( "~C~lose project", cmCloseProject, kbNoKey, hcNoContext );

	  TSubMenu& sub8 = *new TSubMenu( "~O~ptions", kbAltO ) +
	*new TMenuItem( "~C~ustomize colors...", cmColorCmd, kbNoKey, hcNoContext ) +
	*new TMenuItem( "~D~efaults colors", cmDefCols, kbNoKey, hcNoContext ) +
		 newLine() +
	*new TMenuItem( "D~i~rectories...", cmDirOptions, kbNoKey, hcNoContext ) +
	*new TMenuItem( "~E~nvironment...", cmFileOptions, kbNoKey, hcNoContext ) +
	*new TMenuItem( "~T~ab length...", cmTabLen, kbNoKey, hcNoContext ) +
		 newLine() +
	*new TMenuItem( "~S~ave desktop", cmSaveDesktop, kbNoKey, hcNoContext ) +
	*new TMenuItem( "~R~etrieve desktop", cmRetrieveDesktop, kbNoKey, hcNoContext );

	  TSubMenu& sub6 = *new TSubMenu( "~H~elp", kbAltH ) +
	*new TMenuItem( "~C~ontents", cmHelpContents, kbF1, hcNoContext, "F1") +
	*new TMenuItem( "~I~ndex", cmHelpIndex, kbShiftF1, hcNoContext , "Shift-F1") +
	*new TMenuItem( "~T~opic search", cmTopicSearch, kbCtrlF1, hcNoContext, "Ctrl-F1") +
	*new TMenuItem( "~P~revious topic", cmPreviousTopic, kbAltF1, hcNoContext, "Alt-F1") +
	*new TMenuItem( "~Z~ippy search", cmZippySearch, kbCtrlF7, hcNoContext, "Ctrl-F7");

	  TSubMenu& sub10 = *new TSubMenu( "~R~un", kbAltR ) +
	*new TMenuItem( "~R~un", cmRunPPE, kbCtrlF9, hcNoContext, "Ctrl-F9") +
//	*new TMenuItem( "~P~rogram reset", cmResetTrace, kbCtrlF2, hcNoContext, "Ctrl-F2") +
	*new TMenuItem( "~T~race", cmTraceF7, kbF7, hcNoContext, "F7") +
	*new TMenuItem( "~T~oggle breakpoint", cmToggleBp, kbCtrlF8, hcNoContext, "Ctrl-F8") +
	*new TMenuItem( "Re~m~ove all breakpoints", cmClearBp, kbNoKey, hcNoContext) +
		 newLine() +
//	*new TMenuItem( "~S~tep over", cmTraceF8, kbF8, hcNoContext, "F8") +
//	*new TMenuItem( "~U~ser info...", cmUserInfo, kbNoKey, hcNoContext ) +
	*new TMenuItem( "~A~rguments...", cmArguments, kbNoKey, hcNoContext);

	r.b.y = r.a.y + 1;    // set bottom line 1 line below top line

	return new TMenuBar( r, sub1 + sub2 + sub3 + sub4 + sub10 + sub5 + sub7 + sub9 + sub8 + sub6);
}

TStatusLine *TEditorApp::initStatusLine( TRect r )
{
	r.a.y = r.b.y-1;
	return new TStatusLine( r,
	*new TStatusDef( 0, 0xFFFF ) +
		*new TStatusItem( "~F1~ Help", kbF1, cmHelp ) +
		*new TStatusItem( "~F2~ Save", kbF2, cmSave ) +
		*new TStatusItem( "~F3~ Open", kbF3, cmOpen ) +
		*new TStatusItem( "~Alt-F3~ Close", kbAltF3, cmClose ) +
		*new TStatusItem( "~F5~ Zoom", kbF5, cmZoom ) +
		*new TStatusItem( "~F6~ Next", kbF6, cmNext ) +
		*new TStatusItem( "~F9~", kbF9, cmCompile ) +
		*new TStatusItem( "~F10~ Menu", kbF10, cmMenu ) +
		*new TStatusItem( 0, kbCtrlF5, cmResize )
		);

}

void TEditorApp::outOfMemory()
{
	messageBox("\003Not enough memory for this operation.", mfError | mfOKButton );
}

typedef char *_charPtr;
typedef TPoint *PPoint;

#pragma warn -rvl

ushort doEditDialog( int dialog, ... )
{
    va_list arg;

    char buf[80];
    ostrstream os( buf, sizeof( buf ) );
    switch( dialog )
	{
	case edOutOfMemory:
		return messageBox( "\003Not enough memory for this operation",
				   mfError | mfOKButton );
	case edReadError:
		{
		va_start( arg, dialog );
		os << "\003Error reading file " << va_arg( arg, _charPtr )
		   << "." << ends;
		va_end( arg );
			return messageBox( buf, mfError | mfOKButton );
		}
		case edWriteError:
			{
			va_start( arg, dialog );
			os << "\003Error writing file " << va_arg( arg,_charPtr )
			   << "." << ends;
		va_end( arg );
			return messageBox( buf, mfError | mfOKButton );
			}
		case edCreateError:
		{
			va_start( arg, dialog );
			os << "\003Error creating file " << va_arg( arg, _charPtr )
		   << "." << ends;
			va_end( arg );
			return messageBox( buf, mfError | mfOKButton );
		}
		case edSaveModify:
		{
		va_start( arg, dialog );
		os << "\003" << va_arg( arg, _charPtr )
		   << " has been modified. Save ?" << ends;
		va_end( arg );
		return messageBox( buf, mfInformation | mfYesNoCancel );
		}
	case edSaveUntitled:
		return messageBox( "\003Save untitled file?",
				   mfInformation | mfYesNoCancel );
	case edSaveAs:
		{
		va_start( arg, dialog );
		return execDialog( new TFileDialog( "*.PPS",
						"Save file as",
						"~N~ame",
						fdOKButton,
						101 ), va_arg( arg, _charPtr ) );
		}

	case edFind:
		{
		va_start( arg, dialog );
		return execDialog( createFindDialog(), va_arg( arg, _charPtr ) );
		}

	case edSearchFailed:
		return messageBox( "\003Search string not found.",
				   mfError | mfOKButton );
	case edReplace:
		{
		va_start( arg, dialog );
		return execDialog( createReplaceDialog(), va_arg( arg, _charPtr ) );
		}

	case edReplacePrompt:
		//  Avoid placing the dialog on the same line as the cursor
			TRect r( 0, 1, 40, 8 );
			r.move( (TProgram::deskTop->size.x-r.b.x)/2, 0 );
			TPoint t = TProgram::deskTop->makeGlobal( r.b );
	    t.y++;
            va_start( arg, dialog );
            TPoint *pt = va_arg( arg, PPoint );
            if( pt->y <= t.y )
                r.move( 0, TProgram::deskTop->size.y - r.b.y - 2 );
			va_end( arg );
			return messageBoxRect( r, "\003Replace this occurence?",
								   mfYesNoCancel | mfInformation );

		}
}

#pragma warn .rvl

void TEditorApp::fileOptions()
{
	if (!registered) reminder(5);
	TDialog *d = new TDialog( TRect( 0, 0, 70, 17 ), "Environment" );

	d->options |= ofCentered;

	TCheckBoxes *compileOptions = new TCheckBoxes( TRect( 3, 3, 33, 4 ),
								  new TSItem( "~C~reate PPE To Disk",0));

	TLabel *compileOptionsLabel = new TLabel (TRect (2,2,10,3), "Compile", compileOptions);

	TCheckBoxes *desktopOptions = new TCheckBoxes( TRect( 3, 6, 33, 8 ),
								  new TSItem( "Auto-~S~ave",
								  new TSItem( "Auto-~L~oad",0)));

	TLabel *desktopOptionsLabel = new TLabel (TRect (2,5,10,6), "Desktop", desktopOptions);

	TCheckBoxes *colorOptions =   new TCheckBoxes( TRect( 3, 10, 33, 12 ),
								  new TSItem( "~S~yntax Highlight",
								  new TSItem( "@~X~nn Translation",0)));

	TLabel *colorOptionsLabel =   new TLabel (TRect (2,9,9,10), "Color", colorOptions);

	TCheckBoxes *editorOptions =  new TCheckBoxes( TRect( 35, 3, 67, 7 ),
								  new TSItem( "Auto~I~ndent",
								  new TSItem( "Info ~H~eaders",
								  new TSItem( "~S~ave All Before Compile",
								  new TSItem( "Create ~B~AK files",0)))));

	TLabel *editorOptionsLabel =  new TLabel (TRect (34,2,43,3), "Editor", editorOptions);

	TCheckBoxes *memoryOptions =  new TCheckBoxes( TRect( 35, 9, 67, 12 ),
								  new TSItem( "Swap Before ~C~ompile",
								  new TSItem( "Swap Before ~R~unning",
								  new TSItem( "Swap Before Shell To ~D~OS",0))));

	TLabel *memoryOptionsLabel =  new TLabel (TRect (34,8,43,9), "Memory", memoryOptions);

	TInputLine *sSaverInput    =  new TInputLine (TRect( 26, 13, 34, 14 ), 5);

	TLabel *sSaverLabel        =  new TLabel (TRect (2,13,25,14), "Screen Saver ~T~imeout :", sSaverInput );

	d->insert(compileOptions);
	d->insert(compileOptionsLabel);
	d->insert(editorOptions);
	d->insert(editorOptionsLabel);
	d->insert(desktopOptions);
	d->insert(desktopOptionsLabel);
	d->insert(memoryOptions);
	d->insert(memoryOptionsLabel);
	d->insert(colorOptions);
	d->insert(colorOptionsLabel);
	d->insert(sSaverInput);
	d->insert(sSaverLabel);


	d->insert(
	new TButton( TRect( 45, 14, 55, 16 ), "O~K~", cmOK, bfDefault ) );
	d->insert(
	new TButton( TRect( 57, 14, 67, 16 ), "~C~ancel", cmCancel, bfNormal ) );

	d->selectNext( False );


	ParamsDialog.checkBoxData = 0;

	if (creatPPE) ParamsDialog.checkBoxData++;
	compileOptions->setData( &ParamsDialog );


	ParamsDialog.checkBoxData = 0;

	if (autoSaveDesktop) ParamsDialog.checkBoxData ++;
	if (autoLoadDesktop) ParamsDialog.checkBoxData += 2;
	desktopOptions->setData( &ParamsDialog );

	ParamsDialog.checkBoxData = 0;

	if (!alwaysflat) ParamsDialog.checkBoxData ++;
	if (!flatxnn) ParamsDialog.checkBoxData += 2;
	colorOptions->setData( &ParamsDialog );

	ParamsDialog.checkBoxData = 0;

	if (autoindentmode) ParamsDialog.checkBoxData ++;
	if (emacsHeader && !registered)
		emacsHeader = 0;
	if (emacsHeader) ParamsDialog.checkBoxData += 2;
	if (saveBefore) ParamsDialog.checkBoxData += 4;
	if (creatBAK) ParamsDialog.checkBoxData += 8;
	editorOptions->setData( &ParamsDialog );

	ParamsDialog.checkBoxData = 0;

	if (SwapCompil) ParamsDialog.checkBoxData ++;
	if (SwapRun) ParamsDialog.checkBoxData += 2;
	if (SwapShell) ParamsDialog.checkBoxData += 4;
	memoryOptions->setData( &ParamsDialog );

	char str[10]="";
	itoa(screenSaverTimeout,str,10);
	sSaverInput->setData(str);

	ushort control = deskTop->execView( d );

	if( control != cmCancel )
	{

	sSaverInput->getData(str);
	screenSaverTimeout = atoi(str);

	compileOptions->getData( &ParamsDialog );
	if (ParamsDialog.checkBoxData & 1) creatPPE = True; else creatPPE = False;

	desktopOptions->getData( &ParamsDialog );
	if (ParamsDialog.checkBoxData & 1) autoSaveDesktop = True; else autoSaveDesktop = False;
	if (ParamsDialog.checkBoxData & 2) autoLoadDesktop = True; else autoLoadDesktop = False;

	colorOptions->getData( &ParamsDialog );
	if (ParamsDialog.checkBoxData & 1) alwaysflat = False; else alwaysflat = True;
	if (ParamsDialog.checkBoxData & 2) flatxnn = False; else flatxnn = True;

	if (alwaysflat)
		flatxnn = True;

	editorOptions->getData( &ParamsDialog );
	if (ParamsDialog.checkBoxData & 1) autoindentmode = True; else autoindentmode = False;
	if (ParamsDialog.checkBoxData & 2) emacsHeader = True; else emacsHeader = False;
	if (ParamsDialog.checkBoxData & 4) saveBefore = True; else saveBefore = False;
	if (ParamsDialog.checkBoxData & 8) creatBAK = True; else creatBAK = False;

	memoryOptions->getData( &ParamsDialog );
	if (ParamsDialog.checkBoxData & 1) SwapCompil = True; else SwapCompil = False;
	if (ParamsDialog.checkBoxData & 2) SwapRun = True; else SwapRun = False;
	if (ParamsDialog.checkBoxData & 4) SwapShell = True; else SwapShell = False;
	}

	if (emacsHeader && !registered)
		{
		messageBox("\003Headers in editors are only for Registered users !",mfWarning|mfOKButton);
		emacsHeader = 0;
		}


	TEvent event;
	event.what = evBroadcast;
	event.message.command = 1544;
	putEvent( event );

	destroy( d );

	deskTop->setState( sfVisible, False );
	deskTop->setState( sfVisible, True );

		event.what = evBroadcast;
		event.message.command = 1549;
		putEvent(event);

}

void TEditorApp::selectParams()
{
	TDialog *d = new TDialog( TRect( 0, 0, 38, 12 ), "Compiler Options" );

    d->options |= ofCentered;

    d->insert(
	new TStaticText( TRect (5,3,35,4), "Choose compilation options") );

	d->insert( new TCheckBoxes( TRect( 3, 5, 35, 7 ),
	new TSItem( "~A~rray dimension checking",
	new TSItem( "~U~ser variable generation", 0 ))));

    d->insert(
	new TButton( TRect( 14, 9, 24, 11 ), "O~K~", cmOK, bfDefault ) );
	d->insert(
	new TButton( TRect( 26, 9, 36, 11 ), "~C~ancel", cmCancel, bfNormal ) );

    d->selectNext( False );

	// we save the dialog data:
    ParamsDialog.checkBoxData = 0;
    if (!Disarr) ParamsDialog.checkBoxData++;
    if (!Nouvar) ParamsDialog.checkBoxData += 2;

	d->setData( &ParamsDialog );
	
    ushort control = deskTop->execView( d );

	// and read it back when the dialog box is successfully closed
    if( control != cmCancel )
	{
	d->getData( &ParamsDialog );
	if (ParamsDialog.checkBoxData & 1) Disarr = False; else Disarr = True;
	if (ParamsDialog.checkBoxData & 2) Nouvar = False; else Nouvar = True;
	}

    destroy( d );
}
