// GigEApp.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include <dshow.h>
#include <commctrl.h>
#include "commdlg.h"
#include "globals.h"
#include "GigEApp.h"
#include <CySimpleBuffer.h>
#include <CyXMLDocument.h>
#include <CyGrabber.h>
#include "buffer.h"
#include "display.h"
#include "camcontroller.h"
#include "config.h"
#include "lut.h"
#include <stdlib.h>
#include <crtdbg.h>
#include "prefsXML.h"
#include "plathread.h"
#include "assert.h"
#include "filetype.h"
#include "project.h"
#include "playwnd.h"
#include "uimanager.h"
#include "giged3d.h"
#include "sivpe.h"
#include "lut3d.h"
#include "voicerecording.h"
#include "uimacro.h"
#include "macro.h"
#include "simenmonitor.h"
#include "logger.h"
#include "config.h"
#include "globals.h"
#include "siblist.h"
#include "timeline.h"
#include "devicemanager.h"
#include "memorymanager.h"
#include "diskinfo.h"
#include "rawserializer.h"
#include "datetimeutils.h"
#include "slate.h"
#include "timecodecontroller.h"
#include "avilibrary\avistrfv.h"
#include "asyncfilewriter.h"
#include "sdithread.h"
#include "oglthread.h"
#include "winio.h"
#include "sicmdllensdata.h"

#define LOSSLESS_HACK

#define MAX_LOADSTRING 100

#define DEBUG_LEVEL 2

// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name
HGLRC gRC;
HMENU gMenuHandle;
CUIManager *gUIManager = NULL;
CUIScreen *gUIScreen = NULL;
CUtils * gUtils = NULL;
int gLockCompression = 0;

int gAnchorX = 0;
int gAnchorY = 0;
int SilentFanTimer = 0;

// Forward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK	WndProc2(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
void LoadIridas( void );

void OnStartGrabbing( void );
void OnStopRecording( void );
void OnDetectDeviantPixels( HWND hWnd );
void OnOpenProject( HWND hWnd );

extern void OnNoBuffers(void);
extern void OnLostConnection( int cam );
void SetFullScreenMode(void);
extern void printDualRings(char *msg);

DWORD gProgramStateFlags = 0;
bool KeyStates[256];
extern void UtilGetProgramDir( char *inText );

// singletons
CConfig gConfig;
CDisplay gDisplay;
CAudioPlayback * gAudioPlayback = NULL;
CPlayWnd gPlayWnd;
CSibList *gSibList = NULL;
CSIDSMediaFilePlayer  *gSIPlayer;
CTimeline gTimeline;
CDiskInfo gDiskInfo;
CSlate gSlate;
extern HANDLE gShoSignal;
extern HANDLE gDrawnSignal;
extern HANDLE gDuoSignal;

CTimecodeController gTimecodeController;

static int gFanSpeed = -1;
int monitorWidths[ 8 ];
int gDeltaBad = 0;
int gDeltaTotal = 0;


void SetMiniGuiParams(DWORD width)
{
	Globals.mMiniGuiMag = 1280.0f / (float) width;
	Globals.mMiniGuiMin = (float) width / 1280.0f;
	Globals.mMiniGuiWidth = width;
	Globals.mMiniGuiHeight = Globals.mMiniGuiWidth * 9 / 16;
	Globals.mMiniGuiImageX = (float) UI_IMAGE_X * Globals.mMiniGuiMin + 0.5f;
	Globals.mMiniGuiImageY = (float) UI_IMAGE_Y * Globals.mMiniGuiMin;
	Globals.mMiniGuiImageW = (float) UI_IMAGE_W * Globals.mMiniGuiMin + 0.5f;
	Globals.mMiniGuiImageH = (float) UI_IMAGE_H * Globals.mMiniGuiMin + 0.95f;
}


void CheckMEN()
{
	int result = SI_OpenCPUCoreDevice();
	if ( result < 0 )
		gLogger.info(0, "SI_OpenCPUCoreDevice Failed! result %d\n",result );
    else
    {
  		gLogger.info(0, "SI_OpenCPUCoreDevice succeeded.\n");
      	int coreTemp;
        result = SI_ReadCPUCoreTemp( &coreTemp );
        if ( result >= 0 )
        {
       		Globals.checkTemp(true);
            gLogger.info(0, "SI_ReadCPUCoreTemp succeeded: check temp is OK.\n");
        }
        else
            gLogger.info(0, "SI_ReadCPUCoreTemp failed: will not check temp.\n");
    }

    Globals.isMen(false);
    gLogger.info(0, "about to SI_CheckForMEN...\n");
    if ( SI_CheckForMEN() < 0 )
    {
        gLogger.info(0, "   SI_CheckForMEN returned -1.\n");
        return;
    }
    gLogger.info(0, "   SI_CheckForMEN succeeded.\n");

	result = SI_OpenLM63Device();
	if ( result < 0 )
    {
		gLogger.info(0, "SI_OpenLM63Device failed.\n" );
        return;
    }
    gLogger.info(0, "SI_OpenLM63Device succeeded.\n" );
	result = SI_OpenSMB2Device();
	if ( result < 0 )
    {
		gLogger.info(0, "SI_OpenSMB2Device failed.\n" );
        return;
    }
    gLogger.info(0, "SI_OpenSMB2Device succeeded.\n" );
    Globals.isMen(true);
    gLogger.info(0, "Setting isMen to true.\n" );
}

bool SetPrivs()
{
    TOKEN_PRIVILEGES tp;
    LUID luid;
    LPCTSTR lpszPrivilege = SE_MANAGE_VOLUME_NAME;
    HANDLE hToken;
    if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hToken))
    {
        return false;
    }
    if ( !LookupPrivilegeValue(
        NULL, // lookup privilege on local system
        lpszPrivilege, // privilege to lookup
        &luid ) ) // receives LUID of privilege
    {
        return false;
    }
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
     
    if ( !AdjustTokenPrivileges(
        hToken,
        FALSE,
        &tp,
        sizeof(TOKEN_PRIVILEGES),
        (PTOKEN_PRIVILEGES) NULL,
        (PDWORD) NULL) )
    {
        return false;
    }
    CloseHandle(hToken);
    return true;
}
 



char * GetSystemTimeString()
{
	static char str[128];
	// Retrieves the current system date and time. The system 
	// time is expressed in Coordinated Universal Time (UTC). 
	SYSTEMTIME systime;
	GetSystemTime( &systime );

	wsprintf( str, "%02d-%02d-%02d %02d:%02d:%02d:%u",
	systime.wYear, systime.wMonth, systime.wDay,
	systime.wHour, systime.wMinute, systime.wSecond, systime.wMilliseconds );
	return str;
}



BOOL CALLBACK MyMonitorEnumProc(
  HMONITOR hMonitor,  // handle to display monitor
  HDC hdcMonitor,     // handle to monitor DC
  LPRECT lprcMonitor, // monitor intersection rectangle
  LPARAM dwData       // data
)
{
    if ( gConfig.mNumMonitors == 2 ) return TRUE;
	gConfig.mMonitorX[gConfig.mNumMonitors] = lprcMonitor->left;
	gConfig.mMonitorY[gConfig.mNumMonitors] = lprcMonitor->top;
	gConfig.mMonitorW[gConfig.mNumMonitors] = lprcMonitor->right - lprcMonitor->left;
	gConfig.mMonitorH[gConfig.mNumMonitors] = lprcMonitor->bottom - lprcMonitor->top;
    gLogger.info(DEBUG_LEVEL,"MyMonitorEnumProc left %d right %d top %d %d bottom\n",
    	lprcMonitor->left,
    	lprcMonitor->right,
    	lprcMonitor->top,
    	lprcMonitor->bottom);
	gConfig.mNumMonitors++;

	/*if ( gConfig.mMonitorW[0] > GIGAPP_APP_WIDTH )
	{
		Globals.mMainGuiMag2 = ( float ) gConfig.mMonitorW[0] / GIGAPP_APP_WIDTH;
	}
	else
	{
		Globals.mMainGuiMag2 = 1.0f;
	}

	if ( gConfig.mNumMonitors == 1 )
	{
		if ( gPrefs.GetMode800() )
			SetMiniGuiParams( gPrefs.GetMode800() );
		if ( !gPrefs.GetMode800() )
		{
			gConfig.mAppOffsetX = ( float ) gConfig.mMonitorW[0]/2 - GIGAPP_APP_WIDTH/2;
			gConfig.mAppOffsetY = ( float ) gConfig.mMonitorH[0]/2 - GIGAPP_APP_HEIGHT/2;
			Globals.SetGeometry( GEOMETRY_1280 );
		}
		else
		{
			gConfig.mAppOffsetX = ( float ) gConfig.mMonitorW[0]/2 - Globals.mMiniGuiWidth/2;
			gConfig.mAppOffsetY = ( float ) gConfig.mMonitorH[0]/2 - Globals.mMiniGuiHeight/2;
			Globals.SetGeometry( GEOMETRY_800 );
		}
		
		gConfig.mAppFullX = 0;
		gConfig.mAppFullW = ( float ) gConfig.mMonitorW[0];
		gConfig.mAppFullH = ( float ) gConfig.mMonitorW[0] * 9 / 16;
		gConfig.mAppFullY = ( gConfig.mMonitorH[0] - gConfig.mAppFullH ) / 2;
		gConfig.mAppFullOffsetY = ( float ) gConfig.mAppFullY * 2;


	}*/
	return TRUE;
}

void CheckCursor( void )
{
	if ( Globals.GetMouseActive() )
	{
		if ( GetTickCount() > Globals.GetMouseTicks() + 5000 )
		{
			Globals.SetMouseActive( FALSE );
			ShowCursor( FALSE );
		}
	}
}

void CheckIridas( void )
{
	if ( !gIridas )
		return;
	
	if ( !gIridas->mTrackballOn )
		return;

	POINT point;
	GetCursorPos( &point );
	if ( point.x == gAnchorX && point.y == gAnchorY )
		return;

	int dx = point.x - gAnchorX;
	int dy = point.y - gAnchorY;
	if ( gPrefs.GetMode800() )
	{
		dx = (float) dx * Globals.mMiniGuiMag;
		dy = (float) dy * Globals.mMiniGuiMag;
	}

	gIridas->UpdateTrackball( dx, dy );

	SetCursorPos( gAnchorX, gAnchorY );
}

