
/*	TRevengeApp.cpp
 *
 *		The generic application class declaration
 */

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

  YAAF is Copyright 1997-1999 by William Woody.

  Redistribution and use in source and binary forms, with or without 
  modification, are permitted provided that the following conditions 
  are met:

  Redistributions of source code must retain the above copyright notice, 
  this list of conditions and the following disclaimer.

  Neither the name of the copyright holder or other contributors may
  be used to promote products derived from this software without
  specific written prior permission.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
  SOFTWARE.
  
  Contact:   woody@alumni.caltech.edu
  Web page:  http://www.pandawave.com/yaaf/

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

#include <XConfig.h>
#include <XAutoPtr.h>
#include <XAppMenu.h>
#include <XMessages.h>
#include <XScroll.h>
#include <XPrinter.h>
#include <XDialog.h>
#include <XAutoPtr.h>
#include <XList.h>
#include <XPopup.h>
#include <XPrinter.h>
#include <XList.h>
#include <XTextControls.h>
#include <XButtons.h>
#include <XOpenGLView.h>
#include <XSlideControl.h>
#include <XError.h>
#include <ctype.h>
#include "TBitmapView.h"

#include "revengeapp.h"
#include "TTagFileForm.h"
#include "TTagFileDocument.h"
#include "TTagEditHeader.h"
#include "TTagEditForm.h"
#include "RevengeResources.h"
#include "vengeance_script.h"
#include "TAllTagForm.h"

//#include "TBackView.h"
#include "TTreeView.h"
#include "tags.h"
#include "formatters.h"
//#include "TTableView.h"
//#include "TViewEditor.h"
//#include "TViewTemplate.h"

/************************************************************************/
/*																		*/
/*	Application Core													*/
/*																		*/
/************************************************************************/

/*	TRevengeApp::TRevengeApp
 *
 *		The main entry point for constructing me; this knows how to
 *	initialize things. This registers a few views that I may need.
 */

TRevengeApp::TRevengeApp() : XGAppMultiWindow("Vengeance")
{
	/*
	 *	Regster the views I'm going to use
	 */
	
	RegisterView(XGStaticText);
	RegisterView(XGEditText);
	RegisterView(XGPopControl);
	RegisterView(XGCommandButton);
	RegisterView(XGScrollView);
	RegisterView(XGListControl);
	RegisterView(XGGroupBox);
	RegisterView(XGRadioButton);
	RegisterView(XGCheckButton);
	RegisterView(XGOpenGLView);
	RegisterView(XGSlideControl);

	RegisterView(TTreeView);
	RegisterView(TBitmapView);
	RegisterView( TTagEditHeader );
	RegisterView( TTagEditBackground );
	//RegisterView(TTableView);
	//RegisterView(TBackView);
	//RegisterView(TViewEditor);
	
	RegisterWindow(XGDialog);
	
	/*
	 *	Load the templates
	 */
	
	//GTemplate.LoadTemplates();
	
	// and scan the tags!
	
	XGDirectory start;
	
	// scan the /tags folder.
	start.SetAppLocation();
	if (start.ChangeDirectory("tags"))
	{
		scan_directory_for_tag_files( start, true );
	}
	
	// scan the /local folder.
	start.SetAppLocation();
	if (start.ChangeDirectory("local"))
	{
		scan_directory_for_tag_files( start, true );
	}
	
	// scan the /plugins folder.
	start.SetAppLocation();
	if (start.ChangeDirectory("plugins"))
	{
		scan_directory_for_tag_files( start, true );
	}
}

/*	TRevengeApp::~TRevengeApp
 *
 *		Destroy me
 */

TRevengeApp::~TRevengeApp()
{
}

/************************************************************************/
/*																		*/
/*	Event Management													*/
/*																		*/
/************************************************************************/

BEGINDISPATCH(TRevengeApp,XGAppMultiWindow)
	DISPATCHTABLE(KXGGetMenuStatus,TRevengeApp::DoGetMenuStatus)
	DISPATCHTABLE(KXGDoMenuCommand,TRevengeApp::DoMenuCommand)
	DISPATCHTABLE(KXGDoOpenDocument,TRevengeApp::DoOpenDocument)
	DISPATCHTABLE(KXGOpenApplication,TRevengeApp::DoOpenApplication)
