//	MainEvent.c
#ifndef __MWERKS__
#ifndef __GNUC__
		#include <Desk.h>
	#include <Dialogs.h>
	#include <Errors.h>
	#include <Files.h>
	#include <Fonts.h>
	#include <Memory.h>
	#include <Menus.h>
	#include <StandardFile.h>
	#include <TextEdit.h>
	#include <Types.h>
	#include <Windows.h>
#endif
#endif

#include "CDesktop.h"
#include "CDiskMapWindow.h"
#include "ADFS_LogFile.h"
#include "DSGlobals.h"
#include "DSUserProcs.h"
#include "DSAppleEvents.h"
#include "CDialogPrefs.h"
#include "A2PixInterface.h"
#include "MemUtils.h"
#include "CEntry.h"
#include "Utils.h"
#include "ADFS_Menus.h"
#include "IC_ImageTypes.h"
#include "IC_Errors.h"
#include "A2PixInterface.h"
#include "CDialogGetInfo.h"
#include "CDialogAbout.h"
#include "FSUtils.h"
#include "PhysicalFloppy.h"

#include "MainEvent.h"

Boolean		gDone, gOApped, gHasAppleEvents, gWasEvent;
EventRecord	gEvent;
WindowPtr	gSplashScreen;

#ifdef MPW
extern void _DataInit();	
#endif

short		g_event_levelS = 0;

#pragma segment Initialize
void InitToolbox (void) 
{
	#ifndef __68k__
		MoreMasterPointers(256);
	#else
		InitGraf ( &qd.thePort );
		InitFonts ();
		InitWindows ();
		InitMenus ();
		TEInit ();
		InitDialogs (0L);		// use of ResumeProcs no longer approved by Apple
		MaxApplZone();
		
		//	how about some memory fun!
		//	256 master pointers
		MoreMasters();
		MoreMasters();
		MoreMasters();
		MoreMasters();
		
		FlushEvents ( everyEvent, 0 );
	#endif
	
	InitCursor ();
}

/*
	Let's setup those global variables that the DropShell uses.
	
	If you add any globals for your own use,
	init them in the InitUserGlobals routine in DSUserProcs.c
*/
#pragma segment Initialize
Boolean InitGlobals (void) 
{
	long aLong;

	gDone			= false;
	gOApped			= false;	// probably not since users are supposed to DROP things!
	gHasAppleEvents	= Gestalt ( gestaltAppleEventsAttr, &aLong ) == noErr;
	gSplashScreen	= NULL;

	return(InitDSUserGlobals());	// call the user proc
}

/*
	This routine is called during startup to display a splash screen.
	
	This was recommend by the Blue Team HI person, John Sullivan, who
	feels that all apps should display something so that users can easily
	tell what is running, and be able to switch by clicking.  Thanks John!
*/
#pragma segment Initialize
void InstallSplashScreen(void) 
{
}


/*	--------------- Standard Event Handling routines ---------------------- */
#pragma segment Main

Boolean		gDoubleClick	= FALSE;
long		prevEventWhen	= 0;
Point		prevEventWhere	= { 0, 0 };

void DoMouseDown (EventRecord *event)
{
	WindowPtr	whichWindow;
	short		whichPart;
	CWindow		*window;
	Rect		theRect;
	
	theRect.left	= prevEventWhere.h;
	theRect.top		= prevEventWhere.v;
	theRect.right	= prevEventWhere.h;
	theRect.bottom	= prevEventWhere.v;
	InsetRect(&theRect, -1, -1);
	
	gDoubleClick	= 
		event->when - prevEventWhen < GetDblTime() 
		&& PtInRect(event->where, &theRect);
	
	prevEventWhen	= event->when;
	prevEventWhere	= event->where;
	
	whichPart	= FindWindow ( event->where, &whichWindow );
	window		= GetCWindow(whichWindow);
	
	if (window) {
		CWindow		*frontWindowP = GetFrontCWindow();
	
		if (
			frontWindowP 
			&& frontWindowP != window
			&& frontWindowP->i_windowType >= ADFS_Window_MODAL_DIALOG
			&& frontWindowP->i_windowType < ADFS_Window_DOCUMENT
		) {
			SysBeep(1);
		} else switch (whichPart) {

			case inContent: {
				window->DoClick(event);
				break;
			}

			case inDrag: {
				window->Move(event);
				break;
			}

			case inGrow: {
				window->Size(event);
				break;
			}
			
			case inGoAway: {
				window->GoAway(event);
				break;
			}
			
			case inZoomIn:
			case inZoomOut: {
				window->Zoom(event, whichPart);
				break;
			}
		}		
	} else {
		switch (whichPart) {
			//	case inDesk: defunct

			case inMenuBar:
				UpdateMenus();
				DoMenu(MenuSelect(event->where));
				break;
			
			case inSysWindow:
				#ifdef __68k__
					SystemClick(event, whichWindow);
				#endif
				break;
		}
	}	
}

#pragma segment Main

