/******************************************************************************/
/*                                                                            */
/*  JULIA.CPP - This is the main 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 <malloc.h>
#include <new.h>
#include <float.h>
#include <process.h>

#include "const.h"
#include "classes.h"
#include "extern.h"
#include "funcdefs.h"
#include "julia.rh"

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

   Windows globals

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

HINSTANCE hInst = NULL ;      // Global copy of instance handle
HWND hwndMain = NULL ;        // Main window
HWND hwndWaitMessage = NULL ; // MESSAGES.CPP
HWND hwndProgress = NULL ;    // PROGRESS.CPP
HWND hwndMagnify = NULL ;     // MAGNIFY.CPP
int HelpDialogIsActive = 0 ;  // True when user selected a dialog box
int escape_key_pressed = 0 ;  // Set/reset in MESSAGES.CPP (user_pressed_escape)
int Executing = 0 ;           // Are we executing a cruncher that calls user_pressed_escape()?
PRINTDLG print_dlg ;          // Filled in PRINT.CPP
DOCINFO doc_info ;            // Ditto

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

   Mandel globals

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


/*
   Parameters
*/

int ObjectType ;          // 1=Mandelbrot; 2=Julia; 3=Mand quaternion; 4=Julia quaternion
int DwellVsBinary ;       // For Mandelbrot and Julia, dwell method versus binary MSETDIST
double BinaryThreshold ;  // For binary (MSETDIST), binary threshold
double JuliaR, JuliaI ;   // Julia parameter
unsigned int DwellLimit ; // Max dwell
double EscapeConstant ;   // Escape constant, usually 2
int QuatSmooth ;          // Smooth the quaternion display?
int BinaryDecomp ;        // Do binary decomposition
int Collapse ;            // Which quaternion dimension to collapse (0-3)
double Elevation ;        // Quaternion view angle 0-90
double Azimuth ;          // Ditto 0-360
PrintParams print_params ;  // Printing parameters

/*
   Location
*/

int DisplayedRows ;             // Actual number of rows displayed on monitor
int DisplayedCols ;             // And cols.  May not equal client rect if TrueAspect
int LocateHow ;                 // Locate via center (0) or limits (1)
double CentR, CentI ;           // Center
double MagR, MagI ;             // Magnification
double MinR, MaxR, MinI, MaxI ; // Limits
double rcentRT, icentRT, jcentRT, kcentRT, magnifRT ; // Quaternions
// These are for the rectangle
double MagCentR, MagCentI ;                 // Center
double MagMagR, MagMagI ;                   // Magnification
double MagMinR, MagMaxR, MagMinI, MagMaxI ; // Limits

/*
   Display
*/

int DisplayedObjectType ;         // 1=Mandelbrot; 2=Julia; 3=Mand quaternion; 4=Julia quaternion
int TrueAspect ;                  // As opposed to full screen use
int RowResolution ;               // Number of rows computed
int ColResolution ;               // And columns
unsigned char *raw_image = NULL ; // After processing dwells via color map
DIBimage *dib = NULL ;            // The image is here
double CmapStart = 0.0 ;          // Color map starting color, 0-360
int CmapNcolors = 16 ;            // Number of colors in rotation
double CmapFloor = 20.0 ;         // Floor brightness, 0-100 (percent)
unsigned int CmapNlinear = 10 ;   // Number of initial dwells treated linearly
unsigned int CmapNlog = 16 ;      // Number of subsequent dwells treated logarithmically
int Lighting ;                    // Quaternion lighting
                                  // 0 - No lighting; distance only
                                  // 1 - Single white light at eye (usually best)
                                  // 2 - RBG staggered around eye
                                  // 3 - Single white light above object
                                  // 4 - RGB staggered above object

/*
   Miscellaneous communication
*/

int out_by_escape, out_by_max, out_by_conv, out_by_loop ;  /* COUNTIT */
unsigned int *dwells ;   // Computed for Mandelbrot and Julia; used by COLORMAP.CPP
int disallow_menu = 0 ;

/*
   Memory
*/

extern int mem_keep_log ;        // Keep a log file?
extern char mem_file_name[256] ; // Log file name
extern INT64 mem_max_used ;      // Maximum memory ever in use


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

   Main entry point

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