void CheckZoom(void)
{
	if ( !Globals.GetZoomTicks() ) return;

	if ( isProgramPlayingSIV() || isProgramPlayingAVI() )
	{
		InvalidateRect( Globals.hwnd, NULL, false );
		/*if ( gPrefs.GetOpenGL() )
		{
			if ( gOglThread != NULL )
			{
				gOglThread->mDoPaint = true;
				SetEvent(gOglSignal);
			}
		}*/
	}
}

void CheckWhiteBalance()
{
	if ( ! gUIScreen->mUserWBDialog )
		return;

	if ( ! gUIScreen->mUserWBDialog->mTrackballOn )
		return;

	POINT point;
	GetCursorPos( &point );
	if ( point.x == gAnchorX && point.y == gAnchorY )
		return;

	int dx = point.x - gAnchorX;
	int dy = point.y - gAnchorY;
	if ( gPrefs.GetMode800() )
	{
		dx = (float) dx * Globals.mMiniGuiMag;
		dy = (float) dy * Globals.mMiniGuiMag;
	}

	gUIScreen->mUserWBDialog->UpdateTrackball( dx, dy );

	SetCursorPos( gAnchorX, gAnchorY );
}

/*void PrecacheCineformSDK()
{
    if ( !gProject ) return;

    DWORD w = 1280;
    DWORD h = 720;
    char filename[256];
	ProjectSetName( filename, FILE_TYPE_MOV, 0, false );
    int scale = (int)( 1000.0 * FramerateInfo[CAMFRAMERATE_24].framesPerSecond + 0.5 );
	int quality = gPrefs.GetLogicalCineformQuality();

    CSMPTE tc;
    CCineformSDK *cineformSDK = new CCineformSDK(&FramerateInfo[CAMFRAMERATE_24],&FramerateInfo[CAMFRAMERATE_24]);
    cineformSDK->SetupFile(filename, w, h, quality, false, 1, scale, true);
    cineformSDK->startTimecode( tc );

    DWORD size = w * h * 3 / 2;
    CBufferInfo *bufferInfo = new CBufferInfo(PREFS_RECORD_FORMAT_LINEAR12, size, 313, false);
    unsigned char *data = bufferInfo->GetBuffer()->GetBuffer();
    memset(data,0,size);

    int numFrames = 12;
    for ( int i = 0; i < numFrames; i++ )
    {
        SHOThread::ConvertLinear12ToLog84( w, h, data );
        cineformSDK->SendBitmap(bufferInfo, w*3/2, NULL );
    }
    cineformSDK->End(&tc, false);
    delete cineformSDK;
    filename[strlen(filename)-1] = 'v';
    BOOL res = DeleteFile(filename);
    delete bufferInfo;
}*/

const int FixedLowTempThresh  = 80;
const int FixedHighTempThresh = 90;
const int HysBand = 1;   // hysteresis value
int PrevRange = 2;
int DynLowTempThresh = FixedLowTempThresh;
int DynHighTempThresh = FixedHighTempThresh;

void ReinitTemperature(void)
{
    PrevRange = 2;
    DynLowTempThresh = FixedLowTempThresh;
    DynHighTempThresh = FixedHighTempThresh;
}

void TemperatureTask( int CPUTemp )
{
	gLogger.info( 1, "TemperatureTask: Core Temp %d Before FS %d PR %d ", CPUTemp, gFanSpeed, PrevRange );

	if ( isProgramRecording() )
	{
		gLogger.info( 1, "   IS RECORDING speed is %d, core temp is %d.\n", gFanSpeed, CPUTemp );
		if ( gFanSpeed != 0 && CPUTemp < FixedHighTempThresh )
		{
			gLogger.info( 1, "   set fan speed 0.\n" );
			gFanSpeed = 0;

			if ( Globals.IsMinideck() )
			{
				out( INDEX, 0x3 );
				out( DATA, 0x20 );  // low fan speed
				gLogger.info( 1, "Set WINIO fan speed low\n" );
			}
			else
			{
				SI_SetSMB2FanSpeed( gFanSpeed );
			}
		}
		else if ( gFanSpeed != 1 && CPUTemp >= FixedHighTempThresh )
		{
			gLogger.info(1, "   set fan speed 1.\n" );
			gFanSpeed = 1;

			if ( Globals.IsMinideck() )
			{
				out( INDEX, 0x3 ); 
				out( DATA,  0xBF ); // medium fan speed
				gLogger.info( 1, "Set WINIO fan speed medium\n" );
			}
			else
			{
				SI_SetSMB2FanSpeed( gFanSpeed );
			}
		}
	}
	else if ( CPUTemp >= DynHighTempThresh )  // high range
	{
		if ( PrevRange != 2 )
		{
			// Change fan speed to high
			gFanSpeed = 2;
			if ( Globals.IsMinideck() )
			{
				out( INDEX, 0x3 ); 
				out( DATA,  0xFF ); // high fan speed
				gLogger.info( 1, "Set WINIO fan speed high\n" );
			}
			else
			{
				SI_SetSMB2FanSpeed( gFanSpeed );
			}

			if (DynHighTempThresh == FixedHighTempThresh)
				DynHighTempThresh = FixedHighTempThresh - HysBand;
			else
				DynHighTempThresh = FixedHighTempThresh;
			PrevRange = 2;
		}
		if (CPUTemp > FixedHighTempThresh + HysBand)
			DynHighTempThresh = FixedHighTempThresh;
	}
	else if (CPUTemp >= DynLowTempThresh && CPUTemp < DynHighTempThresh) // mid range
	{					
		if (PrevRange != 1)
		{
			// Change fan speed to medium
			gFanSpeed = 1;
			if ( Globals.IsMinideck() )
			{
				out( INDEX, 0x3 ); 
				out( DATA,  0xBF ); // medium fan speed
				gLogger.info( 1, "Set WINIO fan speed medium\n" );
			}
			else
			{
				SI_SetSMB2FanSpeed( gFanSpeed );
			}
			
			if (PrevRange == 2)
			{
				if (DynHighTempThresh == FixedHighTempThresh)
					DynHighTempThresh = FixedHighTempThresh + HysBand;
				else
					DynHighTempThresh = FixedHighTempThresh;
			}
			if (PrevRange == 0)
			{
				if (DynLowTempThresh == FixedLowTempThresh)
					DynLowTempThresh = FixedLowTempThresh - HysBand;
				else
					DynLowTempThresh = FixedLowTempThresh;
			}					
			PrevRange = 1;

		}

		if (CPUTemp > FixedLowTempThresh + HysBand)
			DynLowTempThresh = FixedLowTempThresh;

		if (CPUTemp < FixedHighTempThresh - HysBand)
			DynHighTempThresh = FixedHighTempThresh;				
	}
	else   //low range
	{				
		if (PrevRange != 0)
		{
			// Change fan speed to low
			gFanSpeed = 0;
			if ( Globals.IsMinideck() )
			{
				out( INDEX, 0x3 );
				out( DATA, 0x20 );  // low fan speed
				gLogger.info( 1, "Set WINIO fan speed low\n" );
			}
			else
			{
				SI_SetSMB2FanSpeed( gFanSpeed );
			}

			if (DynLowTempThresh == FixedLowTempThresh)
				DynLowTempThresh = FixedLowTempThresh + HysBand;
			else
				DynLowTempThresh = FixedLowTempThresh;
			PrevRange = 0;
		}

		if (CPUTemp < FixedLowTempThresh - HysBand)
			DynLowTempThresh = FixedLowTempThresh;
	}		
	gLogger.info(1, "After FS %d PR %d\n",gFanSpeed,PrevRange );
}


void CheckDisk( bool force )
{
	static DWORD lastTicks = 0;

	if ( !gProject ) return;

	DWORD ticks = GetTickCount();
    if ( !force )
    {
	    if ( isProgramWriting() )
	    {
		    if ( ticks < lastTicks + 2000 )
			    return;
	    }
	    else
	    {
		    if ( ticks < lastTicks + 5000 )
			    return;
	    }
    }

	lastTicks = ticks;

    for ( int i = 0; i < gDiskInfo.numDrives(); i++ )
    {
	    ULARGE_INTEGER FreeBytesAvailable;
	    ULARGE_INTEGER TotalNumberOfBytes;
	    BOOL res = GetDiskFreeSpaceEx(
		    gDiskInfo.mDrives[i],
		    &FreeBytesAvailable,
		    &TotalNumberOfBytes,
		    NULL
	    );

    	if ( !res  ) return;

	    gDiskInfo.mDiskFreeMB[i]  = (float) FreeBytesAvailable.HighPart * 4096;
	    gDiskInfo.mDiskFreeMB[i] += FreeBytesAvailable.LowPart / (1024 * 1024);
	    gDiskInfo.mDiskTotalMB[i]  = (float) TotalNumberOfBytes.HighPart * 4096;
	    gDiskInfo.mDiskTotalMB[i] += TotalNumberOfBytes.LowPart / (1024 * 1024);
	    gDiskInfo.mDiskPct[i] = 100.0f - gDiskInfo.mDiskFreeMB[i] * 100.0f / gDiskInfo.mDiskTotalMB[i];

		int remainingSpace = 0;

		if ( ! isProgramRecording() )
		{
			remainingSpace = 4096;
		}
		else
		{
			remainingSpace = 2048;
		}

	    if ( gDiskInfo.mDiskFreeMB[i] < remainingSpace )
	    {
    		if ( ! Globals.GetDriveFull() )
	    	{
		    	Globals.SetDriveFull( true );
			    if ( isProgramRecording() )
			    {
				    Globals.SetPolledEvent( POLLED_EVENT_DRIVEFULL );
    		    }
		    }
	    }
	    else
		    Globals.SetDriveFull( false );
    }

}

