/* main file, handles menu's and stuff */

#include "main.h"
#include "modify.h"
#include "mdi.h"
#include "resource.h"

#ifdef LOG
#include <xlog.h>
#endif

#include <windowsx.h>
#include <commctrl.h>
#include <stdio.h>
#include <string.h>

/* this is a fantastic function, we need it! */
#ifndef LOG

#include <sys/types.h>
#include <sys/stat.h>

/* does a file exist with filen as the file name */
int exists_file( char *filen )
{
  struct stat fst;

  if ( stat( filen, &fst) == -1 )
   return FALSE; /* file doesnt exist! */

  return TRUE;
}
#endif

/* globals */
HINSTANCE hInstance;
HWND      hWindow;
HWND      hClient;

LONG PRG_WIDTH = 720;
LONG PRG_HEIGHT = 520;

HWND hwndToolBar;
CAMP *cc;

LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);

/* functions that need localizing */
BOOL _stdcall AboutDlg(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL _stdcall DiceDlg(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL _stdcall NewDlg(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

/* local funtions */
void cleanup( void );

/* Global Variables for the status bar control */
HWND  hWndStatusbar;

/*------------------------------------------------------------------------
 Procedure:     UpdateStatusBar ID:1
 Purpose:       Updates the statusbar control with the appropiate
                text
 Input:         lpszStatusString: Charactar string that will be shown
                partNumber: index of the status bar part number.
                displayFlags: Decoration flags
 Output:        none
 Errors:        none

------------------------------------------------------------------------*/
void UpdateStatusBar(LPSTR lpszStatusString, WORD partNumber, WORD displayFlags)
{
    SendMessage(hWndStatusbar,
                SB_SETTEXT,
                partNumber | displayFlags,
                (LPARAM)lpszStatusString);
}


/*------------------------------------------------------------------------
 Procedure:     MsgMenuSelect ID:1
 Purpose:       Shows in the status bar a descriptive explaation of
                the purpose of each menu item.The message
                WM_MENUSELECT is sent when the user starts browsing
                the menu for each menu item where the mouse passes.
 Input:         Standard windows.
 Output:        The string from the resources string table is shown
 Errors:        If the string is not found nothing will be shown.
------------------------------------------------------------------------*/
LRESULT MsgMenuSelect(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
{
    static char szBuffer[256];
    UINT   nStringID = 0;
    UINT   fuFlags = GET_WM_MENUSELECT_FLAGS(wparam, lparam) & 0xffff;
    UINT   uCmd    = GET_WM_MENUSELECT_CMD(wparam, lparam);
    HMENU  hMenu   = (HMENU)GET_WM_MENUSELECT_HMENU(wparam, lparam);

    szBuffer[0] = 0;                            // First reset the buffer
    if (fuFlags == 0xffff && hMenu == NULL)     // Menu has been closed
        nStringID = 0;

    else if (fuFlags & MFT_SEPARATOR)           // Ignore separators
        nStringID = 0;

    else if (fuFlags & MF_POPUP)                // Popup menu
    {
        if (fuFlags & MF_SYSMENU)               // System menu
            nStringID = IDS_SYSMENU;
        else
            // Get string ID for popup menu from idPopup array.
            nStringID = 0;
    }  // for MF_POPUP
    else                                        // Must be a command item
        nStringID = uCmd;                       // String ID == Command ID

    // Load the string if we have an ID
    if (0 != nStringID)
        LoadString(hInstance, nStringID, szBuffer, sizeof(szBuffer));
    // Finally... send the string to the status bar
    UpdateStatusBar(szBuffer, 0, 0);
    return 0;
}


/*------------------------------------------------------------------------
 Procedure:     InitializeStatusBar ID:1
 Purpose:       Initialize the status bar
 Input:         hwndParent: the parent window
                nrOfParts: The status bar can contain more than one
                part. What is difficult, is to figure out how this
                should be drawn. So, for the time being only one is
                being used...
 Output:        The status bar is created
 Errors:
------------------------------------------------------------------------*/
void InitializeStatusBar(HWND hwndParent,int nrOfParts)
{
    const int cSpaceInBetween = 8;
    int   ptArray[40];   // Array defining the number of parts/sections
    RECT  rect;
    HDC   hDC;

   /* * Fill in the ptArray...  */

    hDC = GetDC(hwndParent);
    GetClientRect(hwndParent, &rect);

    ptArray[nrOfParts-1] = rect.right;
    //---TODO--- Add code to calculate the size of each part of the status
    // bar here.

    ReleaseDC(hwndParent, hDC);
    SendMessage(hWndStatusbar,
                SB_SETPARTS,
                nrOfParts,
                (LPARAM)(LPINT)ptArray);

    UpdateStatusBar("Ready", 0, 0);
    //---TODO--- Add code to update all fields of the status bar here.
    // As an example, look at the calls commented out below.

//    UpdateStatusBar("Cursor Pos:", 1, SBT_POPOUT);
//    UpdateStatusBar("Time:", 3, SBT_POPOUT);
}


/*------------------------------------------------------------------------
 Procedure:     CreateSBar ID:1
 Purpose:       Calls CreateStatusWindow to create the status bar
 Input:         hwndParent: the parent window
                initial text: the initial contents of the status bar
 Output:
 Errors:
------------------------------------------------------------------------*/
static BOOL CreateSBar(HWND hwndParent,char *initialText,int nrOfParts)
{
    hWndStatusbar = CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_BORDER|SBARS_SIZEGRIP,
                                       initialText,
                                       hwndParent,
                                       IDM_STATUSBAR);
    if(hWndStatusbar)
    {
        InitializeStatusBar(hwndParent,nrOfParts);
        SetWindowPos(hWndStatusbar, HWND_TOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW);
        return TRUE;
    }

    return FALSE;
}

int GetFileName(char *buffer,int buflen)
{
	char tmpfilter[40];
	int i = 0;
	OPENFILENAME ofn;

	memset(&ofn,0,sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hInstance = GetModuleHandle(NULL);
	ofn.hwndOwner = GetActiveWindow();
	ofn.lpstrFile = buffer;
	ofn.nMaxFile = buflen;
	ofn.lpstrTitle = "Open";
	ofn.nFilterIndex = 2;
	ofn.lpstrDefExt = "camp";
	strcpy(buffer,"*.camp");
	strcpy(tmpfilter,"All files,*.*,Campaign Files,*.camp");
	while(tmpfilter[i])
    {
		if (tmpfilter[i] == ',')
			tmpfilter[i] = 0;
		i++;
	}
	tmpfilter[i++] = 0; tmpfilter[i++] = 0;
	ofn.Flags = 539678;
	ofn.lpstrFilter = tmpfilter;
	return GetOpenFileName(&ofn);

}

int GetSvFileName(char *buffer,int buflen)
{
	char tmpfilter[40];
	int i = 0;
	OPENFILENAME ofn;

	memset(&ofn,0,sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hInstance = GetModuleHandle(NULL);
	ofn.hwndOwner = GetActiveWindow();
	ofn.lpstrFile = buffer;
	ofn.nMaxFile = buflen;
	ofn.lpstrTitle = "Save As";
	ofn.nFilterIndex = 2;
	ofn.lpstrDefExt = "camp";
	strcpy(buffer,"*.camp");
	strcpy(tmpfilter,"All files,*.*,Campaign Files,*.camp");
	while(tmpfilter[i])
    {
		if (tmpfilter[i] == ',')
			tmpfilter[i] = 0;
		i++;
	}
	tmpfilter[i++] = 0; tmpfilter[i++] = 0;
	ofn.Flags = 539678;
	ofn.lpstrFilter = tmpfilter;
	return GetSaveFileName(&ofn);
}

static BOOL InitApplication(void)
{
	WNDCLASS wc;

	memset(&wc,0,sizeof(WNDCLASS));
	wc.style = CS_HREDRAW|CS_VREDRAW |CS_DBLCLKS ;
	wc.lpfnWndProc = (WNDPROC)MainWndProc;
	wc.hInstance = hInstance;
	wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1);
	wc.lpszClassName = MAIN_WINDOW_CLASS;
	wc.lpszMenuName = MAKEINTRESOURCE(IDMAINMENU);
	wc.hCursor = LoadCursor(NULL,IDC_ARROW);
	
	/* icons */
	wc.hIcon = LoadIcon(NULL,MAKEINTRESOURCE(IDI_ICON));

	if (!RegisterClass(&wc))
		return FALSE;
		
    if ( InitMDI() == FALSE )
     return FALSE;

	return TRUE;
}

HWND CreateMainWnd(void)
{
  int width = PRG_WIDTH + GetSystemMetrics(SM_CXFIXEDFRAME) * 2;
  int height = PRG_HEIGHT + GetSystemMetrics(SM_CYFIXEDFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION);

/*
  if (wincl.lpszMenuName != NULL)
    height += GetSystemMetrics(SM_CYMENU);
*/


  int xpos = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
  int ypos = (GetSystemMetrics(SM_CYSCREEN) - height) / 2;


  return CreateWindow(MAIN_WINDOW_CLASS,"Campaign Developer",
		WS_MINIMIZEBOX|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZEBOX|WS_CAPTION|WS_BORDER|WS_SYSMENU|WS_THICKFRAME,
		xpos,ypos,width,height,
		NULL,
		NULL,
		hInstance,
		NULL);
}

void MainWndProc_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
    char buffer[MAX_PATH];
    HWND c;
    RECT r;

	switch(id)
    {
		/*NEW COMMANDS*/
		case IDM_WINDOWTILEH:
             SendMessage(hClient, WM_MDITILE, (WPARAM)MDITILE_HORIZONTAL|MDITILE_SKIPDISABLED, 0 );
             break;
             
		case IDM_WINDOWTILEV:
             SendMessage(hClient, WM_MDITILE, (WPARAM)MDITILE_VERTICAL|MDITILE_SKIPDISABLED, 0 );
             break;

		case IDM_WINDOWCASCADE:
             SendMessage(hClient, WM_MDICASCADE, (WPARAM)MDITILE_SKIPDISABLED, 0 );
             break;
             
        case IDM_WINDOWICONS:
             SendMessage(hClient, WM_MDIICONARRANGE, 0, 0 );
             break;
             
        case IDM_WINDOWCLOSEALL:
             cleanup_children();
             break;
		
		case IDM_CLOSE:
             if ( cc == NULL )
             {
               MessageBox(hwnd, "There is no active campaign! Try opening one or creating a new one!", "No active campaign!", MB_OK );
               break;
             }

             if ( cc->modified == TRUE )
             {
               char buf[64];
               sprintf( "%s has been modified. Save changes?", cc->name );

               if ( MessageBox(hwnd, buf, "Save Changes?", MB_YESNO ) == IDYES )
                  save_campaign( cc );
             }
             
             close_campaign( cc );
             cc = NULL;
             break;
		
		case IDM_NEW:
/*
            if ( cc != NULL )
            {
              MessageBox( hwnd, "There is an active campaign! Try closing it first!", "Error!", MB_OK );
              break;
            }

             DialogBox(hInstance,MAKEINTRESOURCE(IDD_NEW),hWindow,NewDlg);*/

             if ( random_range(1,2) == 1 )
               c = NewChild("Child");
             else
               c = NewChild("");
             
             /* activate this child! */
             SendMessage(hClient, (UINT) WM_MDIACTIVATE, (WPARAM) (HWND)c, 0);
             break;
		
        case IDM_DICE:
             DialogBox(hInstance,MAKEINTRESOURCE(IDD_DICE),hWindow,DiceDlg);
             break;

		case IDM_ABOUT:
			DialogBox(hInstance,MAKEINTRESOURCE(IDD_ABOUT),hWindow,AboutDlg);
			break;

		case IDM_OPEN:
            if ( cc != NULL ) /* we already have a campaign?! */
            {
                char buf[64];
                sprintf( buf, "There is already another open and active campaign! Would you like to close and save it to start another?" );

                if ( MessageBox(hwnd, buf, "Close and Save?", MB_YESNO ) == IDYES )
                {
                  save_campaign(cc);
                  close_campaign(cc);
                  cc = NULL;
                }
                else /* we obviously want to keep the current one going*/
                  break;
            }

		    if ( (GetFileName(buffer,sizeof(buffer))) != 0 )
		    {
              FILE *fp;
              
              if ( (fp = fopen(buffer,"r")) == NULL )
              {
#ifdef LOG
                L( "MainWndProc_OnCommand", "case IDM_OPEN: failed to open file!", 0 );
#endif
                MessageBox( hwnd, "Failed to open file. Try again.", "Failed!", MB_OK );
                break;
              }

              cc = NULL;

              /* cc is null, we have the file open, lets read */
              if ( (cc = open_campaign( fp )) == NULL )
              {
#ifdef LOG
                L( "MainWndProc_OnCommand", "case IDM_OPEN: failed to read file!", 0 );
#endif
                MessageBox( hwnd, "Failed to read file.", "Failed!", MB_OK );
                
                if ( cc != NULL )
                 close_campaign( cc );
              }
              
              break;
            }
#ifdef LOG
            else if ( CommDlgExtendedError() != 0 )
            {
              DWORD num = CommDlgExtendedError();
              log_entry( __FILE__, "MainWndProc_OnCommand", __LINE__, "case IDM_OPEN: failed to open file, CommDlgExtendedError number = %d", num);
            }
#endif
            break;

        case IDM_SAVE:
            if ( cc == NULL )
            {
              MessageBox( hwnd, "There is no active campaign! Try creating one or opening one first!", "Error!", MB_OK );
              break;
            }

             save_campaign(cc);
             break;
             
        case IDM_SAVEAS:
            if ( cc == NULL )
            {
              MessageBox( hwnd, "There is no active campaign! Try creating one or opening one first!", "Error!", MB_OK );
              break;
            }

		    if ( (GetSvFileName(buffer,sizeof(buffer))) != 0 )
		    {
               if ( !CHECK_STR(cc->filename) ) /* filename has data */
                DISPOSE(cc->filename);
                
               cc->filename = strdup(buffer);
               save_campaign(cc);
               break;
            }
#ifdef LOG
            else if ( CommDlgExtendedError() != 0 )
            {
              DWORD num = CommDlgExtendedError();
              log_entry( __FILE__, "MainWndProc_OnCommand", __LINE__, "case IDM_SAVEAS: failed, CommDlgExtendedError number = %d", num);
            }
#endif
             break;

		case IDM_EXIT:
             PostMessage(hwnd,WM_CLOSE,0,0);
		     break;
	}
}

LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
    HMENU menu = GetMenu(hwnd);
    RECT r;

	switch (msg)
    {
        case WM_TIMER: /* update menu bar */
            if ( cc != NULL ) /* we have an active campaign, no new ones */
            {
              /* disable */
              EnableMenuItem(menu, IDM_NEW, MF_BYCOMMAND|MF_GRAYED );

              /* restore these */
              EnableMenuItem(menu, IDM_SAVE, MF_BYCOMMAND|MF_ENABLED );
              EnableMenuItem(menu, IDM_SAVEAS, MF_BYCOMMAND|MF_ENABLED );
              EnableMenuItem(menu, IDM_CLOSE, MF_BYCOMMAND|MF_ENABLED );
              EnableMenuItem(menu, IDM_FIND, MF_BYCOMMAND|MF_ENABLED );
            }
            else /* no campaign, cannot save/save as/close/find */
            {
              /* restore! */
              EnableMenuItem(menu, IDM_NEW, MF_BYCOMMAND|MF_ENABLED );

              /* disable */
              EnableMenuItem(menu, IDM_FIND, MF_BYCOMMAND|MF_GRAYED );
              EnableMenuItem(menu, IDM_SAVE, MF_BYCOMMAND|MF_GRAYED );
              EnableMenuItem(menu, IDM_SAVEAS, MF_BYCOMMAND|MF_GRAYED );
              EnableMenuItem(menu, IDM_CLOSE, MF_BYCOMMAND|MF_GRAYED );
            }
            
            if ( get_active() == (HWND)NULL ) /* no child windows! */
            {
              EnableMenuItem(menu, IDM_WINDOWTILEH, MF_BYCOMMAND|MF_GRAYED );
              EnableMenuItem(menu, IDM_WINDOWTILEV, MF_BYCOMMAND|MF_GRAYED );
              EnableMenuItem(menu, IDM_WINDOWCASCADE, MF_BYCOMMAND|MF_GRAYED );
              EnableMenuItem(menu, IDM_WINDOWICONS, MF_BYCOMMAND|MF_GRAYED );
              EnableMenuItem(menu, IDM_WINDOWCLOSEALL, MF_BYCOMMAND|MF_GRAYED );
            }
            else /* yes child windows */
            {
              EnableMenuItem(menu, IDM_WINDOWTILEH, MF_BYCOMMAND|MF_ENABLED );
              EnableMenuItem(menu, IDM_WINDOWTILEV, MF_BYCOMMAND|MF_ENABLED );
              EnableMenuItem(menu, IDM_WINDOWCASCADE, MF_BYCOMMAND|MF_ENABLED );
              EnableMenuItem(menu, IDM_WINDOWICONS, MF_BYCOMMAND|MF_ENABLED );
              EnableMenuItem(menu, IDM_WINDOWCLOSEALL, MF_BYCOMMAND|MF_ENABLED );
            }

             /* draw window */
             GetClientRect(hWindow, &r);
             InvalidateRect(hWindow, &r, FALSE);

             /*draw client area*/
             GetClientRect(hClient, &r);
             InvalidateRect(hClient, &r, FALSE);

             /* draw status bar */
             BringWindowToTop(hWndStatusbar);

             GetClientRect(hWndStatusbar, &r);
             InvalidateRect(hWndStatusbar, &r, FALSE);
             
            break;


    	case WM_SIZE:
    		SendMessage(hWndStatusbar,msg,wParam,lParam);
    		SendMessage(hwndToolBar,msg,wParam,lParam);
    		InitializeStatusBar(hWndStatusbar,1);
    		DefFrameProc(hwnd,hClient,msg,wParam,lParam);
    		break;
    		
    	case WM_MENUSELECT:
    		return MsgMenuSelect(hwnd,msg,wParam,lParam);
    		
        case WM_MENUCHAR:
             DefFrameProc(hwnd,hClient,msg,wParam,lParam);
             break;

        case WM_SETFOCUS:
             DefFrameProc(hwnd,hClient,msg,wParam,lParam);
             break;
        	
    	case WM_COMMAND:
    		HANDLE_WM_COMMAND(hwnd,wParam,lParam,MainWndProc_OnCommand);
    		DefFrameProc(hwnd,hClient,msg,wParam,lParam);
    		break;
    		
    	case WM_DESTROY:
            cleanup();
    		PostQuitMessage(0);
    		break;
    		
    	default:
    		return DefFrameProc(hwnd,hClient,msg,wParam,lParam);
	}
	return 0;
}

#define NUM_TOOLBAR_BUTTONS		14

HWND CreateAToolBar(HWND hwndParent)
{ 
	HWND hwndTB; 
	TBADDBITMAP tbab; 
	TBBUTTON tbb[NUM_TOOLBAR_BUTTONS]; 
	int index; 
 
	// Ensure that the common control DLL is loaded. 
	InitCommonControls(); 
 
	// Create a toolbar that the user can customize and that has a 
	// tooltip associated with it. 
	hwndTB = CreateWindowEx(0, TOOLBARCLASSNAME, (LPSTR) NULL, 
	    WS_CHILD|WS_BORDER|CCS_ADJUSTABLE, 
	    0, 0, 0, 0, hwndParent, (HMENU) ID_TOOLBAR, hInstance, NULL);
 
	// Send the TB_BUTTONSTRUCTSIZE message, which is required for 
	// backward compatibility. 
	SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, 
	    (WPARAM) sizeof(TBBUTTON), 0); 
 
	// Add the bitmap containing button images to the toolbar. 
	tbab.hInst = HINST_COMMCTRL; 
	tbab.nID   = IDB_STD_SMALL_COLOR; 
	SendMessage(hwndTB, TB_ADDBITMAP, (WPARAM) NUM_TOOLBAR_BUTTONS,(LPARAM) &tbab); 

	// clean memory before using it
	memset(tbb,0,sizeof tbb);
 
	// Add the strings
 
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Undo");
	tbb[0].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Replace");
	tbb[1].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Redo");
	tbb[2].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Properties");
	tbb[3].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Print preview");
	tbb[4].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Print");
	tbb[5].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Paste");
	tbb[6].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Help");
	tbb[7].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Find");
	tbb[8].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Open");
	tbb[9].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"New");
	tbb[10].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Delete");
	tbb[11].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Cut");
	tbb[12].iString = index;
	index = SendMessage(hwndTB,TB_ADDSTRING,0,(LPARAM)"Copy");
	tbb[13].iString = index;
	// Button "Undo"
	tbb[0].iBitmap = STD_UNDO;
	tbb[0].idCommand = IDM_EDITUNDO;
	tbb[0].fsState = TBSTATE_ENABLED;
	tbb[0].fsStyle = TBSTYLE_BUTTON;
	
	// Button "Replace"
	tbb[1].iBitmap = STD_REPLACE;
	tbb[1].idCommand = IDM_EDITREPLACE;
	tbb[1].fsState = TBSTATE_ENABLED;
	tbb[1].fsStyle = TBSTYLE_BUTTON;
	
	// Button "Redo"
	tbb[2].iBitmap = STD_REDOW;
	tbb[2].idCommand = IDM_EDITREDO;
	tbb[2].fsState = TBSTATE_ENABLED;
	tbb[2].fsStyle = TBSTYLE_BUTTON;
	
	// Button "Properties"
	tbb[3].iBitmap = STD_PROPERTIES;
	tbb[3].idCommand = IDM_PROPERTIES;
	tbb[3].fsState = TBSTATE_ENABLED;
	tbb[3].fsStyle = TBSTYLE_BUTTON;
	
	// Button "Print preview"
	tbb[4].iBitmap = STD_PRINTPRE;
	tbb[4].idCommand = IDM_PRINTPRE;
	tbb[4].fsState = TBSTATE_ENABLED;
	tbb[4].fsStyle = TBSTYLE_BUTTON;
	
	// Button "Print"
	tbb[5].iBitmap = STD_PRINT;
	tbb[5].idCommand = IDM_PRINT;
	tbb[5].fsState = TBSTATE_ENABLED;
	tbb[5].fsStyle = TBSTYLE_BUTTON;
	
	// Button "Paste"
	tbb[6].iBitmap = STD_PASTE;
	tbb[6].idCommand = IDM_EDITPASTE;
	tbb[6].fsState = TBSTATE_ENABLED;
	tbb[6].fsStyle = TBSTYLE_BUTTON;
	
	// Button "Help"
	tbb[7].iBitmap = STD_HELP;
	tbb[7].idCommand = IDM_HELP;
	tbb[7].fsState = TBSTATE_ENABLED;
	tbb[7].fsStyle = TBSTYLE_BUTTON;
	
	// Button "Find"
	tbb[8].iBitmap = STD_FIND;
	tbb[8].idCommand = IDM_FIND;
	tbb[8].fsState = TBSTATE_ENABLED;
	tbb[8].fsStyle = TBSTYLE_BUTTON;
	
	// Button "Open"
	tbb[9].iBitmap = STD_FILEOPEN;
	tbb[9].idCommand = IDM_OPEN;
	tbb[9].fsState = TBSTATE_ENABLED;
	tbb[9].fsStyle = TBSTYLE_BUTTON;
	
	// Button "New"
	tbb[10].iBitmap = STD_FILENEW;
	tbb[10].idCommand = IDM_NEW;
	tbb[10].fsState = TBSTATE_ENABLED;
	tbb[10].fsStyle = TBSTYLE_BUTTON;
	
	// Button "Delete"
	tbb[11].iBitmap = STD_DELETE;
	tbb[11].idCommand = IDM_EDITDELETE;
	tbb[11].fsState = TBSTATE_ENABLED;
	tbb[11].fsStyle = TBSTYLE_BUTTON;
	
	// Button "Cut"
	tbb[12].iBitmap = STD_CUT;
	tbb[12].idCommand = IDM_EDITCUT;
	tbb[12].fsState = TBSTATE_ENABLED;
	tbb[12].fsStyle = TBSTYLE_BUTTON;
	
	// Button "Copy"
	tbb[13].iBitmap = STD_COPY;
	tbb[13].idCommand = IDM_EDITCOPY;
	tbb[13].fsState = TBSTATE_ENABLED;
	tbb[13].fsStyle = TBSTYLE_BUTTON;
	
	SendMessage(hwndTB,TB_ADDBUTTONS,14,(LPARAM)&tbb);
	ShowWindow(hwndTB,SW_SHOW);
	return hwndTB;
}

