/******************************************************************************/
/*                                                                            */
/*  LIN - Main program module                                                 */
/*                                                                            */
/******************************************************************************/

#define STRICT
#include <windows.h>
#include <commctrl.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include "const.h"
#include "classes.h"
#include "funcdefs.h"
#include "lin.rh"


/*
   These are Windows things that are handy to have globally available.
   Their external declarations are in EXTERN.H.
*/

HINSTANCE hInst ;
HWND hwndFrame=NULL, hwndClient=NULL ;
HMENU hMenuInit=NULL, hMenuInitWindow=NULL, hMenuInitFile=NULL, hMenuInitImage=NULL ;

char szImageClass[] = "Image";

HWND hwndWaitMessage = NULL ;    // Handle of begin_wait_message() dialog box
int escape_key_pressed = 0 ;     // Did the user press ESCape?
int modal_dialog_is_active = 0 ; // Is a modal dialog up? See PROG_WIN.CPP
PRINTDLG print_dlg ;             // Filled in PRINT.CPP
DOCINFO doc_info ;               // Ditto

/*
   These are non-Windows globals
*/

ER_Params ER_params ;       // Parameters for edge replacement
AG_Params AG_params ;       // Parameters for axial growth
AG3D_Params AG3D_params ;   // Parameters for 3D axial growth
PrintParams print_params ;  // Printing parameters

Image *lin_img = NULL ;

HWND hwndLin = NULL ;

/*
   These are other Windows things that do not need to be global
*/

static char szFrameClass[] = "Frame";
static BOOL InitializeMDIstuff () ;


extern "C"

/*
--------------------------------------------------------------------------------

   Entry point

--------------------------------------------------------------------------------
*/

int WINAPI WinMain ( HINSTANCE hInstance , HINSTANCE /* hPrevInstance */ ,
                     LPSTR /* lpszCmdLine */ , int /* nCmdShow */ )