void CheckTemperature( bool force )
{
	static int iter = -1;
	int result;

	if ( !Globals.checkTemp() ) return;

	// only do once every 5 seconds, i.e., every 50 timer events
	if ( !force )
	{
		iter++;
		if ( iter % (5000/TIMER_MS) ) 
			return;
	}

	// Silent mode overrides fan mode set in preferences
	if ( Globals.GetSilentFanMode() )
	{
		SilentFanTimer += 1;

		gLogger.info( 1, "%d   CheckTemperature silent fan timer %d\n", GetTickCount(), SilentFanTimer );

		gFanSpeed = 0;

		if ( Globals.IsMinideck() )
		{
			out( INDEX, 0x3 );
			out( DATA, 0x20 );  // low fan speed
		}
		else
		{
			SI_SetSMB2FanSpeed( gFanSpeed );
		}

		if ( SilentFanTimer > 12 )
		{
			Globals.SetSilentFanMode( false );
			SilentFanTimer = 0;
		}
		return;
	}


	int coreTemp;
	result = SI_ReadCPUCoreTemp( &coreTemp );

	if ( result < 0 )
	{
		gLogger.info(1, "SI_ReadCPUCoreTemp Failed!!!!! result %d\n",result );
		Globals.SetTemperature(-1);
	}
	else
	{
		Globals.SetTemperature( coreTemp );
	}

	
	if ( Globals.IsMinideck() )
	{
		DWORD fanSpeed = 0;
		out( INDEX, 0x29 );
		in( DATA, fanSpeed ); // CPU FAN 0
		float fs = 1.35 * 100000 / ( fanSpeed * 2 ); 
		gLogger.info( 1, "WINIO fan speed %f\n", fs );
	}
	
    if ( ! Globals.isMen() && ! Globals.IsMinideck() ) return;

	if ( gPrefs.GetFanMode() == 1 )
	{
		gLogger.info(1, "%s   FAN MODE 1 time %d seconds\n",Globals.GetPrettyHighResClockString(),iter / 10 );

		if ( ( Globals.isMen() ) || ( Globals.IsMinideck() ) )
		{
			TemperatureTask( coreTemp );
		}
	}
	else if ( gPrefs.GetFanMode() == 2 )
	{
		gLogger.info( 1, "%s   FAN MODE 2 time %d seconds\n", Globals.GetPrettyHighResClockString(), iter / 10 );
		//
		// Do Fan Mode 2 stuff;
		//
		if ( isProgramRecording() )
		{
			gLogger.info( 1, "   IS RECORDING speed is %d, core temp is %d.\n", gFanSpeed, coreTemp );
			if ( gFanSpeed != 0 && coreTemp < 90 )
			{
				gLogger.info( 1, "   set fan speed 0.\n" );
				gFanSpeed = 0;

				if ( Globals.IsMinideck() )
				{
					out( INDEX, 0x3 );
					out( DATA, 0x20 );  // low fan speed
					gLogger.info( 1, "Set WINIO fan speed low\n" );
				}
				else
				{
					SI_SetSMB2FanSpeed( gFanSpeed );
				}
			}
			else if ( gFanSpeed != 1 && coreTemp >= 90 )
			{
				gLogger.info(1, "   set fan speed 1.\n" );
				gFanSpeed = 1;

				if ( Globals.IsMinideck() )
				{
					out( INDEX, 0x3 ); 
					out( DATA,  0xBF ); // medium fan speed
					gLogger.info( 1, "Set WINIO fan speed medium\n" );
				}
				else
				{
					SI_SetSMB2FanSpeed( gFanSpeed );
				}
			}
		}
		else
		{
			gLogger.info( 1, "   IS NOT RECORDING speed is %d, core temp is %d.\n", gFanSpeed, coreTemp );
			if ( gFanSpeed != 2 )
			{
				gLogger.info( 1, "   set fan speed 2.\n" );
				gFanSpeed = 2;

				if ( Globals.IsMinideck() )
				{
					out( INDEX, 0x3 ); 
					out( DATA,  0xFF ); // high fan speed
					gLogger.info( 1, "Set WINIO fan speed high\n" );
				}
				else
				{
					SI_SetSMB2FanSpeed( gFanSpeed );
				}
			}
		}
	}
	else if ( gPrefs.GetFanMode() == 3 )
	{
		gLogger.info( 1, "FAN MODE 3 time %d seconds\n", iter / 10 );
		if ( gFanSpeed != 2 )
		{
			gLogger.info( 1, "   FORCE fan speed 2.\n" );
			gFanSpeed = 2;
			
			if ( Globals.IsMinideck() )
			{
				out( INDEX, 0x3 ); 
				out( DATA,  0xFF ); // high fan speed
				gLogger.info( 1, "Set WINIO fan speed high\n" );
			}
			else
			{
				SI_SetSMB2FanSpeed( gFanSpeed );
			}
		}
	}
	else
	{
		gLogger.info(1, "UNKNOWN FAN MODE 1 %d",gPrefs.GetFanMode() );
	}

	if ( ! Globals.isMen() ) return;

	if ( ( iter % (60000/TIMER_MS) ) == 0 ) 
	{
		bool batteryLow;
		int res = SI_CheckSMB2BatteryLevel(&batteryLow);
		if ( !res )
		{
			if ( batteryLow )
				Globals.SetBatteryLow( true );
			else
				Globals.SetBatteryLow(false);
			gLogger.info(1, "Battery Low = %d\n",batteryLow );
		}
	}
	gLogger.info(1, "CheckTemperature done\n");
}



VOID CALLBACK HandleTimer(          
	HWND hwnd,
    UINT uMsg,
    UINT_PTR idEvent,
    DWORD dwTime )
{
	//doSDI();
	while ( Globals.GetPolledEvents() )
	{
		if ( Globals.GetPolledEvents() & POLLED_EVENT_SETBLACK )
		{
			Globals.ClearPolledEvent( POLLED_EVENT_SETBLACK);
			if ( !isProgramRecording() )
				OnSetBlack(0,0);
		}
		
		if ( Globals.GetPolledEvents() & POLLED_EVENT_RECONNECT_CAM_0 )
		{
			gLogger.info( 1, "%d   Timer: got POLLED_EVENT_RECONNECT CAM 0 event\n",GetTickCount());
			Globals.ClearPolledEvent( POLLED_EVENT_RECONNECT_CAM_0 );
			OnReconnect( 0 );
		}
		if ( Globals.GetPolledEvents() & POLLED_EVENT_RECONNECT_CAM_1 )
		{
			gLogger.info( 1, "%d   Timer: got POLLED_EVENT_RECONNECT CAM 1 event\n",GetTickCount());
			Globals.ClearPolledEvent( POLLED_EVENT_RECONNECT_CAM_1 );
			OnReconnect( 1 );
		}

		if ( Globals.GetPolledEvents() & POLLED_EVENT_DRIVEFULL )
		{
			Globals.ClearPolledEvent(POLLED_EVENT_DRIVEFULL);
			if ( isProgramRecording() )
			{
				gUIManager->mScreen->StopRecording();
			}
		}
		if ( Globals.GetPolledEvents() & POLLED_EVENT_DELETEBLACK )
		{
			Globals.ClearPolledEvent( POLLED_EVENT_DELETEBLACK );
			delete gUIManager->mScreen->mBlackDialog;
			gUIManager->mScreen->mBlackDialog = NULL;
			InvalidateRect( Globals.hwnd, NULL, false );
		}
		if ( Globals.GetPolledEvents() & POLLED_EVENT_DELETERECONNECT )
		{
			Globals.ClearPolledEvent( POLLED_EVENT_DELETERECONNECT );
			delete gUIManager->mScreen->mCamConnectionDlg;
			gUIManager->mScreen->mCamConnectionDlg = NULL;
			InvalidateRect( Globals.hwnd, NULL, false );
		}
		if ( Globals.GetPolledEvents() & POLLED_EVENT_DELETEIRIDAS )
		{
			Globals.ClearPolledEvent(POLLED_EVENT_DELETEIRIDAS);
			gUIManager->mScreen->SetVideoDisplayMode( (EVideoDisplayMode) gIridas->mOldVideoDisplayMode );
			gDisplay.ResetImageCoordinates();
			delete gIridas;
			gIridas = NULL;
			Globals.SetIridasOn( false );

			InvalidateRect( Globals.hwnd, NULL, false );
		}
		if ( Globals.GetPolledEvents() & POLLED_EVENT_DELETEFILEDIALOG )
		{
			Globals.ClearPolledEvent(POLLED_EVENT_DELETEFILEDIALOG);
			gUIManager->mScreen->CloseFileDialog();
			InvalidateRect( Globals.hwnd, NULL, false );
		}
		if ( Globals.GetPolledEvents() & POLLED_EVENT_DELETEMACROLISTDIALOG )
		{
			Globals.ClearPolledEvent(POLLED_EVENT_DELETEMACROLISTDIALOG);
			gUIManager->mScreen->CloseMacroListDialog();
			InvalidateRect( Globals.hwnd, NULL, false );
		}
		if ( Globals.GetPolledEvents() & POLLED_EVENT_DELETEMESSAGEBOX )
		{
			Globals.ClearPolledEvent(POLLED_EVENT_DELETEMESSAGEBOX);
			delete gUIManager->mScreen->mMessageBox;
			gUIManager->mScreen->mMessageBox = NULL;
			InvalidateRect( Globals.hwnd, NULL, false );
		}
		if ( Globals.GetPolledEvents() & POLLED_EVENT_DELETELOOKDIALOG )
		{
			Globals.ClearPolledEvent(POLLED_EVENT_DELETELOOKDIALOG);
			delete gLookDialog;
			gLookDialog = NULL;

			// Update the LOOK panel
			if ( gPrefs.GetPreviewLookActive() )
			{
				gUIManager->UpdateLookButtonStates( gPrefs.GetViewLook() );
			}
			else
			{
				gUIManager->UpdateLookButtonStates( gPrefs.GetRecordLook() );
			}
			InvalidateRect( Globals.hwnd, NULL, false );
		}
		if ( Globals.GetPolledEvents() & POLLED_EVENT_DELETEMACRODIALOG )
		{
			Globals.ClearPolledEvent(POLLED_EVENT_DELETEMACRODIALOG);
			delete gMacroDialog;
			gMacroDialog = NULL;
			InvalidateRect( Globals.hwnd, NULL, false );
		}
		if ( Globals.GetPolledEvents() & POLLED_EVENT_NOBUFFERS )
		{
			Globals.ClearPolledEvent(POLLED_EVENT_NOBUFFERS);
            //gLogger.info(0,"%d   CLEARING POLLED_EVENT_NOBUFFERS about to gConfig.StopGrabbing\n", GetTickCount());
			OnNoBuffers();
		}
		if ( Globals.GetPolledEvents() & POLLED_EVENT_FILEIOERROR )
		{
            gLogger.info(0,"%d   CLEARING POLLED_EVENT_FILEIOERROR.\n", GetTickCount());
			gUIScreen->FileIOError();
			Globals.ClearPolledEvent( POLLED_EVENT_FILEIOERROR );
            gUIScreen->StopRecording();
		}

		if ( Globals.GetPolledEvents() & POLLED_EVENT_LOSTCONNECTION_CAM_0 )
		{
			gLogger.info( 1, "%d   Timer: got LOSTCONNECTION CAM 0 event A\n",GetTickCount());
			Globals.ClearPolledEvent( POLLED_EVENT_LOSTCONNECTION_CAM_0 );
			if ( !isProgramRecording() ) 
			{
			    gLogger.info( 1, "%d   Timer: got LOSTCONNECTION CAM 0 event B\n",GetTickCount());
				gConfig.StopGrabbing( true, false );
    			gLogger.info( 1, "%d   Timer: got LOSTCONNECTION CAM 0 event C\n",GetTickCount());
				gConfig.Clear( false );
				Globals.SetPolledEvent( POLLED_EVENT_RECONNECT_CAM_0 );
			}
			else
			{
				OnLostConnection( 0 );
			}
		}

		if ( Globals.GetPolledEvents() & POLLED_EVENT_NONSYNCED_CAMERAS )
		{
			Globals.ClearPolledEvent( POLLED_EVENT_NONSYNCED_CAMERAS );
			if ( isProgramRecording() ) 
            	gUIScreen->StopRecording();
	        gConfig.StopGrabbing(false,false);
		}

		if ( Globals.GetPolledEvents() & POLLED_EVENT_GPIO_BIT0 )
		{
			gLogger.info( 1, "%d   Timer: got POLLED_EVENT_GPIO_BIT0 event C\n",GetTickCount() );
			Globals.ClearPolledEvent(POLLED_EVENT_GPIO_BIT0);

			switch ( gPrefs.GetGPIOMapping() )
			{
				case GPIO_MODE_RECORD:
					OnRecordClick( 0, 0 );
					break;
				case GPIO_MODE_RIGHT_CLICK:
					gUIManager->OnRightClick();
					break;
			}
			InvalidateRect( Globals.hwnd, NULL, false );
		}

		if ( Globals.GetPolledEvents() & POLLED_EVENT_DONESAVETHREAD )
		{
			Globals.ClearPolledEvent(POLLED_EVENT_DONESAVETHREAD);
			gConfig.DeleteSaveThread();
			gUIScreen->mSaveButton->SetHighlight( false );
			InvalidateRect( Globals.hwnd, NULL, false );
		}
		if ( Globals.GetPolledEvents() & POLLED_EVENT_DONEBLACKTHREAD )
		{
			Globals.ClearPolledEvent( POLLED_EVENT_DONEBLACKTHREAD );
			gConfig.DeleteBlackThread();

			if ( gUIScreen->mProgressDialog )
			{
				delete gUIScreen->mProgressDialog;
				gUIScreen->mProgressDialog = NULL;
				InvalidateRect( Globals.hwnd, NULL, false );
			}

			if ( Globals.GetRestartSetBlack() )
			{
				OnBlackCalibration( 0, 0 );
				Globals.SetRestartSetBlack( false );
			}
		}

		if ( Globals.GetPolledEvents() & POLLED_EVENT_DONERENDERTHREAD )
		{
			Globals.ClearPolledEvent(POLLED_EVENT_DONERENDERTHREAD);
			ClearProgramStateFlag( PROGRAM_STATE_FLAG_RENDERING );
			gConfig.DeleteRenderThread();

			if ( gUIScreen->mProgressDialog )
			{
				delete gUIScreen->mProgressDialog;
				gUIScreen->mProgressDialog = NULL;
				InvalidateRect( Globals.hwnd, NULL, false );
			}
		}
	}

	CheckCursor();
	CheckIridas();
	CheckWhiteBalance();
	CheckZoom();
	CheckTemperature( false );
	CheckDisk( false );
    if ( Globals.mCaptureOK == 1 )
    {
        Globals.mCaptureOK = 2;
	    gDeviceManager.ImportBlackImage();
    }
}

