#include "allegro.h"
#include "allegro/internal/aintern.h"
#include "allegro/platform/aintosx.h"

#include <CoreFoundation/CoreFoundation.h>
#include <mach/mach_port.h>
#include <servers/bootstrap.h>

extern int    __crt0_argc;
extern char **__crt0_argv;
extern NSBundle *osx_bundle;
extern void* osx_event_mutex;
extern NSCursor *osx_cursor;
extern NSCursor *osx_blank_cursor;
extern AllegroWindow *osx_window;
extern void (*osx_window_close_hook)(void);
extern int osx_gfx_mode;
extern int osx_emulate_mouse_buttons;
extern int osx_window_first_expose;

@interface MyApp : NSApplication
@end

/* the run method doesnt do anything really except create a mutex that
 * is used in other places. The "run" loop is implemented by repeated
 * calls to the update() method below. This can be done from mzscheme
 * or from a thread spawned in the C code.
 */
@implementation MyApp
- (void) run
{
   osx_event_mutex=_unix_create_mutex();
   [self finishLaunching];
   // printf( "App finished launching\n" );
}

/* i dont know what this does but I guess its important */
- (void)applicationDidChangeScreenParameters: (NSNotification *)aNotification
{
   CFDictionaryRef mode;
   int new_refresh_rate;
   
   if ((osx_window) && (osx_gfx_mode == OSX_GFX_WINDOW)) 
   {
      osx_setup_colorconv_blitter();
      [osx_window display];
   }
   /*
   mode = CGDisplayCurrentMode(kCGDirectMainDisplay);
   CFNumberGetValue(CFDictionaryGetValue(mode, kCGDisplayRefreshRate), kCFNumberSInt32Type, &new_refresh_rate);
   if (new_refresh_rate <= 0)
      new_refresh_rate = 70;
   refresh_rate = new_refresh_rate;
   */
}

/* method for just polling the event queue */
- (void) update_event
{
	_unix_lock_mutex(osx_event_mutex);
	osx_event_handler();
	_unix_unlock_mutex(osx_event_mutex);
}

/* method for just updating the screen. theoretically this only
 * needs to be called after the screen is modified via some draw function
 * or a blit( screen, ... ). If updating the screen is slow then it
 * shouldnt be updated in the same function as polling the event queue
 * which is why the two functions are split up
 */
- (void) update_screen
{
	if (osx_gfx_mode == OSX_GFX_WINDOW)
		osx_update_dirty_lines();
	_unix_lock_mutex(osx_event_mutex);
	if (osx_gfx_mode == OSX_GFX_FULL) {
		if ((osx_palette) && (osx_palette_dirty)) {
			CGDisplaySetPalette(kCGDirectMainDisplay, osx_palette);
			osx_palette_dirty = FALSE;
		}
	}
	_unix_unlock_mutex(osx_event_mutex);
}

// - (void) update: ( NSTimer *)  timer
/* update the event queue and the screen in the same function */
- (void) update
{
	// printf( "Update\n" );
	/*
	struct timeval time;
	gettimeofday( &time, NULL );
	printf( "Time = %d\n", time.tv_usec );
	*/
	if (osx_gfx_mode == OSX_GFX_WINDOW)
		osx_update_dirty_lines();
	_unix_lock_mutex(osx_event_mutex);
	if (osx_gfx_mode == OSX_GFX_FULL) {
		if ((osx_palette) && (osx_palette_dirty)) {
			CGDisplaySetPalette(kCGDirectMainDisplay, osx_palette);
			osx_palette_dirty = FALSE;
		}
	}
	osx_event_handler();
	_unix_unlock_mutex(osx_event_mutex);
}
@end

/* set the name of the program to 'mzscheme' and set up the NSApplication
 * to make Cocoa happy
 */
void osx_startup( const char * name ){
	__crt0_argv = (char **)malloc( sizeof(char*) );
	__crt0_argv[ 0 ] = name;
	osx_bootstrap_ok();
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	[MyApp sharedApplication];
	[NSApp run];
}

/* helper functions to call the update methods */
void osx_update_event(){
	[NSApp update_event];
}

void osx_update_screen(){
	[NSApp update_screen];
}

void osx_update(){
	// printf( "osx_update\n" );
	[NSApp update];
}

/* try to schedule the update method to be called repeatedly by Cocoa itself.
 * this doesnt really work since we took over the run method so Cocoa doesnt
 * get a chance to perform its own functions, such as calling timers
 */
void osx_begin_update() {
	printf( "Begin updating\n" );
	[NSTimer scheduledTimerWithTimeInterval: 1.0/70.0 target: NSApp selector: @selector(update:) userInfo: nil repeats: YES];
}