{
   int i, j, retcode, val ;
   int caps_bitspixel, caps_planes, caps_sizepalette ;
   int caps_numreserved, caps_colorres ;
   int ras_bitblt, ras_bitmap64, ras_di_bitmap ;
   int ras_palette, ras_stretchblt, ras_stretchdib ;

   char msg[256], tempmsg[256] ;
   MSG winmsg ;
   HDC hdc ;


/*
   Miscellaneous Windows inits
*/

   SetLastError ( 0 ) ;            // Start out clean to help debugging
   hInst = hInstance ;             // Keep a global copy of this instance's handle
//   InitCommonControlsEx () ;     // Make sure common control library loaded
   if (! InitializeMDIstuff ()) {  // Register window classes, get menu handles
      audit ( "Error initializing MDI" ) ;
      return FALSE ;
      }

/*
   Create the frame window.  Its WM_CREATE will create the preregistered
   client window.
*/

   hwndFrame = CreateWindow ( szFrameClass , "Lin 1.0",
                        WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN ,
                        CW_USEDEFAULT , CW_USEDEFAULT ,
                        CW_USEDEFAULT , CW_USEDEFAULT,
                        NULL , hMenuInit , hInst , NULL ) ;

   if (! hwndFrame) {
      audit ( "Error creating frame window" ) ;
      return FALSE ;
      }

   if (! hwndClient) {
      audit ( "Error creating client window" ) ;
      return FALSE ;
      }

/*
   Verify that the display device is ok for image display
*/

   hdc = GetDC ( hwndFrame ) ;
   if (! hdc) {
      audit ( "Error initializing display adapter" ) ;
      return FALSE ;
      }

   caps_bitspixel = GetDeviceCaps ( hdc , BITSPIXEL ) ;
   caps_planes = GetDeviceCaps ( hdc , PLANES ) ;
   caps_sizepalette = GetDeviceCaps ( hdc , SIZEPALETTE ) ;
   caps_numreserved = GetDeviceCaps ( hdc , NUMRESERVED ) ;
   caps_colorres = GetDeviceCaps ( hdc , COLORRES ) ;
   sprintf_s ( msg , "bits=%d planes=%d szpal=%d res=%d cols=%d",
               caps_bitspixel, caps_planes, caps_sizepalette,
               caps_numreserved, caps_colorres ) ;
   audit ( msg ) ;
   val = GetDeviceCaps ( hdc , RASTERCAPS ) ;
   ras_bitblt = val & RC_BITBLT ;
   ras_bitmap64 = val & RC_BITMAP64 ;
   ras_di_bitmap = val & RC_DI_BITMAP ;
   ras_palette = val & RC_PALETTE ;
   ras_stretchblt = val & RC_STRETCHBLT ;
   ras_stretchdib = val & RC_STRETCHDIB ;
   sprintf_s ( tempmsg ,
               "bitblt=%d bitmap64=%d DIbitmap=%d pal=%d StrBlt=%d StrDIB=%d",
               ras_bitblt, ras_bitmap64, ras_di_bitmap,
               ras_palette, ras_stretchblt, ras_stretchdib ) ;
   audit ( tempmsg ) ;

   ReleaseDC ( hwndFrame , hdc ) ;

   if ((caps_bitspixel < 8)  ||  (caps_planes > 1)) {
      audit ( "Incompatible video driver" ) ;
      retcode = NULL ;
      goto FINISH ;
      }

   ShowWindow ( hwndFrame , SW_SHOWMAXIMIZED ) ;

   UpdateWindow ( hwndFrame ) ;

/*
   Initializations
*/

   name_3DAG_file_init () ;         // Initialize for user naming 3DAG file
   save_img_file_init () ;          // Initialize for user naming written file

   ER_params.nrows = 500 ;
   ER_params.ncols = 500 ;
   ER_params.width = 3 ;
   ER_params.depth = 1 ;
   ER_params.angle = 90.0 ;
   strcpy_s ( ER_params.axiom , "" ) ;
   strcpy_s ( ER_params.primary , "" ) ;
   strcpy_s ( ER_params.secondary , "" ) ;

   AG_params.nrows = 500 ;
   AG_params.ncols = 500 ;
   AG_params.width = 3 ;
   AG_params.shrink = 1.0 ;
   AG_params.depth = 1 ;
   AG_params.angle = 90.0 ;
   strcpy_s ( AG_params.axiom , "" ) ;
   strcpy_s ( AG_params.primary , "" ) ;
   strcpy_s ( AG_params.secondary , "" ) ;


   AG3D_params.nrows = 500 ;
   AG3D_params.ncols = 500 ;
   AG3D_params.width = 3 ;
   AG3D_params.depth = 1 ;
   AG3D_params.bad_rule = 0 ;
   AG3D_params.angle = 22.5 ;
   AG3D_params.shrink = 1.0 ;
   AG3D_params.stepsize = 0.05 ;
   AG3D_params.azimuth = 0.0 ;
   AG3D_params.elevation = 0.0 ;
   AG3D_params.n_colors = 0 ;
   AG3D_params.axiom = NULL ;
   AG3D_params.erp = NULL ;
   AG3D_params.n_macros = 0 ;
   for (i=0 ; i<MAX_PRODUCTIONS ; i++) {
      AG3D_params.macro_nops[i] = 0 ;
      AG3D_params.macro_string[i] = NULL ;
      }
   AG3D_params.n_productions = 0 ;
   for (i=0 ; i<MAX_PRODUCTIONS ; i++) {
      for (j=0 ; j<MAX_RANDOMS ; j++) {
         AG3D_params.prod_nops[i][j] = 0 ;
         AG3D_params.prod_ops[i][j] = NULL ;
         }
      }

   print_params.fraction = 80 ;
   print_params.vert_scaling = 100 ;

/*
   Main message loop.
*/

   while (GetMessage ( &winmsg , NULL , 0 , 0 )) {
      TranslateMessage ( &winmsg ) ;
      DispatchMessage ( &winmsg ) ;
      }

   retcode = (int) winmsg.wParam ;

/*
   Done.  Clean up and return to Windows.
*/

FINISH:
   audit ( "" ) ;
   audit ( "LIN final cleanup..." ) ;
   for (i=0 ; i<AG3D_params.n_macros ; i++) {
      if (AG3D_params.macro_string[i] != NULL)
         free ( AG3D_params.macro_string[i] ) ;
      }
   if (AG3D_params.axiom != NULL)
      free ( AG3D_params.axiom ) ;
   if (AG3D_params.erp != NULL)
      free ( AG3D_params.erp ) ;
   for (i=0 ; i<AG3D_params.n_productions ; i++) {
      for (j=0 ; j<AG3D_params.prod_nrand[i] ; j++) {
         if (AG3D_params.prod_ops[i][j] != NULL)
            free ( AG3D_params.prod_ops[i][j] ) ;
         }
      }
   audit ( "LIN main terminating..." ) ;
   return retcode ;
}