UINT_PTR timer = NULL;
void SiliconDVRShutdown()
{
    Globals.SetWindowsShutdown(true);
	gLogger.info(1, "%d  SiliconDVRShutdown START\n", GetTickCount() );

	ShutdownWinIo();

#ifdef LENS_DEVICE
	if ( Globals.GetLensDevice() )
	{
		int res = SI_StopCMLensContMode();

		if ( res == SUCCESS )
		{
			res = SI_CloseCMLensDevice();
		}
	}
#endif

	KillTimer( NULL,timer );

	if ( isProgramRecording() )
	{
		gLogger.info(1, "%d  STOP RECORDING 1\n", GetTickCount() );
		gUIManager->mScreen->StopRecording();
		gLogger.info(1, "%d  STOP RECORDING 2\n", GetTickCount() );
		Sleep( 100 );
	}

	if ( isProgramPreviewing() )
	{
		gConfig.StopGrabbing(false,true);
		Sleep(100);
	}

	if ( isProgramConfigured() )
	{
		gConfig.Clear(true);
	}

	// Store the guides value
	gPrefs.SetGuides( Globals.GetGuide() );

	// Close audio recording device
	if ( gAudioRecorder )
	{
		gAudioRecorder->Close();
		gAudioRecorder->CloseMixer();
		delete gAudioRecorder;
		gAudioRecorder = NULL;
	}

	// Update project data only if a project is loaded
	if ( gProject )
	{
		gPrefs.SetProjectData( false );
	}

	// Close audio playback device
	if ( gAudioPlayback )
	{
		gAudioPlayback->Close();
		delete gAudioPlayback;
		gAudioPlayback = NULL;
	}

    gTimecodeController.Deinit();

	if ( Globals.isMen() )
	{
		gFanSpeed = 2;
		SI_SetSMB2FanSpeed(gFanSpeed);
		SI_CloseLM63Device();
		SI_CloseSMB2Device();
		SI_CloseCPUCoreDevice();
	}

	if ( Globals.checkTemp() )
	{
		SI_CloseCPUCoreDevice();
	}

	gPrefs.SetOpenGL( Globals.mNewOpenGLState );
	gPrefs.Write();

	gLogger.info(1, "%d   APPLICATION EXIT\n", GetTickCount() );

#ifdef RAM_LOGGER
    gLogger.exit();
#endif

	if ( gPrefs.GetSdiMode() )
	{
		gSdiThread->mDoIt = false;
		gLogger.info(1,"%s   Signalling SDI thread.\n",
			Globals.GetPrettyHighResClockString());
		SetEvent(gSdiSignal);
		Sleep(1500);
    	delete gSdiThread;
	    gSdiThread = NULL;
	}
	delete gSIPlayer;
    CoUninitialize();
}


void InitSi2k(void)
{
	char path[256];
	strcpy(path,Globals.GetSIDir());
	strcat(path,"si2k.txt");
    FILE *f = fopen(path,"rt");
    if ( f )
    {
        fclose(f);
        Globals.isSi2k(true);
    }
}

void InitMinideck()
{
	char path[256];
	strcpy( path, Globals.GetSIDir() );
	strcat( path, "minideck.txt" );
    FILE *f = fopen( path, "rt" );
    if ( f )
    {
        fclose( f );
        Globals.IsMinideck( true );
		gLogger.info( 1, "Initializing Minideck\n" );
    }
}


void FlushFiles( char volumeLetter )
{
    char volumeName[32];
    strcpy(volumeName,"\\\\.\\C:");
    volumeName[4] = volumeLetter;
    HANDLE h = CreateFile(volumeName, 
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE, 
        0,
        OPEN_EXISTING, 
        0, 
        0);
	if ( h == INVALID_HANDLE_VALUE ) 
        return;

    FlushFileBuffers(h);
    CloseHandle(h);
}

/*void LoadCodecHeader()
{
    char headerName[128];
    strcpy( headerName, Globals.GetSIDir() );
    strcat( headerName, "codecheader.bin" );
	FILE *f = fopen(headerName,"rb");
    if ( !f ) 
    {
        gLogger.error( "LoadCodecHeader : could not open file %s\n", headerName );
        return;
    }
    int res = fread(AviStrfv::mCineformStrf,1,CINEFORM_STRF_SIZE,f);
    assert(res == CINEFORM_STRF_SIZE);
    fclose(f);
	//memset(AviStrfv::mCineformStrf,0,CINEFORM_STRF_SIZE);


}*/


void PostMonitorEnum()
{
	// swap if necessary
	if ( gConfig.mMonitorX[0] > gConfig.mMonitorX[1] && gPrefs.GetOpenGL() )
	{
		int x = gConfig.mMonitorX[0];
		int y = gConfig.mMonitorY[0];
		int w = gConfig.mMonitorW[0];
		int h = gConfig.mMonitorH[0];
		gConfig.mMonitorX[0] = gConfig.mMonitorX[1];
		gConfig.mMonitorY[0] = gConfig.mMonitorY[1];
		gConfig.mMonitorW[0] = gConfig.mMonitorW[1];
		gConfig.mMonitorH[0] = gConfig.mMonitorH[1];
		gConfig.mMonitorX[1] = x;
		gConfig.mMonitorY[1] = y;
		gConfig.mMonitorW[1] = w;
		gConfig.mMonitorH[1] = h;
	}

	if ( gConfig.mMonitorW[0] > GIGAPP_APP_WIDTH )
	{
		Globals.mMainGuiMag2 = ( float ) gConfig.mMonitorW[0] / GIGAPP_APP_WIDTH;
	}
	else
	{
		Globals.mMainGuiMag2 = 1.0f;
	}

	if ( gPrefs.GetMode800() )
		SetMiniGuiParams( gPrefs.GetMode800() );
	if ( !gPrefs.GetMode800() )
	{
		gConfig.mAppOffsetX = ( float ) gConfig.mMonitorW[0]/2 - GIGAPP_APP_WIDTH/2 + gConfig.mMonitorX[0];
		gConfig.mAppOffsetY = ( float ) gConfig.mMonitorH[0]/2 - GIGAPP_APP_HEIGHT/2 + gConfig.mMonitorY[0];
		Globals.SetGeometry( GEOMETRY_1280 );
	}
	else
	{
		gConfig.mAppOffsetX = ( float ) gConfig.mMonitorW[0]/2 - Globals.mMiniGuiWidth/2 + gConfig.mMonitorX[0];
		gConfig.mAppOffsetY = ( float ) gConfig.mMonitorH[0]/2 - Globals.mMiniGuiHeight/2 + gConfig.mMonitorY[0];
		Globals.SetGeometry( GEOMETRY_800 );
	}
		
	gConfig.mAppFullX = gConfig.mMonitorX[0];
	gConfig.mAppFullW = ( float ) gConfig.mMonitorW[0];
	gConfig.mAppFullH = ( float ) gConfig.mMonitorW[0] * 9 / 16;
	gConfig.mAppFullY = ( gConfig.mMonitorH[0] - gConfig.mAppFullH ) / 2 + gConfig.mMonitorY[0];
	gConfig.mAppFullOffsetY = ( float ) gConfig.mAppFullY * 2 + gConfig.mMonitorY[0];
}