INT WINAPI WinMain ( HINSTANCE hInstance , HINSTANCE /* hPrev */ ,
                     LPSTR /* szCmdLine */ , INT /* nCmdShow */ )
{
   FILE* fp;
   WNDCLASSEX wndclass ;
   HMENU hMenuMain = NULL ;
   MSG winmsg ;
   INITCOMMONCONTROLSEX iccs ;
   RECT rect ;
   SYSTEMTIME systime ;
   char line[256];
   char szWindowClass[] = "MANDELmain";

/*
   Set floating point properties and other default behaviors
*/

   _fpreset () ;    // For uniformity, begin by setting the default
   _control87 ( MCW_EM , MCW_EM ) ; // Mask all interrupts: avoid crash
   _control87 ( 0 , 0 ) ;

   _set_new_handler ( 0 ) ;      // Causes 'new' to return NULL versus exception

/*
   Initialize Windows globals
*/

   hInst = hInstance ;          // Keep a global copy of this instance's handle

/*
   Initialize MEM64.CPP
*/

   mem_max_used = 0 ;
   mem_keep_log = 1 ;
   _fullpath ( mem_file_name , "MEM.LOG" , 256 ) ;
   if (fopen_s ( &fp , mem_file_name , "wt" )) {
      mem_file_name[0] = 0 ;
      mem_keep_log = 0 ;
      }
   else {
      GetLocalTime ( &systime ) ;
      sprintf_s ( line , "JULIA memory log %s  %d/%d/%02d  %d:%02d:%02d" ,
         mem_file_name,
         systime.wMonth, systime.wDay, systime.wYear%100,
         systime.wHour, systime.wMinute, systime.wSecond ) ;
      fprintf ( fp , "%s", line ) ;
      fclose ( fp ) ;
      }

//   sprintf_s ( line , "JULIA log %d/%d/%02d  %d:%02d:%02d" ,
//         systime.wMonth, systime.wDay, systime.wYear%100,
//         systime.wHour, systime.wMinute, systime.wSecond ) ;
//   audit ( line ) ;

/*
   Initialize Julia globals
*/

   DisplayedObjectType = 0 ; // 1=Mandelbrot; 2=Julia; 3=Mand quaternion; 4=Julia quaternion
   ObjectType = 3 ;          // 1=Mandelbrot; 2=Julia; 3=Mand quaternion; 4=Julia quaternion
   DwellVsBinary = 1 ;       // For Mandelbrot and Julia, dwell method versus binary MSETDIST
   DwellLimit = 1000 ;
   BinaryThreshold = 1.0 ;   // For binary (MSETDIST), binary threshold
   EscapeConstant = 2.0 ;
   JuliaR = -.74543 ;
   JuliaI = .11301 ;
   LocateHow = 0 ;
   CentR = 0. ;
   CentI = 0. ;
   MagR = 0.5 ;
   MagI = 0.5 ;
   MinR = -2. ;
   MaxR = 2. ;
   MinI = -2. ;
   MaxI = 2. ;
   TrueAspect = 0 ;
   BinaryDecomp = 0 ;
   Collapse = 3 ;
   Elevation = 60 ;
   Azimuth = 30. ;
   QuatSmooth = 1 ;
   Lighting = 1 ;
   print_params.fraction = 80 ;
   print_params.vert_scaling = 100 ;


/*------------------------- INITIALIZE OTHER STUFF ---------------------------*/

   save_img_file_init () ;          // Initialize for user naming written file

   iccs.dwSize = sizeof(iccs) ;
   iccs.dwICC = ICC_PROGRESS_CLASS ;
//   InitCommonControlsEx ( &iccs ) ;

/*
   Register the main window class
*/

   wndclass.cbSize = sizeof(WNDCLASSEX) ;
   wndclass.style = CS_HREDRAW | CS_VREDRAW ;
   wndclass.lpfnWndProc = (WNDPROC) MsgProc ;
   wndclass.cbClsExtra = 0L ;
   wndclass.cbWndExtra = 0L ;
   wndclass.hInstance = hInst ;
   wndclass.hIcon = LoadIcon ( hInst , MAKEINTRESOURCE ( IDI_JULIA ) ) ;
   wndclass.hCursor = LoadCursor ( NULL , IDC_ARROW ) ;
   wndclass.hbrBackground = (HBRUSH) COLOR_APPWORKSPACE + 1 ;// Prettier loading
   wndclass.lpszMenuName = NULL ;
   wndclass.lpszClassName = szWindowClass ;
   wndclass.hIconSm = LoadIcon ( hInst , MAKEINTRESOURCE ( IDI_JULIA ) ) ;

   assert ( wndclass.hIcon != NULL ) ;
   assert ( wndclass.hIconSm != NULL ) ;
   assert ( wndclass.hCursor != NULL ) ;

   if (! RegisterClassEx ( &wndclass ))
      return FALSE ;

/*
   Load the menu and create the main window
*/

   hMenuMain = LoadMenu ( hInst , "MenuMain" ) ;
   assert ( hMenuMain != NULL ) ;

   hwndMain = CreateWindow ( szWindowClass ,
                         "JULIA 1.0  Copyright 2020 Timothy Masters",
                         WS_OVERLAPPEDWINDOW | WS_MAXIMIZE | WS_VISIBLE |
                         WS_CLIPCHILDREN ,
                         CW_USEDEFAULT , CW_USEDEFAULT ,
                         CW_USEDEFAULT , CW_USEDEFAULT ,
                         GetDesktopWindow() , hMenuMain , hInst , NULL ) ;
   assert ( hwndMain != NULL ) ;

   ShowWindow ( hwndMain, SW_SHOWMAXIMIZED ) ;
   UpdateWindow ( hwndMain ) ;

   GetClientRect ( hwndMain , &rect ) ;
   RowResolution = rect.bottom ;
   ColResolution = rect.right ;

   dwells = NULL ;
   raw_image = NULL ;

/*
   Message pump
*/

   // GetMessage does not return until a message appears in the queue.
   // Message processing during number crunching is handled by the
   // Translate/Dispatch calls in user_pressed_escape() via PeekMessage.
   while (GetMessage ( &winmsg , NULL , 0 , 0 )) {
      if ((hwndWaitMessage != NULL)  &&
           IsDialogMessage ( hwndWaitMessage , &winmsg ))
         continue ;
      if ((hwndProgress != NULL)  &&
           IsDialogMessage ( hwndProgress , &winmsg ))
         continue ;
      if ((hwndMagnify != NULL)  &&
           IsDialogMessage ( hwndMagnify , &winmsg ))
         continue ;
      TranslateMessage ( &winmsg ) ;
      DispatchMessage ( &winmsg ) ;
      }

/*
   All done.  Clean up and exit.
*/

   if (dwells != NULL)
      FREE ( dwells ) ;
   if (dib != NULL)
      delete dib ;
   if (raw_image != NULL)
      FREE ( raw_image ) ;
   MEMCLOSE () ;          // Terminate memory debugging
   UnregisterClass ( szWindowClass , hInst ) ;
   return 0 ;
}