ENDDISPATCH

/*	TRevengeApp::DoGetMenuStatus
 *
 *		Get the menu status
 */

long TRevengeApp::DoGetMenuStatus(long arg, void *parg)
{
	XGSMenuStatus *status = (XGSMenuStatus *)parg;
	
	switch (arg) {
		case KMenuFileNew:
		case KMenuFileOpen:
		case KMenuFilePageSetup:
			status->enable = true;
			return 0;
		case KMenuExecuteScript:
			status->enable = true;
			return 0;
		case KMenuFileBuildFoundation:
		case KMenuShowMeAllParsedTags:
		case KMenuFileUpdateFormats:
			status->enable = true;
			return 0;
		case KMenuFindTag:
			status->enable = true;
			return 0;
		default:
			break;
	}
	return -1;
}

/*	TRevengeApp::DoMenuCommand
 *
 *		Handle the menu command
 */

struct tag_find_data
{
	tag type;
	tag id;
};

static tag_find_data tag_find_last = { -1, -1 };

long TRevengeApp::FindTagProc(XGDialog *dlog, void *data, long msg, long arg, void *)
{
	tag_find_data *tag_find = (tag_find_data *)data;
	
	switch( msg )
	{
		case KXGDialogMessage:
		{
			switch( arg )
			{
				case KXGDMInitDialog:
				{
					if( tag_find->type != -1 )
						SetText( dlog->GetWindow(), 1, tagstr( tag_find->type ) );
						
					if( tag_find->id != -1 )
						SetText( dlog->GetWindow(), 2, tagstr( tag_find->id ) );
				}
				
				return 0;
				
				default:
					break;
			}
		}
		
		break;
		
		case KXGKeyClick:
			break;
		
		case KXGControlClick:
		{
			char buf[16];
			
			switch( arg )
			{
				case 1001: // OK
				{
					GetText( dlog->GetWindow(), 1, buf, 16 );
					tag_find->type = tag_type_from_string( buf );
					
					GetText( dlog->GetWindow(), 2, buf, 16 );
					tag_find->id = tag_type_from_string( buf );

					dlog->EndDialog( 1 );
				}
				
				break;
				
				case 1002: // Cancel
				{
					dlog->EndDialog( 0 );
				}
				
				break;
				
				default:
					break;
			}
		}
		
		break;
	}
			
	return -1;
}

long TRevengeApp::DoMenuCommand(long arg, void *)
{
	switch (arg) {
		case KMenuFileNew:
			NewDocument();
			return 0;
		case KMenuFileOpen:
			OpenDocument();
			return 0;
		case KMenuFilePageSetup:
			GPrinter.PageSetup();
			return 0;
		case KMenuShowMeAllParsedTags:
		{
			TAllTagForm::Show();
		} break;
		case KMenuExecuteScript:
		{
			XGFileSpecifier *fs;

		#if OPT_MACOS
			fs = XGFileSpecifier::OpenDialog( 129 );
		#endif

		#if OPT_WINOS
			fs = XGFileSpecifier::OpenDialog( "Vengeance Script File|*.VSF","VSF" );
		#endif

		#if OPT_XWIN
			fs = XGFileSpecifier::OpenDialog( "vsf" );
		#endif

			if( fs )
			{
				if( parse_vengeance_script( fs ) )
				{
					if( execute_vengeance_script() )
					{
						// save all tags
						for( tag_file *tf = tag_file_list; tf != NULL; tf = tf->next )
						{
							if( is_file_modified( tf ) )
							{
								update_tag_file( tf );
							}
						}
					}
				}
			}
		}
		return 0;
		case KMenuFileBuildFoundation: {
			XGFileSpecifier *fs = 0;
			
			#if OPT_MACOS
				fs = XGFileSpecifier::OpenDialog( 130 );
			#endif
			
			#if OPT_WINOS
				fs = XGFileSpecifier::OpenDialog( "All Files|*.*","txt" );
			#endif
			
			BuildFoundationTags( fs );
			} return 0;
			
		case KMenuFileUpdateFormats: {
				tag_file *file = 0;
				while ((file = get_next_tag_file(file)) != 0)
				{
					bool any_updates = false;
					tag_group *group = 0;
					while ((group = get_next_group_in_file( file, group )) != 0)
					{
						int version = get_type_version( group->type );
						tag_entry *entry = 0;
						while ((entry = get_next_entry_in_group( group, entry )) != 0)
						{
							if (get_entry_id( entry ) == 'dwmo')
							{
								entry = entry;
							}
							if (update_entry_version( entry ))
							{
								any_updates = true;
								//OpenTagFileWindow( file, true );
							}
						}
					}
					if (any_updates)
					{
						TTagFileForm *form = get_file_form( file );
						if (form)
						{
							form->ReloadTableContents();
						}
						else
						{
							try {
								update_tag_file( file );
							}
							catch (XGError &e)
							{
								e.DisplayError();
							}
							
						}
					}
				}
			} return 0;
			
		case KMenuFindTag:
		{
			tag_find_data tag_find;
			
			
			if( XGDialog::ModalDialog( KWindowFindTag, FindTagProc, (void *)&tag_find ) )
			{
				tag_find_last = tag_find;
				OpenItem( get_entry( tag_find.type, tag_find.id ) );
			}
		}
		
		return 0;
		
		default:
			break;
	}
	return -1;
}