int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	MSG msg;
	HACCEL hAccelTable;
	bool quit = false;
	int i = 0;

	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_GIGEAPP, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

    _CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF);
 	gPrefs.Read();
    gLogger.init();
    InitSi2k();
	InitMinideck();

    assert(sizeof(SIVHeader) == 64*1024);

    DWORD mainThreadID = GetCurrentThreadId();
    Globals.SetThreadName(mainThreadID,"SDVR_main_thread");

	// Write build version info to logfile
	char versionText[ 256 ];
	int buildVersion = MULTICAM_BUILD_VERSION;
	sprintf( versionText, "\n\nSilicon DVR Build Version %d\nDate: %s", buildVersion, GetSystemTimeString() );
	gLogger.info( 0, "%s\n", versionText );

	// Perform application initialization:
	BOOL res = EnumDisplayMonitors(
		NULL,
		NULL,
		MyMonitorEnumProc,
		NULL
	);


	PostMonitorEnum();

    gLogger.info( DEBUG_LEVEL, "EnumMonitors: width %d height %d, width %d height %d\n", 
		gConfig.mMonitorW[0],
		gConfig.mMonitorH[0],
		gConfig.mMonitorW[1],
		gConfig.mMonitorH[1]);
    
	Globals.mNewOpenGLState = gPrefs.GetOpenGL();
	/*if ( gPrefs.GetOpenGL() )
	{
	    if ( gConfig.mNumMonitors == 1 )
		{
			gConfig.mMonitorW[gConfig.mNumMonitors] = gConfig.mMonitorW[0] - 800;
			gConfig.mMonitorH[gConfig.mNumMonitors++] = gConfig.mMonitorW[gConfig.mNumMonitors] * 9 / 16;
			gConfig.mMonitorW[0] = 800;
			gConfig.mMonitorH[0] = 800;

			if ( gPrefs.GetMode800() )
				SetMiniGuiParams( gPrefs.GetMode800() );
			if ( !gPrefs.GetMode800() )
			{
				gConfig.mAppOffsetX = ( float ) gConfig.mMonitorW[0]/2 - GIGAPP_APP_WIDTH/2;
				gConfig.mAppOffsetY = ( float ) gConfig.mMonitorH[0]/2 - GIGAPP_APP_HEIGHT/2;
				Globals.SetGeometry( GEOMETRY_1280 );
			}
			else
			{
				gConfig.mAppOffsetX = ( float ) gConfig.mMonitorW[0]/2 - Globals.mMiniGuiWidth/2;
				gConfig.mAppOffsetY = ( float ) gConfig.mMonitorH[0]/2 - Globals.mMiniGuiHeight/2;
				Globals.SetGeometry( GEOMETRY_800 );
			}
		
			gConfig.mAppFullX = 0;
			gConfig.mAppFullW = ( float ) gConfig.mMonitorW[0];
			gConfig.mAppFullH = ( float ) gConfig.mMonitorW[0] * 9 / 16;
			gConfig.mAppFullY = ( gConfig.mMonitorH[0] - gConfig.mAppFullH ) / 2;
			gConfig.mAppFullOffsetY = ( float ) gConfig.mAppFullY * 2;
		}
	}*/

	if (!InitInstance (hInstance, nCmdShow)) 
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_GIGEAPP);


    if(FAILED(CoInitialize(NULL)))
    {
        exit(1);
    }

    gPrefs.GetTimecodePrefs2(gTimecodeController.prefs());
    gTimecodeController.Init();

	CAsyncFileWriter::InitData();
	LoadIridas();
	if ( gPrefs.GetSdiMode() )
	{
		SDIThread::InitSdiBuffers();
		gSdiSignal = CreateEvent( NULL, FALSE, FALSE, "SdiSignal" );
		gSdiThread = new SDIThread();
		gSdiThread->StartThread();
		while( !gSdiThread->mIsInitialized )
			Sleep(100);
	}


	// Initialization
	Globals.SetDisplay3DMode( ( E3DDisplayMode ) gPrefs.GetDispMode() );
	gLut3d.LoadLooks();
	gDisplay.EnableDX( Globals.hwnd );
	gD3D->SetLut3DTextures();
	gSIPlayer = new CSIDSMediaFilePlayer;
	SetPreviewWB();
	gUtils = new CUtils();
    CheckMEN();
	Globals.SetTimeMeter( true );




	if ( Globals.IsMinideck() )
	{
		bool result = InitializeWinIo();

		if ( result ) 
		{
			out( INDEX, 0x4e );     // select Bank0
			out( DATA , 0x0 );
			out( INDEX, 0x4 ); 	    // enable DC on cpu fan out 0
			out( DATA,  0x1 );
			gLogger.info( 1, "%d  InitializeWinIo() SUCCESS\n", GetTickCount() );
		}
		else
		{
			gLogger.info( 1, "%d  InitializeWinIo() FAILURE\n", GetTickCount() );
		}
	}


	gLogger.info( 1, "%d   about to gSlate.UpdateClipData...\n", GetTickCount() );
	gSlate.UpdateClipData();

	// Retrieve the guides value
	gLogger.info( 1, "%d   about to Globals.SetGuide...\n", GetTickCount() );
	Globals.SetGuide( gPrefs.GetGuides() );

	gLogger.info( 1, "%d   about to gPrefs.GetSlaveIridasState...\n", GetTickCount() );
	if ( gPrefs.GetSlaveIridasState() )
	{
		gConfig.StartThreadIRI( true );
	}

	InitGammaTables();
    //LoadCodecHeader();
	gLoupe = new CLoupe;

	// Init Audio device
	gLogger.info( 1, "%d   about to CVoiceRecording...\n", GetTickCount() );
	gAudioRecorder = new CVoiceRecording();
	gAudioRecorder->PrepareBuffer();

	gUIManager = new CUIManager;
	gUIManager->Init();
    SetPrivs();
	
	Globals.SetMouseTicks(GetTickCount());
	timer = SetTimer( NULL, NULL, TIMER_MS, HandleTimer );

    Globals.SetParallaxShift( 2, 0.0f );
    float angle = Globals.GetParallaxRotation(1280,720,false);

	SetFullScreenMode();
	gUIScreen->mRightPanelInfo.drive_full = false;

	gLogger.info( 1, "%d   about to gPrefs.GetRecentProject...\n", GetTickCount() );
	if ( strlen(gPrefs.GetRecentProject()) )
	{
		CProject *project = new CProject();

		if ( project->Init( gPrefs.GetRecentProject() ) )
		{
			if ( gProject )
			{
				delete gProject;
			}
			gProject = project;
    		gPrefs.SetProjectData( false );
	    	gSlate.UpdateClipData();
		    gPrefs.Write();
		    CheckDisk( true );
		    Globals.SetNextFileName();
		}
	}

#ifdef LENS_DEVICE
	// Lens initialization
	res = SI_OpenCMLensDevice();
	if ( res == SUCCESS )
	{
		res = SI_StartCMLensContMode();
		if ( res == SUCCESS )
		{
			Globals.SetLensDevice( true );
		}
	}
#endif

	Globals.SetLensDevice( false );

    // asdf gDeviceManager.SetLEDState(false);
	int logicalRAM = gPrefs.GetLogicalRamMB( gDeviceManager.NumDevices() );
    setGlobalMemoryManager( logicalRAM );
    //PrecacheCineformSDK();
    gShoSignal = CreateEvent( NULL, FALSE, FALSE, "ShoSignal" );
    gDrawnSignal = CreateEvent( NULL, FALSE, FALSE, "DrawnSignal" );
    gDuoSignal = CreateEvent( NULL, FALSE, FALSE, "DuoSignal" );

	if ( gPrefs.GetOpenGL() )
	{
		gOglSignal = CreateEvent( NULL, FALSE, FALSE, "OglSignal" );
		gOglThread = new OGLThread(Globals.hwnd2);
		if ( gConfig.mNumMonitors > 1 )
		{
			gOglThread->StartThread();
			while( !gOglThread->mIsInitialized )
    			Sleep(100);
		}
	}

	gD3D->InitLut3DTexture();

	if ( gPrefs.GetConfigAutoload() )
	{
		// If both CAMS are marked as inactive in prefsXML, don't connect to the devices
		if ( ( gPrefs.GetCamActive( 0 ) == 0 ) && ( gPrefs.GetCamActive( 1 ) == 0 ) )
		{
			gConfig.Autoload( (ECamRaster) gPrefs.GetCameraRaster(), (ECamFramerate) gPrefs.GetCameraFramerate(), false );
		}
		else
		{
			gConfig.Autoload( (ECamRaster) gPrefs.GetCameraRaster(), (ECamFramerate) gPrefs.GetCameraFramerate(), true );
		}
	}

    if ( !gMemoryManager ) setGlobalMemoryManager(gPrefs.GetLogicalRamMB(gDeviceManager.NumDevices()));

	// Load custom settings if applicable
	if ( gPrefs.GetCustomMode() )
	{
		// If the custom mode file cannot be found, disable the custom mode and load the 1080 default raster
		char * customFilePath = gPrefs.GetCustomSettingsFileName();
		FILE *file = fopen( customFilePath, "r" );

		if ( ! ( file ) )
		{
			gPrefs.SetCustomMode( false );
			Globals.SetCameraRaster( CAMRASTER_1080 );
			gPrefs.SetCameraRaster( CAMRASTER_1080 );
			gLogger.info( 1, "%d   Custom mode file not found - use default\n", GetTickCount() );
			gUIScreen->mShutterControl->SetActive( true );
		}
		else
		{
			SetCustomModeVals( customFilePath );
			fclose ( file );
			gUIScreen->mShutterControl->SetActive( false );
			Globals.SetCameraModeText( "CUSTOM" );
		}
	}

	if ( gProject )
	{
		Globals.SetNextFileName();
	}

	// Define a system wide hot key (SHIFT + F9)
	if ( RegisterHotKey( NULL, 1, MOD_SHIFT, VK_F9 ) ) 
    {
        gLogger.info( 1, "%d   Hotkey registered\n", GetTickCount() );
    }



	if ( gPrefs.GetSdiMode() )
	{
		gSdiThread->mDoRestart = true;
		gLogger.info(1,"%s   Signalling SDI thread with restart.\n",
			Globals.GetPrettyHighResClockString());
		SetEvent(gSdiSignal);
	}