void	DoKeyDown(EventRecord *curEvent)
{
	if (!DoMenuKey(curEvent)) {
		CWindow		*window;
		
		if ((window = GetFrontCWindow()) != NULL) {	/*=*/
			window->DoKeyDown(curEvent);
		}
	}
}

static	Boolean		IdleCB(CWindow *window, void *data)
{
	window->Idle();
	return FALSE;
}

void	MountPending(void);

static	void	Idle(void)
{
	if (g_event_levelS == 1) {
		if (gDesktop) {
			gDesktop->DoPendingFlush();
		}

		CEntry::ADFS_DoPendingCopyCB();
		MountPending();

		Idle_DisposeSpeechChannel();
	}

	ReportPendingErrors();
	HandlePendingA2PixConvert();
	IterateCWindows(IdleCB, NULL);
	
	SetStandardCursor(arrowCursor);
}

enum {
	idleEvt = 16, 
	suspendEvt, 
	suspendNoConvEvt, 
	resumeEvt, 
	resumeNoConvEvt, 
	mouseMovedEvt, 
	highLevelEvt = kHighLevelEvent
};

#define	GetOSEvtType(message)	(((message) & osEvtMessageMask) >> 24)
#define	IsResume(message)		(((message) & resumeFlag) != 0)
#define	DontConvert(message)	(((message) & convertClipboardFlag) != 0)

static	short	OSEvtType(EventRecord *theEvent)
{
	short	event	= nullEvent;
	
	switch (GetOSEvtType(theEvent->message)) {

		case suspendResumeMessage: {
			
			if (IsResume(theEvent->message)) {
				event = resumeEvt;
			} else {
				event = suspendEvt;
			}

/*			
			if (DontConvert(theEvent->message)) {
				event++;
			}
*/
			break;
		}
		
		case mouseMovedMessage: {
			event = mouseMovedEvt;
			break;
		}
	}
	
	return event;
}

void		HandleUpdate(EventRecord *theEvent);
void		HandleUpdate(EventRecord *theEvent)
{
	WindowRef	windowRef	= (WindowRef)theEvent->message;
	CWindow		*window		= GetCWindow(windowRef);
	
	if (window) {
		window->Update();
	}
}

Boolean		g_inForeB = TRUE;
Boolean		IsInForeground(void)
{
	return g_inForeB;
}

void	HandleEvent(EventRecord *theEvent)
{
	switch (theEvent->what) {
		
		case idleEvt:
			Idle();
			break;
		
		case highLevelEvt:
			DoHighLevelEvent(theEvent);
			break;
		
		case mouseUp:	
			break;
		
		case mouseDown:
			DoMouseDown(theEvent);
			break;

		case mouseMovedEvt:
			break;
			
		case keyDown:
		case autoKey: {
			DoKeyDown(theEvent);
			break;
		}
		
		case suspendEvt:
		case resumeEvt: {
			CWindow		*window	= GetFrontCWindow();

			if (window) {
				window->ReActivate(theEvent->what == resumeEvt);
			}
			
			g_inForeB = theEvent->what == resumeEvt;
			break;
		}
		
		case activateEvt: {
			WindowRef	windowRef	= (WindowRef)theEvent->message;
			CWindow		*window		= GetCWindow(windowRef);
			
			if (window) {
				window->ReActivate((theEvent->modifiers & activeFlag) != 0);
			}
			break;
		}

		case updateEvt: {
			HandleUpdate(theEvent);
			break;
		}

		case diskEvt: {
			OSErr		err			= HiWord(theEvent->message);
			short		driveNumS	= LoWord(theEvent->message);
				
			err = MountPhysicalFloppy(driveNumS, err);
			break;
		}
		
		default: {
			if (theEvent->what == 16) {
				ReportOSErr(1);
			}
			break;
		}
	}
}

Boolean		HandleOneEvent(long sleep) 
{
	gWasEvent = WaitNextEvent(everyEvent, &gEvent, sleep, NULL);
	
	if (!gWasEvent) {
		gEvent.what = idleEvt;
	} else if (gEvent.what == osEvt) {
		gEvent.what = OSEvtType(&gEvent);
	}

	g_event_levelS++;
	HandleEvent(&gEvent);
	g_event_levelS--;
	
	return gWasEvent;
}

/*
OSStatus SyncLaunchServices( FSRef& inRef ) // Pass in a ref to your app package 
{ 
    OSStatus err; 
    AEDesc finderTarget; 
    AEDesc updateEvent; 
    AliasHandle alias; 

    do { 
        OSType finderSignature = 'MACS'; 
        err = AECreateDesc( typeApplSignature, &finderSignature, sizeof( OSType ), &finderTarget ); 
        if ( err != noErr ) break; 

        // create the appleevent 
        err = AECreateAppleEvent( kAEFinderSuite, kAESync, &finderTarget, kAutoGenerateReturnID, 
                        kAnyTransactionID, &updateEvent ); 
        AEDisposeDesc( &finderTarget ); 
        if (err != noErr) break; 
         
        // Make an alias so that it will work across processes. 
        err = FSNewAliasMinimal( &inRef, &alias ); 
        if (err != noErr) break; 

        HLock( (Handle)alias ); 

        // add the direct parameter 
        err = AEPutParamPtr( &updateEvent, keyDirectObject, typeAlias, *alias, GetHandleSize( (Handle)alias )); 
        if (err != noErr) break; 
         
        DisposeHandle( (Handle)alias ); 

        // send the appleevent 
        err = AESend( &updateEvent, NULL, kAENoReply, kAENormalPriority, kAEDefaultTimeout, NULL, NULL ); 
        if (err != noErr) break; 

        AEDisposeDesc( &updateEvent ) 
    } while (false); 
    return err; 
} 
*/