/*	TContructorApp::DoOpenDocument
 *
 *		Open the document. Basically defers to the proper open document
 *	routine
 */

long TRevengeApp::DoOpenDocument(long, void *parg)
{
	// this is only called if command line arguments were passed to the application
#if 0
	OpenDocument( (XGFileSpecifier *)parg );
#else
	BuildFoundationTags( (XGFileSpecifier *)parg );
	XGDispatch::SendDispatch(KXGQuitApplication,0,NULL);
#endif

	return 0;
}


/*	TContructorApp::DoOpenApplication
 *
 *		Application launched. Open a new document.
 */

long TRevengeApp::DoOpenApplication(long, void *)
{
	//NewDocument();
	//TAllTagForm::Show();
	return 0;
}

/*	TRevengeApp::DoPostPeriodic
 *
 *		Handle periodic updates, by determining the focus, and
 *	finding the frontmost document object.
 */

void TRevengeApp::DoPostPeriodic(void)
{
#if 0
	XGView *view;
	XGDocForm *dform;
	TTagFileDocument *doc;
	
	view = dynamic_cast<XGView *>(GetFocus());
	if (view == NULL) {
		TCatalogForm::SetCurrentCatalog(NULL,NULL);
	} else {
		dform = dynamic_cast<XGDocForm *>(view->GetForm());
		if (dform) {
			doc = dynamic_cast<TTagFileDocument *>(dform->GetDocument());
			if (doc) {
				TCatalogForm::SetCurrentCatalog(&(doc->GetViewTemplate()),doc);
			}
		}
	}
#endif
}

/************************************************************************/
/*																		*/
/*	Global Commands														*/
/*																		*/
/************************************************************************/

/*	TRevengeApp::NewDocument
 *
 *		Create a new document. This builds the document object, then
 *	the form object, and finally the window.
 */

void TRevengeApp::NewDocument()
{
	
	tag_file *tf = new_empty_tag_file();
	if (tf) {
		TTagFileForm *form = new TTagFileForm( tf );
		form->AttachWindow(KWindowTagFile);
	}
}

/*	TRevengeApp::OpenDocument
 *
 *		Create a new document. This builds the document object, then
 *	the form object, and finally the window.
 */

void TRevengeApp::OpenDocument()
{
	XGFileSpecifier *fs;
	
#if OPT_MACOS
	fs = XGFileSpecifier::OpenDialog(128);
#endif

#if OPT_WINOS
	fs = XGFileSpecifier::OpenDialog("Myth 3 Tag File|*.tag|All Files|*.*","tag");
#endif

#if OPT_XWIN
	fs = XGFileSpecifier::OpenDialog("tag");
#endif
	
	if (!fs) return;
	this->OpenDocument( fs );
	
	delete fs;
}

/*	TRevengeApp::OpenDocument
 *
 *		Create a new document. This builds the document object, then
 *	the form object, and finally the window.
 */

