/******************************************************************************/
/*                                                                            */
/*  CB_FRAME - Callback for the FRAME window                                  */
/*                                                                            */
/******************************************************************************/

#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"
#include "extern.h"

static int disallow_menu = 0 ;

extern "C"

BOOL CALLBACK CloseAllProc ( HWND hwnd , LPARAM lParam ) ;

LRESULT CALLBACK FrameWndProc ( HWND hwnd , UINT message ,
                                WPARAM wParam , LPARAM lParam )
{
   int ret_val, menu_state ;
   char msg[1024], filename[1024], title[256] ;
   CLIENTCREATESTRUCT ccs ;   // For creating client window
   MDICREATESTRUCT mcs ;      // For creating child window
   RECT rect ;
   HWND hwndChild ;
   Image *imgptr ;
   
   switch (message) {
       
      case WM_CREATE:                             // Create CLIENT window
         ccs.hWindowMenu = hMenuInitWindow ;
         ccs.idFirstChild = IDM_FIRSTCHILD ;
         hwndClient = CreateWindow ( "MDICLIENT" , NULL ,
            WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL ,
            0 , 0 , 0 , 0 , hwnd , NULL , hInst , (LPSTR) &ccs ) ;
         return 0 ;

      case WM_COMMAND :
         switch ( LOWORD ( wParam )) {

            case IDM_COMPUTE_ER:
               ret_val = (int) DialogBox ( hInst , "DialogBoxERParams" ,
                                           hwnd , DialogERParams ) ;
               if (! ret_val)
                  return 0 ;  // User canceled
               if (ER_params.depth < 0  ||  ER_params.angle < 0.0  ||  ER_params.angle > 90.0) {
                  MessageBox ( hwnd , "Depth must not be negative, and angle must be 0-90" ,
                     "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;  // User canceled
                  }
               if (ER_params.width < 1) {
                  MessageBox ( hwnd , "Line width must be at least 1" ,
                     "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;  // User canceled
                  }
               if (strlen ( ER_params.axiom ) == 0) {
                  MessageBox ( hwnd , "No axiom specified" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;  // User canceled
                  }
               if (ER_params.depth  &&  strlen ( ER_params.primary ) == 0) {
                  MessageBox ( hwnd , "No primary specified" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;  // User canceled
                  }
               sprintf_s ( msg, "Edge rewriting image %d rows by %d columns  Depth=%d  Angle=%.2lf",
                           ER_params.nrows, ER_params.ncols, ER_params.depth, ER_params.angle ) ;
               strcpy_s ( title , msg ) ;
               audit ( "" ) ;
               audit ( "--------------------> Beginning new project <------------------" ) ;
               audit ( "" ) ;
               audit ( msg ) ;
               sprintf_s ( msg, "Axiom: %s", ER_params.axiom ) ;
               audit ( msg ) ;
               sprintf_s ( msg, "Primary: %s", ER_params.primary ) ;
               audit ( msg ) ;
               sprintf_s ( msg, "Secondary: %s", ER_params.secondary ) ;
               audit ( msg ) ;
               if (ER_params.bad_rule) {
                  MessageBox ( hwnd , "An illegal rule was specified; see LIN.LOG" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;
                  }
               disallow_menu = 1 ;
               imgptr = new Image8 ( &ER_params ) ;
               disallow_menu = 0 ;

               if ((imgptr == NULL)  ||  ! imgptr->valid()) {
                  if (imgptr != NULL)
                     delete imgptr ;
                  return 0 ;
                  }

               if (imgptr->error_code) {
                  if (imgptr->error_code == ERROR_INSUFFICIENT_MEMORY)
                     MessageBox ( hwnd , "Insufficient memory" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  if (imgptr->error_code == ERROR_REFERENCE_NO_SECONDARY)
                     MessageBox ( hwnd , "Secondary referenced but not present; see LIN.LOG" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  else if (imgptr->error_code == ERROR_INVALID_PRODUCTION_OPERATION)
                     MessageBox ( hwnd , "An invalid production appeared; see LIN.LOG" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  delete imgptr ;
                  return 0 ;
                  }

               GetClientRect ( hwndClient , &rect ) ;
               mcs.szClass = szImageClass ;
               mcs.szTitle = title ;
               mcs.hOwner = hInst ;
               mcs.x = CW_USEDEFAULT ;
               mcs.y = CW_USEDEFAULT ;
               if (rect.bottom <= rect.right) {  // Usual situation
                  mcs.cx = 2 * rect.bottom / 3 ;
                  mcs.cy = 2 * rect.bottom / 3 ;
                  }
               else {
                  mcs.cx = 2 * rect.right / 3 ;
                  mcs.cy = 2 * rect.right / 3 ;
                  }
               mcs.style = 0 ;
               mcs.lParam = (LPARAM) imgptr ;
               hwndChild = (HWND) SendMessage ( hwndClient , WM_MDICREATE ,
                                     0 , (LPARAM) (LPMDICREATESTRUCT) &mcs ) ;
               if (! hwndChild) {
                  MessageBox ( hwnd , "Insufficient memory to create lin image" ,
                     "Abandoning this image", MB_ICONEXCLAMATION | MB_OK);
                  delete imgptr ;
                  }
               return 0 ;

            case IDM_COMPUTE_AG:
               ret_val = (int) DialogBox ( hInst , "DialogBoxAGParams" ,
                                           hwnd , DialogAGParams ) ;
               if (! ret_val)
                  return 0 ;  // User canceled
               if (AG_params.depth < 0  ||  AG_params.angle < 0.0  ||  AG_params.angle > 90.0) {
                  MessageBox ( hwnd , "Depth must not be negative, and angle must be 0-90" ,
                     "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;  // User canceled
                  }
               if (AG_params.width < 1) {
                  MessageBox ( hwnd , "Line width must be at least 1" ,
                     "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;  // User canceled
                  }
               if (strlen ( AG_params.axiom ) == 0) {
                  MessageBox ( hwnd , "No axiom specified" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;  // User canceled
                  }
               if (AG_params.depth  &&  strlen ( AG_params.primary ) == 0) {
                  MessageBox ( hwnd , "No primary specified" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;  // User canceled
                  }
               sprintf_s ( msg, "Axial growth image %d rows by %d columns  Depth=%d  Angle=%.2lf  Shrink=%.3lf",
                           AG_params.nrows, AG_params.ncols, AG_params.depth, AG_params.angle, AG_params.shrink ) ;
               strcpy_s ( title , msg ) ;
               audit ( "" ) ;
               audit ( "--------------------> Beginning new project <------------------" ) ;
               audit ( "" ) ;
               audit ( msg ) ;
               sprintf_s ( msg, "Axiom: %s", AG_params.axiom ) ;
               audit ( msg ) ;
               sprintf_s ( msg, "Primary: %s", AG_params.primary ) ;
               audit ( msg ) ;
               sprintf_s ( msg, "Secondary: %s", AG_params.secondary ) ;
               audit ( msg ) ;
               if (AG_params.bad_rule) {
                  MessageBox ( hwnd , "An illegal rule was specified; see LIN.LOG" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;
                  }
               disallow_menu = 1 ;
               imgptr = new Image8 ( &AG_params ) ;
               disallow_menu = 0 ;

               if ((imgptr == NULL)  ||  ! imgptr->valid()) {
                  MessageBox ( hwnd , "Serious error; see LIN.LOG" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  if (imgptr != NULL) {
                     delete imgptr ;
                     imgptr = NULL ;
                     }
                  return 0 ;
                  }

               if (imgptr  &&  imgptr->error_code) {
                  if (imgptr->error_code == ERROR_INSUFFICIENT_MEMORY)
                     MessageBox ( hwnd , "Insufficient memory" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  else if (imgptr->error_code == ERROR_REFERENCE_NO_SECONDARY)
                     MessageBox ( hwnd , "Secondary referenced but not present; see LIN.LOG" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  else if (imgptr->error_code == ERROR_INVALID_PRODUCTION_OPERATION)
                     MessageBox ( hwnd , "An invalid production appeared; see LIN.LOG" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  delete imgptr ;
                  return 0 ;
                  }

               GetClientRect ( hwndClient , &rect ) ;
               mcs.szClass = szImageClass ;
               mcs.szTitle = title ;
               mcs.hOwner = hInst ;
               mcs.x = CW_USEDEFAULT ;
               mcs.y = CW_USEDEFAULT ;
               if (rect.bottom <= rect.right) {  // Usual situation
                  mcs.cx = 2 * rect.bottom / 3 ;
                  mcs.cy = 2 * rect.bottom / 3 ;
                  }
               else {
                  mcs.cx = 2 * rect.right / 3 ;
                  mcs.cy = 2 * rect.right / 3 ;
                  }
               mcs.style = 0 ;
               mcs.lParam = (LPARAM) imgptr ;
               hwndChild = (HWND) SendMessage ( hwndClient , WM_MDICREATE ,
                                     0 , (LPARAM) (LPMDICREATESTRUCT) &mcs ) ;
               if (! hwndChild) {
                  MessageBox ( hwnd , "Insufficient memory to create lin image" ,
                     "Abandoning this image", MB_ICONEXCLAMATION | MB_OK);
                  delete imgptr ;
                  }
               return 0 ;

            case IDM_COMPUTE_AG3D:
               filename[0] = 0 ;
               if (name_3DAG_file ( hwnd , filename )) {
                  ret_val = read_3DAG ( filename ) ;  // Read and parse the definition file
                  if (ret_val) {  // Error
                     MessageBox ( hwnd , "Error reading or processing file.  See LIN.LOG for details." ,
                                  "ERROR", MB_ICONEXCLAMATION | MB_OK);
                     return 0 ;
                     }
                  }
               if (AG3D_params.n_axiom == 0)   // No sense proceeding if no object definition
                  return 0 ;
               ret_val = (int) DialogBox ( hInst , "DialogBox3DAGParams" ,
                                           hwnd , Dialog3DAGParams ) ;
               if (! ret_val)
                  return 0 ;  // User canceled
               if (AG3D_params.depth < 0  ||  AG3D_params.angle < 0.0  ||  AG3D_params.angle > 90.0) {
                  MessageBox ( hwnd , "Depth must not be negative, and angle must be 0-90" ,
                     "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;  // User canceled
                  }
               if (AG3D_params.width < 1) {
                  MessageBox ( hwnd , "Line width must be at least 1" ,
                     "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;  // User canceled
                  }
               if (AG3D_params.azimuth < 0.0  ||  AG3D_params.azimuth > 360.0) {
                  MessageBox ( hwnd , "Azimuth must be 0-360" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;  // User canceled
                  }
               if (AG3D_params.elevation < 0.0  ||  AG3D_params.elevation > 90.0) {
                  MessageBox ( hwnd , "Elevation must be 0-90" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;  // User canceled
                  }
               sprintf_s ( msg, "3D AG %d by %d Angle=%.2lf Depth=%d Shrink=%.3lf Step=%.3lf Az=%.3lf El=%.3lf",
                           AG3D_params.nrows, AG3D_params.ncols, AG3D_params.angle, AG3D_params.depth, AG3D_params.shrink, AG3D_params.stepsize, AG3D_params.azimuth, AG3D_params.elevation ) ;
               strcpy_s ( title , msg ) ;
               audit ( msg ) ;
               if (AG3D_params.bad_rule) {
                  MessageBox ( hwnd , "An illegal rule was specified; see LIN.LOG" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  return 0 ;
                  }
               disallow_menu = 1 ;
               imgptr = new Image24 ( &AG3D_params ) ;
               disallow_menu = 0 ;

               if ((imgptr == NULL)  ||  ! imgptr->valid()) {
                  MessageBox ( hwnd , "Serious error; see LIN.LOG" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  if (imgptr != NULL) {
                     delete imgptr ;
                     imgptr = NULL ;
                     }
                  return 0 ;
                  }

               if (imgptr  &&  imgptr->error_code) {
                  if (imgptr->error_code == ERROR_INSUFFICIENT_MEMORY)
                     MessageBox ( hwnd , "Insufficient memory" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  else if (imgptr->error_code == ERROR_INVALID_PRODUCTION_OPERATION)
                     MessageBox ( hwnd , "An invalid production appeared; see LIN.LOG" , "ERROR", MB_ICONEXCLAMATION | MB_OK);
                  delete imgptr ;
                  return 0 ;
                  }

               GetClientRect ( hwndClient , &rect ) ;
               mcs.szClass = szImageClass ;
               mcs.szTitle = title ;
               mcs.hOwner = hInst ;
               mcs.x = CW_USEDEFAULT ;
               mcs.y = CW_USEDEFAULT ;
               if (rect.bottom <= rect.right) {  // Usual situation
                  mcs.cx = 2 * rect.bottom / 3 ;
                  mcs.cy = 2 * rect.bottom / 3 ;
                  }
               else {
                  mcs.cx = 2 * rect.right / 3 ;
                  mcs.cy = 2 * rect.right / 3 ;
                  }
               mcs.style = 0 ;
               mcs.lParam = (LPARAM) imgptr ;
               hwndChild = (HWND) SendMessage ( hwndClient , WM_MDICREATE ,
                                     0 , (LPARAM) (LPMDICREATESTRUCT) &mcs ) ;
               if (! hwndChild) {
                  MessageBox ( hwnd , "Insufficient memory to create lin image" ,
                     "Abandoning this image", MB_ICONEXCLAMATION | MB_OK);
                  delete imgptr ;
                  }
               return 0 ;

            case IDM_SAVEIMAGE:
               filename[0] = 0 ;
               if (! save_img_file ( hwnd , filename )) // Get file name
                  return 0 ;
               hwndChild = (HWND) SendMessage ( hwndClient , WM_MDIGETACTIVE ,
                           0 , 0 ) ;
               if (hwndChild == NULL)
                  return 0 ;
               imgptr = (Image *) GetWindowLongPtr ( hwndChild , 0 ) ;
               sprintf_s ( msg, "Save lin image file %s", filename ) ;
               audit ( msg ) ;
               disallow_menu = 1 ;
               imgptr->write_bmp ( filename ) ;     // Write the file
               disallow_menu = 0 ;
               return 0 ;

            case IDM_PRINTIMAGE:
               ret_val = (int) DialogBox ( hInst , "DialogBoxPrintParams" ,
                                           hwnd , DialogPrintParams ) ;
               if (! ret_val)
                  return 0 ;  // User canceled
               hwndChild = (HWND) SendMessage ( hwndClient , WM_MDIGETACTIVE , 0 , 0 ) ;
               if (hwndChild == NULL)
                  return 0 ;
               imgptr = (Image *) GetWindowLongPtr ( hwndChild , 0 ) ;
               if (initialize_for_printing ( hwnd )) // Err setting up printer?
                  return 0 ;
               disallow_menu = 1 ;
               imgptr->draw ( hwnd , 1 ) ;
               end_printing ( hwnd ) ;
               disallow_menu = 0 ;
               return 0 ;

            case IDM_CASCADE:            // Pass on arrangement command
               SendMessage ( hwndClient , WM_MDICASCADE , 0 , 0 ) ;
               return 0 ;

            case IDM_TILE:               // Pass on arrangement command
               SendMessage ( hwndClient , WM_MDITILE , 0 , 0 ) ;
               return 0 ;

            case IDM_CLOSE:  // This is a menu item, not currently used ???!!!!!!
               hwndChild = (HWND) SendMessage ( hwndClient , WM_MDIGETACTIVE ,
                           0 , 0 ) ;
               SendMessage ( hwndClient , WM_MDIDESTROY ,
                             (WPARAM) hwndChild , 0 ) ;
               return 0 ;

            case IDM_CLOSEALL:           // Close all child windows
               EnumChildWindows ( hwndClient , CloseAllProc , 0 ) ;
               return 0 ;

            case IDM_EXIT:               // Exit to Windows
               PostMessage ( hwnd , WM_CLOSE , 0 , 0 ) ;
               return 0 ;

            case IDM_ABOUT:
               modal_dialog_is_active = 1 ;
               DialogBox ( hInst , "DialogBoxAbout" , hwnd , DialogAbout ) ;
               modal_dialog_is_active = 0 ;
               return 0 ;

            default: // This is under WM_COMMAND.  Pass msg to active child.
               hwndChild = (HWND) SendMessage ( hwndClient , WM_MDIGETACTIVE ,
                           0 , 0 ) ;
               if (IsWindow ( hwndChild ))
                  SendMessage ( hwndChild , WM_COMMAND , wParam , lParam ) ;
               break ;   // Must also let DefFrameProc see it
            } // Switch on WM_COMMAND
         break ; // Case WM_COMMAND ;
              
      case WM_CLOSE:
         // If we allow the user to abort CLOSEALL, check here to see if any left
         SendMessage ( hwnd , WM_COMMAND , IDM_CLOSEALL , 0 ) ;
         break ;  // DefFrameProc will call DestroyWindow

      case WM_DESTROY:
         DestroyMenu ( hMenuInit ) ;  // Not needed?
         PostQuitMessage ( 0 ) ;
         return 0 ;

      case WM_INITMENUPOPUP :
         if (GetSubMenu(GetMenu(hwnd), (int) lParam) == hMenuInitFile) {
            hwndChild = (HWND) SendMessage ( hwndClient , WM_MDIGETACTIVE , 0 , 0 ) ;
            menu_state = (hwndChild != NULL)  ?   MF_ENABLED : MF_GRAYED ;
            EnableMenuItem ( (HMENU) wParam , IDM_SAVEIMAGE , menu_state ) ;
            EnableMenuItem ( (HMENU) wParam , IDM_PRINTIMAGE , menu_state ) ;
            if (disallow_menu) {
               EnableMenuItem ( (HMENU) wParam , IDM_SAVEIMAGE , MF_GRAYED ) ;
               EnableMenuItem ( (HMENU) wParam , IDM_PRINTIMAGE , MF_GRAYED ) ;
               EnableMenuItem ( (HMENU) wParam , IDM_EXIT , MF_GRAYED ) ;
               }
            }
         else if (GetSubMenu(GetMenu(hwnd), (int) lParam) == hMenuInitImage) {
            EnableMenuItem ( (HMENU) wParam , IDM_COMPUTE_ER , MF_ENABLED ) ;
            EnableMenuItem ( (HMENU) wParam , IDM_COMPUTE_AG , MF_ENABLED ) ;
            EnableMenuItem ( (HMENU) wParam , IDM_COMPUTE_AG3D , MF_ENABLED ) ;
            if (disallow_menu) {
               EnableMenuItem ( (HMENU) wParam , IDM_COMPUTE_ER , MF_GRAYED ) ;
               EnableMenuItem ( (HMENU) wParam , IDM_COMPUTE_AG , MF_GRAYED ) ;
               EnableMenuItem ( (HMENU) wParam , IDM_COMPUTE_AG3D , MF_GRAYED ) ;
               }
            }
         return 0 ;
      } // Switch on message

   return DefFrameProc ( hwnd , hwndClient , message , wParam , lParam ) ;
}

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

   Local routine called by EnumChildWindows to close all

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

BOOL CALLBACK CloseAllProc ( HWND hwnd , LPARAM /* lParam */ )
{
/*
   The first step here is tricky.  If a child window has been minimized, its
   icon is owned by the child.  Nevertheless, the icon appears in the
   enumeration.  So we must check for this situation to avoid two destroys.
*/

   if (GetWindow ( hwnd , GW_OWNER ))  // Child window cannot be owned
      return 1 ;                       // Check for icon title (Petzold pg 893)
                                       // Also see v. 1 pg 570

   // Here is where we could ask the user for verification of close
   SendMessage ( hwndClient , WM_MDIDESTROY , (WPARAM) hwnd , 0 ) ;
   return 1 ;  // Flag to continue enumerating
}