#if 1
	while ( GetMessage( &msg, NULL, 0, 0) ) 
	{
		if ( msg.message == WM_HOTKEY )
        {
            gLogger.info( 1, "%d   Hotkey received\n", GetTickCount() );
			// SHIFT + F9 hotkey turns off external monitor L/R switching
			gPrefs.SetDispExtMode( MODE3D_ANAGLYPH );
        }

		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
#else
    int result;
	while (result = GetMessage(&msg, NULL, 0, 0)) 
	{
        if ( result == -1 )
        {
        	gLogger.info(1, "%d  MESSAGE LOOP RECEIVED -1\n", GetTickCount() );
            break;
        }
		//if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
		//{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		//}

	}

#endif

    if ( !Globals.GetWindowsShutdown() )
        SiliconDVRShutdown();
	//_CrtDumpMemoryLeaks();

	return (int) msg.wParam;
}



ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX); 

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_GIGEAPP);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH) GetStockObject( BLACK_BRUSH );
	wcex.lpszMenuName	= NULL;
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

	return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	hInst = hInstance; // Store instance handle in our global variable

	Globals.hwnd = CreateWindow(szWindowClass, szTitle, 
		WS_OVERLAPPEDWINDOW,
		gConfig.mMonitorX[0], gConfig.mMonitorY[0], 
		gConfig.mMonitorW[0], gConfig.mMonitorH[0], 
		NULL, NULL, hInstance, NULL);

   gMenuHandle = GetMenu( Globals.hwnd );

   if (!Globals.hwnd)
   {
      return FALSE;
   }

   ShowWindow(Globals.hwnd, nCmdShow);
   UpdateWindow(Globals.hwnd);

   if ( gConfig.mNumMonitors > 1 )
   {
		Globals.hwnd2 = CreateWindow(szWindowClass, szTitle, 
			WS_OVERLAPPEDWINDOW,
			gConfig.mMonitorX[1], gConfig.mMonitorY[1],
			gConfig.mMonitorW[1], gConfig.mMonitorH[1], 
			NULL, NULL, hInstance, NULL);


		SetWindowLong( 
			Globals.hwnd2, 
			GWL_WNDPROC,
			(LONG)WndProc2
			);

	   ShowWindow(Globals.hwnd2, nCmdShow);
	   UpdateWindow(Globals.hwnd2);
   }


   return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	extern void SimGPIO( void );
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc = NULL;
	bool res = false;
	static int mouseX1 = -1, mouseY1 = -1, mouseX2 = -1, mouseY2 = -1;
	int deltaX = 0;
	int deltaY = 0;

	switch (message) 
	{
	case WM_COMMAND:
		wmId    = LOWORD(wParam); 
		wmEvent = HIWORD(wParam); 

		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_EXIT:
    		gLogger.info(1, "%d  WndProc IDM_EXIT\n", GetTickCount() );
		    PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		if ( gD3D )
		{
            //gLogger.info(DEBUG_LEVEL,"MainThread, got paint event.\n");
			//printDualRings("MainThread\n");
			gUIManager->Render( hdc, true );
		}
		EndPaint(hWnd, &ps);
		break;

	case 0xbadd:
		if( gDisplay.mIsNewImage )
		{
			if ( !gUIManager->mScreen->mFileDialog  && !gUIManager->mScreen->mMacroListDialog  && !gUIManager->mScreen->mPrefs )
			{
                //gLogger.info(DEBUG_LEVEL,"MainThread, got new image.\n");
    			//printDualRings("MainThread\n");
				gUIManager->Render( hdc, false );
			}
		}
		break;

	case 0xbadf:
		if ( !gUIManager->mScreen->mFileDialog  && !gUIManager->mScreen->mMacroListDialog  && !gUIManager->mScreen->mPrefs )
		{
            //gLogger.info(DEBUG_LEVEL,"MainThread, got 0xbadf.\n");
			//printDualRings("MainThread\n");
			gUIManager->Render( hdc, false );
		}
		break;

	case WM_SIZE:
		gDisplay.ResizeGraphics(Globals.hwnd);
		break;

    case WM_SI_DSGRAPHNOTIFY:
		gSIPlayer->handle_graph_event();
		break;

	case WM_RBUTTONUP:
		deltaX = mouseX1 - mouseX2;
		deltaY = mouseY1 - mouseY2;

		// Temporarily disabled until fully functional (2010-02-08)
		/*if ( Globals.GetRightClickMessage() == RIGHT_CLICK_MESSAGE_MOVE )
		{
			gLogger.info( 1, "WM_RBUTTONUP deltaX: %d deltaY: %d\n", deltaX, deltaY );
			gUIScreen->MouseMoveRightClick( deltaX, deltaY );
			Globals.SetRightClickMessage( RIGHT_CLICK_MESSAGE_NONE );
		}*/
		break;

	case WM_MOUSEMOVE:
		Globals.SetMouseTicks( GetTickCount() );
		if ( ! Globals.GetMouseActive() )
		{
			Globals.SetMouseActive( true );
			ShowCursor( TRUE );
		}

		if ( wParam == MK_RBUTTON )
		{
			mouseX1 = mouseX2;
			mouseY1 = mouseY2;
			mouseX2 = LOWORD( lParam ); // New x position
			mouseY2 = HIWORD( lParam ); // New y position

			gLogger.info( 1, "WM_MOUSEMOVE deltaX: %d deltaY: %d\n", deltaX, deltaY );

			Globals.SetRightClickMessage( RIGHT_CLICK_MESSAGE_MOVE );
		}
		break;

	case WM_LBUTTONDOWN:
		Globals.SetMouseTicks( GetTickCount() );
		if ( ! Globals.GetMouseActive() )
		{
			Globals.SetMouseActive( true );
			ShowCursor( TRUE );
		}

		switch ( Globals.GetGeometry() )
		{
			case GEOMETRY_1280:
			case GEOMETRY_800:
				gUIManager->OnClick( GET_X_LPARAM( lParam ) / Globals.mMainGuiMag2, 
								   ( GET_Y_LPARAM( lParam ) - gConfig.mAppFullY ) / Globals.mMainGuiMag2 );
				break;
			case GEOMETRY_FULL:
				gUIManager->OnClick( GET_X_LPARAM( lParam ), 
									 GET_Y_LPARAM( lParam ) );
				break;
		}
		
		break;
	case WM_RBUTTONDOWN:
		Globals.SetRightClickMessage( RIGHT_CLICK_MESSAGE_NORMAL );

		if ( gIridas )
		{
			if ( !gPrefs.GetMode800() )
			{
				if ( gIridas->HandleRightClick( (float) GET_X_LPARAM( lParam ) / Globals.mMainGuiMag2, 
												(float) ( GET_Y_LPARAM( lParam ) - gConfig.mAppFullY ) / Globals.mMainGuiMag2 ) )
				{
					gAnchorX = GET_X_LPARAM( lParam );
					gAnchorY = GET_Y_LPARAM( lParam );
				}
			}
			else
			{
				if ( gIridas->HandleRightClick( 
					( (float) GET_X_LPARAM( lParam ) - gConfig.mAppOffsetX) * Globals.mMiniGuiMag, 
					( (float) GET_Y_LPARAM( lParam ) - gConfig.mAppOffsetY) * Globals.mMiniGuiMag ) )
				{
					gAnchorX = GET_X_LPARAM( lParam );
					gAnchorY = GET_Y_LPARAM( lParam );
				}
			}
		}
		else if ( gUIScreen->mUserWBDialog )
		{
			if ( !gPrefs.GetMode800() )
			{
				if ( gUIScreen->mUserWBDialog->HandleRightClick( GET_X_LPARAM( lParam ) - gConfig.mAppFullX / Globals.mMainGuiMag2, 
															   ( GET_Y_LPARAM( lParam ) - gConfig.mAppFullY ) / Globals.mMainGuiMag2 ) )
				{
					gAnchorX = GET_X_LPARAM( lParam );
					gAnchorY = GET_Y_LPARAM( lParam );
				}
			}
			else
			{
				if ( gUIScreen->mUserWBDialog->HandleRightClick( 
					( (float) GET_X_LPARAM(lParam) - gConfig.mAppOffsetX) * Globals.mMiniGuiMag, 
					( (float) GET_Y_LPARAM(lParam) - gConfig.mAppOffsetY) * Globals.mMiniGuiMag	) )
				{
					gAnchorX = GET_X_LPARAM( lParam );
					gAnchorY = GET_Y_LPARAM( lParam );
				}
			}
		}
		else
		{
			if ( Globals.GetRightClickMessage() == RIGHT_CLICK_MESSAGE_NORMAL )
			{
				gUIManager->OnRightClick();
			}
		}
		break;

	case WM_SYSKEYDOWN:
		if( wParam == VK_F10 )
		{
			OnIncDisplay3DMode( 0, 0 );
		}
		else if ( wParam == VK_F4 )
		{
			PostQuitMessage( 0 );
		}
		break;

	case WM_MOUSEWHEEL:
		if ( gIridas )
		{
			gIridas->OnMouseWheel( (UINT) LOWORD( wParam ), (short) HIWORD( wParam ) );            
		}
		break;

	case WM_KEYDOWN:
		switch ( wParam )
		{
			case VK_DELETE:
			case VK_LEFT:
			case VK_RIGHT:
			case VK_UP:
			case VK_DOWN:
			case VK_RETURN:
			case VK_BACK:
				gUIManager->OnVK( (DWORD)wParam );
				break;
			case VK_F1:
				OnFullScreenClick( 0, 0 );
				break;
			case VK_F2:
				OnExposureMeterClick( 0, 0 );
				break;
			case VK_F3:
				OnToggleSobel( 0, 0 );
				break;
			case VK_F4:
				OnZoomClick( 0, 0 );
				break;
			case VK_F5:
				OnToggleHistogram( 0, 0 );
				break;
			case VK_F6:
				OnToggleLut3D( 0, 0 );
				break;
			case VK_F7:
				OnRecordClick( 0, 0 );
				break;
			case VK_F8:
				OnPlayModeClick( 0, 0 );
				OnPlayPlay( 0, 0 );
				break;
			case VK_F9:
				if ( gPrefs.GetDispExtMode() != MODE3D_LEFT )
				{
					gPrefs.SetDispExtMode( MODE3D_LEFT );
				}
				else
				{
					gPrefs.SetDispExtMode( MODE3D_RIGHT );
				}
				break;
			case VK_F11:
				if ( gPrefs.GetHistogramExt() )
				{
					gPrefs.SetHistogramExt( 0 );
					Globals.SetHistogramOn( false );
				}
				else
				{
					gPrefs.SetHistogramExt( 1 );
				}
				break;
			case VK_F12:
				gUIManager->OnCustomExtMode();
				break;

#ifdef LOSSLESS_HACK
		    case VK_NUMPAD1:
                gLockCompression ^= 1;
                break;
		    case VK_NUMPAD2:
                CCineformSDK::mLosslessLevel--;
                if ( CCineformSDK::mLosslessLevel < 0)
                    CCineformSDK::mLosslessLevel = 0;
                break;
		    case VK_NUMPAD3:
                CCineformSDK::mLosslessLevel++;
                if ( CCineformSDK::mLosslessLevel >= NUM_LOSSLESS_LEVELS )
                    CCineformSDK::mLosslessLevel = (NUM_LOSSLESS_LEVELS - 1);
                break;
#endif
			}
		break;

	case WM_CHAR:
		gUIManager->OnKeydown( (DWORD) wParam );
		break;

	case WM_DESTROY:
		gLogger.info(1, "%d  WndProc WM_DESTROY\n", GetTickCount() );
		break;
	case WM_QUERYENDSESSION:
		gLogger.info(1, "%d  WndProc WM_QUERYENDSESSION\n", GetTickCount() );
        SiliconDVRShutdown();
		return TRUE;

	case WM_ENDSESSION:
		gLogger.info(1, "%d  WndProc WM_ENDSESSION\n", GetTickCount() );
		PostQuitMessage(0);
		break;
	case WM_CLOSE:
		gLogger.info(1, "%d  WndProc WM_CLOSE\n", GetTickCount() );
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

LRESULT CALLBACK WndProc2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	bool res = false;

	switch (message) 
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_INITDIALOG:
		return TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
		{
			EndDialog(hDlg, LOWORD(wParam));
			return TRUE;
		}
		break;
	}
	return FALSE;
}