/*<---------------------------------------------------------------------->*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
{
	MSG msg;
	HANDLE hAccelTable;
	BOOL bRet;

	hInstance = hInstance;
	
	if (!InitApplication())
	{
#ifdef LOG
        glog( "Failed initapplication!" );
#endif
		return 0;
    }
		
	hAccelTable = LoadAccelerators(hInstance,MAKEINTRESOURCE(IDACCEL));
	
	if ((hWindow = CreateMainWnd()) == (HWND)0)
	{
#ifdef LOG
        glog( "Failed to create the main window" );
#endif
		return 0;
    }

    if ((hClient = CreateClientWnd()) == (HWND)0)
    {
#ifdef LOG
        glog( "Failed to create the client window" );
#endif
        return 0;
    }
		
	CreateSBar(hWindow,"Ready",1);

    cc = NULL;

	/* seed random num gen */
	init_dice();
	
#ifdef LOG
#ifdef LOG_XLOG
	/* start the xml log */
	init_log();
#endif
#endif

    /* start timer */
    SetTimer(hWindow, T_ID, 100, NULL ); /* we want to keep our menu up to date */

    if ( exists_file("save") == FALSE ) /* does the save directory exist? */
     system( "mkdir save" );
	
	/* no tool bar just yet */
	hwndToolBar = NULL; //CreateAToolBar(hWindow);

	ShowWindow(hWindow, SW_SHOW);
	ShowWindow(hClient, SW_SHOW);
	
	while ((bRet = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0 )
    {
        if ( bRet == -1 )
        {
             /* error! */
        }
        else
        {
   		if (!TranslateMDISysAccel(hClient, &msg) && !TranslateAccelerator(hWindow,hAccelTable,&msg))
            {
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
        }
	}
	return msg.wParam;
}

/* cleanup this prog */
void cleanup( void )
{
  KillTimer(hWindow,T_ID); /* stop timer */

  if ( cc != NULL ) /* clear out current campaign stuff */
  {
    if ( cc->modified == TRUE )
      if ( MessageBox(hWindow, "The active campaign has been modified, would you like to save the changes?", "Save Changes?", MB_YESNO ) == IDYES )
        save_campaign(cc);
        
    close_campaign(cc);
  }

  cleanup_children();

#ifdef LOG
#ifdef LOG_XLOG
  L( "Cleanup", "Ending XML Log", 0 );
  end_log(); /* end xml log */
#endif
#endif
}

/*** RANDOM FUNCTIONS ***/
#include <sys/types.h>
#include <time.h>

/* local seed variable, used to create pseudo random numbers */
static unsigned int iSeed;

double rand_seed   ( void );

/* returns a random number between a and b */
int random_range(int a, int b)
{
  return ((int)(rand_seed() * ((double) (b) - (a) + 1))) + (a);
}

/* return a random number between 1 and 100 */
int random_percent( void )
{
  return random_range(1, 100);
}

/* Roll some amount of dices of a specific size */
int roll_dice(int amount, int size)
{
  int i;
  int result = 0;

  for (i = 1; i <= amount; i++)
    result += random_range(1, size);

  return result;
}

/* this function initializes the randomize functions */
void init_dice()
{
  iSeed = (unsigned int) time(NULL);
  srand(time(NULL));
}

/* Local function that returns a random double between 0 and 1 */
double rand_seed()
{
  static unsigned int a = 1588635695, m = 4294967291U, q = 2, r = 1117695901;

  iSeed = a * (iSeed % q) - r * (iSeed / q);

  return ((double) iSeed / (double) m);
}