/*
--------------------------------------------------------------------------------

   Local initialization routine registers frame and child windows
   It also loads from the resource the frame menus for initial state as well
   as all child states, along with the 'window' submenus of the frame menu.

--------------------------------------------------------------------------------
*/

static BOOL InitializeMDIstuff ()
{
   WNDCLASS wndclass ;

/*
   Frame
*/

   wndclass.style = CS_HREDRAW | CS_VREDRAW ;
   wndclass.lpfnWndProc = (WNDPROC) FrameWndProc ;
   wndclass.cbClsExtra = 0 ;
   wndclass.cbWndExtra = 0 ;
   wndclass.hInstance = hInst ;
   wndclass.hIcon = LoadIcon ( hInst , MAKEINTRESOURCE ( IDI_LIN ) ) ;
   wndclass.hCursor = LoadCursor ( NULL , IDC_ARROW ) ;
   wndclass.hbrBackground = (HBRUSH) COLOR_APPWORKSPACE + 1 ;// Prettier loading
   wndclass.lpszMenuName = NULL ;
   wndclass.lpszClassName = szFrameClass ;

   if (! RegisterClass ( &wndclass )) {
      audit ( "RegisterClass () for frame failed" ) ;
      return FALSE ;
      }

   hMenuInit = LoadMenu ( hInst , "MenuInit" ) ;
   if (! hMenuInit) {
      audit ( "LoadMenu () for frame failed" ) ;
      return FALSE ;
      }

/*
   The purpose of GetSubMenu is to get a pointer to the 'Window' menu selection.
   The MDI interface uses this to add the names of new child windows as they
   are added, allowing the user to click on any of them to activate it.
   We also get a few other menu handles for graying selections.
*/

   hMenuInitWindow = GetSubMenu ( hMenuInit , INIT_MENU_WINDOW_POS ) ;
   if (! hMenuInitWindow) {
      audit ( "GetSubMenu () for frame failed" ) ;
      return FALSE ;
      }

   hMenuInitFile = GetSubMenu ( hMenuInit , INIT_MENU_FILE_POS ) ;
   if (! hMenuInitFile) {
      audit ( "GetSubMenu () for frame failed" ) ;
      return FALSE ;
      }

   hMenuInitImage = GetSubMenu ( hMenuInit , INIT_MENU_IMAGE_POS ) ;
   if (! hMenuInitImage) {
      audit ( "GetSubMenu () for frame failed" ) ;
      return FALSE ;
      }

/*
   Image
*/

   wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNCLIENT ;
   wndclass.lpfnWndProc = (WNDPROC) ImageWndProc ;
   wndclass.cbClsExtra = 0 ;
   wndclass.cbWndExtra = sizeof (Image *) ; // Image callback WM_CREATE
   wndclass.hInstance = hInst ;
   wndclass.hIcon = LoadIcon ( NULL , IDI_APPLICATION ) ;
   wndclass.hCursor = LoadCursor ( NULL , IDC_ARROW ) ;
   wndclass.hbrBackground = (HBRUSH) GetStockObject ( WHITE_BRUSH ) ;
   wndclass.lpszMenuName = NULL ;
   wndclass.lpszClassName = szImageClass ;

   if (! RegisterClass ( &wndclass )) {
      return FALSE ;
      }

   return TRUE ;
}