void OnStartGrabbing( void )
{
	assert(	!isProgramPreviewing() );
	gConfig.StartGrabbing();
}


void OnStopRecording( void )
{
    assert(_CrtCheckMemory() );
    gD3D->mDoClearExternal = 4;
	if ( isProgramWriting() )
	{
        //gLogger.info(0, "%d   clear PROGRAM_STATE_FLAG_WRITING\n", 
        //    GetTickCount());
		ClearProgramStateFlag( PROGRAM_STATE_FLAG_WRITING );
		while( true )
		{
        	//gLogger.info(1, "%d   Waiting for SIV thread to end.\n",GetTickCount() );
			if ( Globals.GetPolledEvents() & POLLED_EVENT_DONEWRITING )
			{
				Globals.ClearPolledEvent(POLLED_EVENT_DONEWRITING);
				gConfig.DeleteWriteThread();
			}
			if ( !gWriThread )
			{
				break;
			}
			Sleep(100);
    assert(_CrtCheckMemory() );
			SendMessage( Globals.hwnd, 0xbadf, 0xbadf, 0xbadf );
		}
	}
	else if ( isProgramCompressing() )
	{
    assert(_CrtCheckMemory() );
		ClearProgramStateFlag( PROGRAM_STATE_FLAG_COMPRESSING );
		gAudioRecorder->SetCallback( NULL );
		while( true )
		{
			if ( Globals.GetPolledEvents() & POLLED_EVENT_DONECOMPRESSING )
			{
				Globals.ClearPolledEvent(POLLED_EVENT_DONECOMPRESSING);
				gConfig.DeleteCompressThread();
			}
			if ( !gCinThread )
			{
				break;
			}
			Sleep(100);
			SendMessage( Globals.hwnd, 0xbadf, 0xbadf, 0xbadf );
		}
	}

	// Write stop TC to prefs
	/*CSMPTE stopTC = *( Globals.GetTimecode() );
	TTimecodePrefs2 tcp;
	gPrefs.GetTimecodePrefs2( &tcp );

	tcp.data[ 0 ] = stopTC.mHours;
	tcp.data[ 1 ] = stopTC.mMinutes;
	tcp.data[ 2 ] = stopTC.mSeconds;
	tcp.data[ 3 ] = stopTC.mFrames;
	gPrefs.SetTimecodePrefs2( &tcp );

	char tc[16];
	stopTC.String( tc );
	gLogger.info( 1, "%d  OnStopRecording TC: %s\n", GetTickCount(), tc );*/

	UpdateButtonStates();
}

void OnSetZoom( int zoomFactor )
{
	switch ( zoomFactor )
	{
	case 2:
		Globals.SetPanH(0);
		Globals.SetPanV(0);
		Globals.SetPanHStart(0);
		Globals.SetPanVStart(0);
		Globals.SetPanHEnd(0);
		Globals.SetPanVEnd(0);
		Globals.SetZoomStart(Globals.GetZoomMode());
		Globals.SetZoomMode(2);
		Globals.SetZoomEnd(Globals.GetZoomMode());
		Globals.SetZoomTicks(GetTickCount());
		Globals.SetZoomPanMaxH(2);
		if ( RasterInfo[Globals.GetCameraRaster()].aspectRatio == CAMAR_16_9 )
		{
			Globals.SetZoomPanMaxV(2);
		}
		else if ( RasterInfo[Globals.GetCameraRaster()].aspectRatio == CAMAR_DCI )
		{
			Globals.SetZoomPanMaxV(1.75f);
		}
		else if ( RasterInfo[Globals.GetCameraRaster()].aspectRatio == CAMAR_SCOPE )
		{
			Globals.SetZoomPanMaxV(0.9722222222222f);
		}
		break;
	case 4:
		//Globals.GetPanH() *= 2;
		//Globals.GetPanV() *= 2;
		Globals.SetPanHStart(Globals.GetPanH());
		Globals.SetPanVStart(Globals.GetPanV());
		Globals.SetPanHEnd(Globals.GetPanH()*2);
		Globals.SetPanVEnd(Globals.GetPanV()*2);
		Globals.SetZoomStart(Globals.GetZoomMode());
		Globals.SetZoomMode(4);
		Globals.SetZoomEnd(Globals.GetZoomMode());
		Globals.SetZoomTicks(GetTickCount());
		Globals.SetZoomPanMaxH(6);
		if ( RasterInfo[Globals.GetCameraRaster()].aspectRatio == CAMAR_16_9 )
		{
			Globals.SetZoomPanMaxV(6);
		}
		else if ( RasterInfo[Globals.GetCameraRaster()].aspectRatio == CAMAR_DCI )
		{
			Globals.SetZoomPanMaxV(5.5f);
		}
		else if ( RasterInfo[Globals.GetCameraRaster()].aspectRatio == CAMAR_SCOPE )
		{
			Globals.SetZoomPanMaxV(3.94444444f);
		}
		break;
	case 1:
		Globals.SetPanH(0);
		Globals.SetPanV(0);
		Globals.SetPanHStart(0);
		Globals.SetPanVStart(0);
		Globals.SetPanHEnd(0);
		Globals.SetPanVEnd(0);
		Globals.SetZoomStart(Globals.GetZoomMode());
		Globals.SetZoomMode(1);
		Globals.SetZoomValue(1);
		Globals.SetZoomEnd(Globals.GetZoomMode());
		Globals.SetZoomTicks(0);
		break;
	}

	if ( Globals.GetZoomMode() != 1 )
	{
		Globals.SetHistogramOn(false);
		Globals.SetRecall(GLOBALS_RECALL_NONE);
		Globals.SetLoupeState(0);
	}
	gD3D->mDoClearExternal = 4;
	InvalidateRect( Globals.hwnd, NULL, false );
}

bool OpenProject( char *filename )
{
	CProject *project = new CProject();
	if ( project->Init( filename ) )
	{
		if ( gProject )
		{
			delete gProject;
		}
		gProject = project;
		gPrefs.SetProjectData( false );
		gSlate.UpdateClipData();
		gPrefs.Write();
		CheckDisk( true );
		Globals.SetNextFileName();
		return true;
	}
    else
        delete project;
	return false;
}

LONG_PTR saveWindowLong;
HMENU saveMenu = NULL;

void SetFullScreenMode(void)
{
	LONG_PTR newLong = WS_POPUP + WS_VISIBLE;
	saveWindowLong = SetWindowLongPtr( Globals.hwnd, GWL_STYLE, (LONG) newLong );
	if ( saveMenu == NULL )
	{
		saveMenu = GetMenu( Globals.hwnd );
		SetMenu( Globals.hwnd, NULL );
	}
	if ( gConfig.mNumMonitors > 1 )
	{
		saveWindowLong = SetWindowLongPtr( Globals.hwnd2, GWL_STYLE, newLong );
		if ( saveMenu == NULL )
		{
			saveMenu = GetMenu( Globals.hwnd2 );
			SetMenu( Globals.hwnd2, NULL );
		}
	}
}


void SetProgramStateFlag( DWORD flag )
{
    //gLogger.info( DEBUG_LEVEL, "%d   SetProgramStateFlag flag %d\n", GetTickCount(), flag );
	gProgramStateFlags |= flag;
}

void ClearProgramStateFlag( DWORD flag )
{
    //gLogger.info( DEBUG_LEVEL, "%d   ClearProgramStateFlag flag %d\n", GetTickCount(), flag );
	gProgramStateFlags &= ~flag;
}



bool isProgramPreviewing(void)
{
	if ( gProgramStateFlags & PROGRAM_STATE_FLAG_PREVIEW )
		return true;
	return false;
}

bool isProgramEmptying(void)
{
	if ( gProgramStateFlags & PROGRAM_STATE_FLAG_EMPTYING )
		return true;
	return false;
}
bool isProgramConfigured(void)
{
	if ( gProgramStateFlags & PROGRAM_STATE_FLAG_CONFIG )
		return true;
	return false;
}

bool isProgramRecording(void)
{
	if ( gProgramStateFlags & (PROGRAM_STATE_FLAG_WRITING+PROGRAM_STATE_FLAG_COMPRESSING) )
		return true;
	return false;
}

bool isProgramWriting(void)
{
	if ( gProgramStateFlags & PROGRAM_STATE_FLAG_WRITING )
		return true;
	return false;
}

bool isProgramCompressing(void)
{
	if ( gProgramStateFlags & PROGRAM_STATE_FLAG_COMPRESSING )
		return true;
	return false;
}
bool isProgramPlayingAVI(void)
{
	if ( gProgramStateFlags & PROGRAM_STATE_FLAG_PLAYAVI )
		return true;
	return false;
}

bool isProgramPlayingSIV(void)
{
	if ( gProgramStateFlags & PROGRAM_STATE_FLAG_PLAYSIV )
		return true;
	return false;
}