#ifndef __68k__
static pascal OSStatus	MyAppEventHandler(
	EventHandlerCallRef	myHandlerChain, 
	EventRef			eventRef, 
	void				*userData)
{
	ulong			whatHappened;
	OSStatus		errL = eventNotHandledErr; /* report failure by default */
	EventRecord		eventRec;

	whatHappened = GetEventKind(eventRef);

	switch (whatHappened) {
	
		case kEventVolumeMounted: {
			errL = VolMountEventRefToRec(eventRef, &eventRec);
			
			if (!errL) {
				HandleEvent(&eventRec);
			} else {
				errL = eventNotHandledErr;
			}
			break;
		}

		case kEventMouseWheelMoved: {
			UInt32					modifiers;
			EventMouseWheelAxis		axis;
			SInt32					delta;

			errL = GetEventParameter( eventRef, kEventParamKeyModifiers, typeUInt32, 
				NULL, sizeof(modifiers), NULL, &modifiers );

			if (!errL) errL = GetEventParameter( eventRef, kEventParamMouseWheelAxis, 
				typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis );

			if (!errL) errL = GetEventParameter( eventRef, kEventParamMouseWheelDelta, 
				typeLongInteger, NULL, sizeof(delta), NULL, &delta);

			if (!errL) {
				if (axis == kEventMouseWheelAxisY ) {
					SInt32		deltaPixels = 40 * delta;
					CWindow		*windowP = GetFrontCWindow();

					if (modifiers & optionKey)
						deltaPixels *= 10;
					
					
					if (windowP->i_windowType >= ADFS_Window_DOCUMENT) {
						CDocument		*documentP = (CDocument *)windowP;
						
						documentP->SetScrollOffset(documentP->i_vScrollbar, -deltaPixels);
					}
				}
			}
            break;
        } 
        		case kEventWindowBoundsChanged: {
			UInt32		attributes;

			errL = GetEventParameter(
				eventRef, kEventParamAttributes, typeUInt32,
				NULL, sizeof(UInt32), NULL, &attributes);
				
			if (!errL) {
				WindowRef	windowRef;
				
				if (attributes & kWindowBoundsChangeSizeChanged) {
					errL = GetEventParameter(
						eventRef, kEventParamDirectObject, typeWindowRef,
						NULL, sizeof(WindowRef), NULL, &windowRef);
					
					if (!errL) {
						CWindow		*windowP = GetCWindow(windowRef);
						
						if (windowP) {
							
							switch (windowP->i_windowType) {
							
								case ADFS_Window_DISK_MAP: {
									CDiskMapWindow	*winP = (CDiskMapWindow *)windowP;
									
									winP->UpdateViewAs(TRUE);
									break;
								}

								case ADFS_Window_TEXT:
								case ADFS_Window_GENERATOR: {
									CDocument		*winP = (CDocument *)windowP;
									
									winP->LiveResize();
									break;
								}
							}
						}
					}
				} else {
					errL = eventNotHandledErr;
				}
			} else {
				errL = eventNotHandledErr;
			}
		}
	}
	
	return errL;
}

#define		kCarbonEventsHandled	3
EventTypeSpec   g_appEventList[kCarbonEventsHandled] = {
	{	kEventClassVolume, kEventVolumeMounted			}, 
	{	kEventClassMouse , kEventMouseWheelMoved 		}, 
	{	kEventClassWindow, kEventWindowBoundsChanged	}
};

#endif

#include "CDiskCpm.h"

int main(void) 
{
	if (check_key_down(shift_key)) {
		ADFS_OpenLogFile();
	}

	ADFS_Log("toolbox\n");
	
	InitToolbox();

	ADFS_Log("globals\n");
	
	SetStandardCursor(watchCursor);
	
	if (InitGlobals()) {	// if we succeeding in initting self
		
		if (!gHasAppleEvents) {
			ErrorAlert(kErrStringID, kCantRunErr, 0);
		} else {
			ADFS_Log("apple events\n");
			InitAEVTStuff();
						
			#ifndef __68k__
				InstallApplicationEventHandler(
					NewEventHandlerUPP(MyAppEventHandler), 
					kCarbonEventsHandled, g_appEventList, 0, NULL); 
			#endif
			
			while (!gDone) {
				HandleOneEvent(10);
				
				if (gDone && !CloseAllCWindows()) {
					gDone = FALSE;
				}
			}
		}
		
		DisposeUserGlobals();	// call the userproc to clean itself up
	}
	
	ExitToShell();
	return 0;
}