void TRevengeApp::OpenDocument(XGFileSpecifier *file)
{
	tag_file *tf = get_tag_file( *file, false );
	TRevengeApp::OpenTagFileWindow( tf );
}


void TRevengeApp::OpenTagFileWindow( tag_file *tf, bool bring_to_front )
{
	if (tf)
	{
		TTagFileForm *form;
		form = get_file_form( tf );
		if (form) {
			if (bring_to_front) {
				form->GetWindow()->SelectWindow();
			} // else do nothing
		} else {
			XGWindow *front = NULL;
			if (!bring_to_front) {
				front = XGWindow::GetFrontWindow();
			}
			form = new TTagFileForm( tf );
			form->AttachWindow(KWindowTagFile);
			if (bring_to_front) {
				front = form->GetWindow();
			}
			if (front) {
				front->SelectWindow();
			}
		}
	}
}

void TRevengeApp::BuildFoundationTags( XGFileSpecifier *fs )
{
	if( fs )
	{
		begin_tag_dependency_generation();
		FILE *f = fs->OpenFile( "r" );
		int c;
		int i;
		file_tag type, id;
	next:
		do {
			c = getc(f);
			if (c == EOF) goto done;
		} while (isspace(c));
		type = c;
		for (i = 0; i < 3; ++i) {
			c = getc(f);
			if (c == EOF) goto done;
			type = (type << 8) + c;
		}
		if (getc(f) != ':') goto next;
		for (i = 0; i < 4; ++i) {
			c = getc(f);
			if (c == EOF) goto done;
			id = (id << 8) + c;
		}
		add_tag_dependency( type, id );
		goto next;
	done:
		fclose( f );
		end_tag_dependency_generation();
	}
	
//	add_tag_dependency( 'mesh', '01yu' );
//	add_tag_dependency( 'mesh', '02ci' );
//	add_tag_dependency( 'mesh', '05fg' );
}

void TRevengeApp::GetTagFilePath( char *path, tag_file *f )
{
	XGFileSpecifier *fs = get_tag_file_spec( f );
	char buf[256];
	if (fs) {
		XGDirectory app;
		app.SetAppLocation();
		XGDirectory dir;
		fs->GetDirectory( dir );
		fs->GetName( path );
		for (;;) {
			dir.GetDirectoryName( buf );
			int len = strlen(buf);
			memmove( path + len + 1, path, strlen(path)+1 );
			memcpy( path, buf, len );
			path[len] = '/';
			XGDirectory child = dir;
			dir.ChangeDirectory(0);	// up to parent
			if (dir == child) break;
			if (dir == app) break;
		}
	} else {
		strcpy( path, "(unsaved tag file)" );
	}
}

/*	TRevengApp::OpenItem
 *
 *		Open the specified resource for editing. This is the primary
 *	location which needs to be updated when new resources are added
 *	for editing.
 */

void TRevengeApp::OpenItem( struct tag_entry *entry, bool mod )
{
	if (!entry) return;
	OpenTagFileWindow( get_entry_file( entry ), false );
	
	bool updated = update_entry_version( entry );
	bool opened = false;
	
	TTagEditForm *form = get_entry_form( entry );
	if (form)
	{
		form->GetWindow()->SelectWindow();
		opened = true;
	}
	else
	{
		tag type = get_entry_type( entry );
		if (type)
		{
			tag_editor_proc edit = get_type_editor( type, mod );
			if (edit)
			{
				edit( entry );
				form = get_entry_form( entry );
				if (form)
				{
					form->TagInfoChanged();
					form->ReloadTag();
					opened = true;
				}
			}
		}
	}
	
	if (updated)
	{
		XGDialog::ModalAlert( KWindowTagVersionUpdate, "", "", "", "" );
	}
	
	if (!opened)
	{
		OpenTagFileWindow( get_entry_file( entry ), true );
		TTagFileForm *file_form = get_file_form( get_entry_file( entry ) );
		if (file_form)
		{
			file_form->NoticeItem( entry, true, true );
		}
	}
}

XGAppCore *StartApplication()
{
	return new TRevengeApp;
}