bool isProgramRendering(void)
{
	if ( gProgramStateFlags & PROGRAM_STATE_FLAG_RENDERING )
		return true;
	return false;
}

bool isProgramRunningQC()
{
	if ( gProgramStateFlags & PROGRAM_STATE_FLAG_QUALITY_CTRL )
		return true;
	return false;
}

bool canProgramPreview(void)
{
	if ( !isProgramConfigured() )
	{
		return false;
	}
	return canProgramPlay();
}
bool canProgramPlay(void)
{
	if ( gProgramStateFlags & PROGRAM_STATE_FLAG_ACTIVITY_MASK )
		return false;
	return true;
}

bool canProgramRecord(void)
{
	if ( !isProgramPreviewing() )
		return false;
	if ( gProgramStateFlags & PROGRAM_STATE_FLAG_PREVIEW_MASK )
		return false;
	return true;
}

bool isAudioCameraMode(void)
{
	if ( gPrefs.GetTimeLapseMode() != TIME_LAPSE_MODE_NONE )
		return false;
	if ( Globals.GetCameraFramerate() < CAMFRAMERATE_23 )
		return false;
	if ( Globals.GetCameraFramerate() > CAMFRAMERATE_30 )
		return false;

	return true;
}

TFramerateInfo *getProjectFramerate(void)
{
    if ( gProject && gPrefs.GetConformProjectFPS() )
	    return gProject->framerateInfo();
    return &FramerateInfo[ Globals.GetCameraFramerate() ];
}

TFramerateInfo *getFramerateInfo(float framerate)
{
    if ( framerate < 23.99f )
	    return &FramerateInfo[ CAMFRAMERATE_23 ];
    if ( framerate < 24.5f )
	    return &FramerateInfo[ CAMFRAMERATE_24 ];
    if ( framerate < 25.5f )
	    return &FramerateInfo[ CAMFRAMERATE_25 ];
    if ( framerate < 29.99f )
	    return &FramerateInfo[ CAMFRAMERATE_29 ];
    if ( framerate < 30.5f )
	    return &FramerateInfo[ CAMFRAMERATE_30 ];
    if ( framerate < 48.5f )
	    return &FramerateInfo[ CAMFRAMERATE_48 ];
    if ( framerate < 50.5f )
	    return &FramerateInfo[ CAMFRAMERATE_50 ];
    if ( framerate < 59.97f )
	    return &FramerateInfo[ CAMFRAMERATE_59 ];
    if ( framerate < 50.5f )
	    return &FramerateInfo[ CAMFRAMERATE_60 ];
    return &FramerateInfo[ CAMFRAMERATE_24 ];
}

TFramerateInfo *getOriginalFramerate(void)
{
    return &FramerateInfo[ Globals.GetCameraFramerate() ];
}

void OnLoadFrame( int x, int y )
{
	gUIScreen->OpenFileDialog( FILE_TYPE_SII, NULL );
}

void OnRecallFrame( int x, int y )
{
    if ( Globals.GetRecall() == GLOBALS_RECALL_100 )
	{
		gUIScreen->mRecall100Button->SetHighlight( false );
    	Globals.SetRecall( GLOBALS_RECALL_NONE );
	}
    else
	{
		gUIScreen->mRecall100Button->SetHighlight( true );
		gUIScreen->mRecall50Button->SetHighlight( false );

		Globals.SetRecall( GLOBALS_RECALL_100 );

		// turn off zoom, histogram, spot
		Globals.SetZoomMode( 1 );
		Globals.SetZoomValue( 1 );
		Globals.SetZoomTicks( 0 );
		Globals.SetHistogramOn( false );
		Globals.SetLoupeState( 0 );
	}

	InvalidateRect( Globals.hwnd, NULL, false );
}

void OnRecallFrame50( int x, int y )
{
    if ( Globals.GetRecall() == GLOBALS_RECALL_50 )
	{
		gUIScreen->mRecall50Button->SetHighlight( false );
    	Globals.SetRecall( GLOBALS_RECALL_NONE );
	}
    else
	{
		gUIScreen->mRecall50Button->SetHighlight( true );
		gUIScreen->mRecall100Button->SetHighlight( false );
		Globals.SetRecall( GLOBALS_RECALL_50 );

		// turn off zoom, histogram, spot
		Globals.SetZoomMode( 1 );
		Globals.SetZoomValue( 1 );
		Globals.SetZoomTicks( 0 );
		Globals.SetHistogramOn( false );
		Globals.SetLoupeState( 0 );
	}

	InvalidateRect( Globals.hwnd, NULL, false );
}

void OnToggleLut3D( int x,int y )
{
	DWORD max = 1;
	if ( gD3D->mLookHasAlpha )
		max = 2;
	Globals.SetLut3DOn(Globals.GetLut3DOn()+1);
	if ( Globals.GetLut3DOn() > max ) 
		Globals.SetLut3DOn(0);
 	InvalidateRect( Globals.hwnd, NULL, false );
}


void OnSetWhiteBalance( int index )
{
	if ( !isProgramPreviewing() ) return;
	if ( isProgramWriting() ) return;
	if ( isProgramCompressing() ) return;

	if ( index == 2 )
	{
		Globals.Flags |= GLOBALS_FLAG_WHITEBALANCE;
		gPrefs.SetWhiteBalance( PREFS_WB_USER_1 );
	}
	else
	{
		Globals.Flags |= GLOBALS_FLAG_WHITEBALANCE;
		gPrefs.SetWhiteBalance( PREFS_WB_USER_2 );
	}
}

void LoadIridas()
{
	char licensepath[256];
	strcpy(licensepath,Globals.GetSIDir());
	strcat(licensepath,"Iridas\\License");
	SetCurrentDirectory(licensepath);
	char test[256];
	GetCurrentDirectory(255,test);

	char shaders[256];
	strcpy(shaders,Globals.GetSIDir());
	strcat(shaders,"Iridas\\Shaders");
	char luts[256];
	strcpy(luts,Globals.GetSIDir());
	strcat(luts,"Iridas\\LUTs");


	// NEW
	char szToken[15 + IRTOKEN_MAX_SIZE];
	strcpy(szToken, "SiliconImaging=");
	IrGenerateToken(5, szToken + 15);		
	FILE* pf = fopen("token.irlc", "w");
	fwrite(szToken, strlen(szToken), 1, pf);
	fclose(pf);

	char szError[256];
	if ( !gPrefs.GetSdiModeFlag() )
	{
		szError[0] = 0;
		gIrex = psQueryLookInterface( "license.irlc", shaders, luts, szError );
	}
	else
	{
		szError[0] = 0;
		gIrexSdi = psQuerySDIInterface("license.irlc", shaders, luts, szError);
		gIrex = psQueryLookInterface( "license.irlc", shaders, luts, szError );
		if ( gIrex == NULL || gIrexSdi == NULL )
			gLogger.error("%s   gIrexSdi is %x gIrex is %x.\n", 
				Globals.GetPrettyHighResClockString(), 
				gIrexSdi, gIrex);

		gLogger.info(1, "%s   Query SDI interface result is 0x%x, Query LOOK interface result is 0x%x, error text %s.\n", 
			Globals.GetPrettyHighResClockString(), 
			gIrexSdi, gIrex, szError);
	}

	szError[255] = 0;
}

bool SetCustomModeVals( char * filePath )
{
	string keys[] = { "RASTER", "SKIP", "COMMAND" }; 
	string line;
	string key;
	string value;
	string command;
	int pos = 0;
	int length = 0;
	int result = 0;
	int i = 0;

	ifstream inputFile( filePath );

	// If custom mode is checked, but the input SIC file is not found, use default values
	if ( ! ( inputFile ) )
	{
		return false;
	}

	while( getline( inputFile, line ) )
	{
		if( line.empty() ); // Ignore empty lines
		else
		{
			length = (int) line.length();
			pos = (int) line.find( "=" );
			key = line.substr( 0, pos );
			value = line.substr( pos + 1, length );

			result = key.compare( keys[ i ] );
			
			switch( i )
			{
				case 0:
					if ( result == 0 )
					{
						gLogger.info( 1, "%d   SetCustomModeVals - cam raster: %s\n", GetTickCount(), value.c_str() );

						// Set the values according to the string read from the custom file
						if ( stricmp ( value.c_str(), "540" ) == 0 )
						{
							Globals.SetCameraRaster( CAMRASTER_540 );
						}
						else if ( stricmp ( value.c_str(), "720" ) == 0 )
						{
							Globals.SetCameraRaster( CAMRASTER_720 );
						}
						else if ( stricmp ( value.c_str(), "1080" ) == 0 )
						{
							Globals.SetCameraRaster( CAMRASTER_1080 );
						}
						else if ( stricmp ( value.c_str(), "DCI" ) == 0 )
						{
							Globals.SetCameraRaster( CAMRASTER_DCI );
						}
						else if ( stricmp ( value.c_str(), "2K" ) == 0 )
						{
							Globals.SetCameraRaster( CAMRASTER_2K );
						}
						else
						{
							Globals.SetCameraRaster( CAMRASTER_SCOPE );
						}
					}
					else
					{
						// Default
						Globals.SetCameraRaster( CAMRASTER_1080 );
						gLogger.info( 1, "%d   SetCustomModeVals - cam raster default: 1080\n", GetTickCount() );
					}
					break;
				case 1:
					if ( result == 0 )
					{
						int n = atoi( value.c_str() );
						gPrefs.SetSkipFrames( n );
						gLogger.info( 1, "%d   SetCustomModeVals - timelapse skip: %s\n", GetTickCount(), value.c_str() );
					}
					break;
				case 2:
					if ( result == 0 )
					{
						ParseAndSendCmdString( value );
					}
					break;
			}
			i++;
		}
	}
	return true;
}

bool ParseAndSendCmdString( string cmd )
{
	char * token;
	char cmdText[ 128 ];
	int i = 0;

	// Comma is our delimter
	token = strtok( ( char* ) cmd.c_str() , "," );

	while ( token != NULL )
	{
		strcpy( cmdText, token );
		gDeviceManager.GetDevice( 0 )->SendSerialCommand( cmdText );
		gLogger.info( 1, "%d   ParseAndSendCmdString: %s\n", GetTickCount(), cmdText );
		token = strtok( NULL, "," );
		i++;
	}

	return true;
}

void SignalStereo()
{
	if ( !gPrefs.GetSdiMode() ) return;
	gSdiThread->mDoUpdateStereo = true;
    gLogger.info(1,"%s   Signalling SDI thread with new stereo flip.\n",
		Globals.GetPrettyHighResClockString());
    SetEvent(gSdiSignal);
}