#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include "resource.h"
#include "filedlg.h"

#define INIT_MENU_POS    0
#define CHILD_MENU_POS   1

#define UNTITLED_FORMAT  TEXT ("Untitled%d")
#define IDM_FIRSTCHILD   50000

LRESULT CALLBACK FrameWndProc  (HWND, UINT, WPARAM, LPARAM);
BOOL    CALLBACK CloseEnumProc (HWND, LPARAM);
LRESULT CALLBACK ChildWndProc  (HWND, UINT, WPARAM, LPARAM);

/* structure for storing data unique to each child window */
typedef struct tagDOCDATA
{
	TCHAR szFileName[MAX_PATH];
	TCHAR szFileTitle[MAX_PATH];
	BOOL  bNeedSave;
}DOCDATA, *PDOCDATA;

/* global variables */
TCHAR     szAppName[]    = TEXT ("MDIDemo");
TCHAR     szFrameClass[] = TEXT ("MdiFrame");
TCHAR     szChildClass[] = TEXT ("MdiChild");
HINSTANCE hInst;
HMENU     hMenuInit, hMenuChild;
HMENU     hMenuInitWindow, hMenuChildWindow;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
	HACCEL   hAccel;
	HWND     hwndFrame, hwndClient;
	MSG      msg;
	WNDCLASS wndclass;
	
	hInst = hInstance;
	
	/* Register the frame window class */   
	wndclass.style         = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc   = FrameWndProc;
	wndclass.cbClsExtra    = 0;
	wndclass.cbWndExtra    = 0;
	wndclass.hInstance     = hInstance;
	wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1);
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = szFrameClass;    
	if (!RegisterClass (&wndclass))
	{
		MessageBox (NULL, TEXT ("This program requires Windows NT!"),
		          szAppName, MB_ICONERROR);
		return 0;
	}
	
	/* Register the child window class */
	wndclass.style         = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc   = ChildWndProc;
	wndclass.cbClsExtra    = 0;
	wndclass.cbWndExtra    = sizeof (HANDLE);
	wndclass.hInstance     = hInstance;
	wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = szChildClass;        
	RegisterClass (&wndclass);
	
	/* Obtain handles to menus & submenus */
	hMenuInit  = LoadMenu (hInstance, TEXT ("MdiMenuInit"));
	hMenuChild = LoadMenu (hInstance, TEXT ("MdiMenuChild"));
	
	hMenuInitWindow  = GetSubMenu (hMenuInit,   INIT_MENU_POS);
	hMenuChildWindow = GetSubMenu (hMenuChild, CHILD_MENU_POS);
	
	/* Load accelerator table */
	hAccel = LoadAccelerators (hInstance, szAppName);
	
	/* Create the frame window */
	hwndFrame = CreateWindow (szFrameClass, szAppName,
	                       WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
	                       CW_USEDEFAULT, CW_USEDEFAULT,
	                       CW_USEDEFAULT, CW_USEDEFAULT,
	                       NULL, hMenuInit, hInstance, NULL);
	
	hwndClient = GetWindow (hwndFrame, GW_CHILD);
	
	ShowWindow (hwndFrame, iCmdShow);
	UpdateWindow (hwndFrame);
	
	/* Enter the modified message loop */
	while (GetMessage (&msg, NULL, 0, 0))
	{
		if (!TranslateMDISysAccel (hwndClient, &msg) &&
		  !TranslateAccelerator (hwndFrame, hAccel, &msg))
		{
		   TranslateMessage (&msg);
		   DispatchMessage (&msg);
		}
	}
	/* Clean up by deleting unattached menus */
	DestroyMenu (hMenuChild);
	
	return msg.wParam;
}
     
LRESULT CALLBACK FrameWndProc (HWND hwnd, UINT message, 
                               WPARAM wParam, LPARAM lParam)
{
     static HWND        hwndClient;
     static int			iTitleIndex;
     CLIENTCREATESTRUCT clientcreate;
     HWND               hwndChild;
     MDICREATESTRUCT    mdicreate;
     TCHAR				szTitle[MAX_PATH] = { 0 };
     TCHAR				szFileName[MAX_PATH] = { 0 };
     PDOCDATA      	 	pDocData;
          
     switch (message)
     {
     case WM_CREATE:           /* Create the client window */
          
		clientcreate.hWindowMenu  = hMenuInitWindow;
		clientcreate.idFirstChild = IDM_FIRSTCHILD;
		
		hwndClient = CreateWindow (TEXT ("MDICLIENT"), NULL,
		                         WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,   
		                         0, 0, 0, 0, hwnd, (HMENU) 1, hInst,
		                         (PSTR) &clientcreate);
		                         
  		/* Init file open/save dialog structure */
  		FileDlgInit( hwnd );
		return 0;

     case WM_COMMAND:
		switch (LOWORD (wParam))
		{
		case IDM_FILE_NEW:       /* Create/Open a new child window */
		case IDM_FILE_OPEN:
		
			if ((LOWORD (wParam) == IDM_FILE_OPEN) )
			{
				if( !FileOpenDlg (hwnd, szFileName, szTitle) )
					return 0;
			}
			else
		   		_stprintf( szTitle, UNTITLED_FORMAT, ++iTitleIndex );
		   	
			mdicreate.szClass = szChildClass;
			mdicreate.szTitle = szTitle;
			mdicreate.hOwner  = hInst;
			mdicreate.x       = CW_USEDEFAULT;
			mdicreate.y       = CW_USEDEFAULT;
			mdicreate.cx      = CW_USEDEFAULT;
			mdicreate.cy      = CW_USEDEFAULT;
			mdicreate.style   = 0;
			mdicreate.lParam  = (LPARAM)szFileName;
			
			hwndChild = (HWND) SendMessage (hwndClient,
			                   WM_MDICREATE, 0,
			                   (LPARAM) (LPMDICREATESTRUCT) &mdicreate);
		   	return 0;
		
	   	case IDM_FILE_SAVE:			/* Save the active document */
	   		hwndChild = (HWND) SendMessage (hwndClient,
			                               WM_MDIGETACTIVE, 0, 0);
      		pDocData = (PDOCDATA)GetWindowLong (hwndChild, 0);
      		lstrcpy( szTitle, pDocData->szFileTitle );
      		lstrcpy( szFileName, pDocData->szFileName );
      		if (FileSaveDlg (hwnd, szFileName, szTitle))
			{
				
			}
		   	return 0;
	   		
		case IDM_FILE_CLOSE:		/* Close the active window */
		   
			hwndChild = (HWND) SendMessage (hwndClient,
			                               WM_MDIGETACTIVE, 0, 0);
			
			if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0))
			    SendMessage (hwndClient, WM_MDIDESTROY,
			                 (WPARAM) hwndChild, 0);
			return 0;
		   
		case IDM_APP_EXIT:            /* Exit the program */
		   
			SendMessage (hwnd, WM_CLOSE, 0, 0);
			return 0;
			
			/* messages for arranging windows */
		
		case IDM_WINDOW_TILE:
			SendMessage (hwndClient, WM_MDITILE, 0, 0);
			return 0;
		   
		case IDM_WINDOW_CASCADE:
			SendMessage (hwndClient, WM_MDICASCADE, 0, 0);
			return 0;
		   
		case IDM_WINDOW_ARRANGE:
			SendMessage (hwndClient, WM_MDIICONARRANGE, 0, 0);
			return 0;
		   
		case IDM_WINDOW_CLOSEALL:     /* Attempt to close all children */
		   
			EnumChildWindows (hwndClient, CloseEnumProc, 0);
			return 0;
		   
		default:             /* Pass to active child... */
		   
			hwndChild = (HWND) SendMessage (hwndClient,
			                               WM_MDIGETACTIVE, 0, 0);
			
			if (IsWindow (hwndChild))
			    SendMessage (hwndChild, WM_COMMAND, wParam, lParam);
			
			break;        /* ...and then to DefFrameProc */
		}
		break;
          
     case WM_QUERYENDSESSION:
     case WM_CLOSE:                      /* Attempt to close all children */
               
			SendMessage (hwnd, WM_COMMAND, IDM_WINDOW_CLOSEALL, 0);
			   
			if (NULL != GetWindow (hwndClient, GW_CHILD))
			   return 0;
			   
			break;   /* i.e., call DefFrameProc */
               
     case WM_DESTROY:
			PostQuitMessage (0);
			return 0;
     }
          /* Pass unprocessed messages to DefFrameProc (not DefWindowProc) */
     
     return DefFrameProc (hwnd, hwndClient, message, wParam, lParam);
}

BOOL CALLBACK CloseEnumProc (HWND hwnd, LPARAM lParam)
{
     if (GetWindow (hwnd, GW_OWNER))         /* Check for icon title */
          return TRUE;
     
     SendMessage (GetParent (hwnd), WM_MDIRESTORE, (WPARAM) hwnd, 0);
     
     if (!SendMessage (hwnd, WM_QUERYENDSESSION, 0, 0))
          return TRUE;
     
     SendMessage (GetParent (hwnd), WM_MDIDESTROY, (WPARAM) hwnd, 0);
     return TRUE;
}

LRESULT CALLBACK ChildWndProc (HWND hwnd, UINT message, 
                               WPARAM wParam, LPARAM lParam)
{
	static HWND     	hwndClient, hwndFrame;
	HDC             	hdc;
	HMENU           	hMenu;
	PDOCDATA      	 	pDocData;
	PAINTSTRUCT     	ps;
	RECT            	rect;
	LPCREATESTRUCT		lpcs;
	LPMDICREATESTRUCT	lpmcs;
	switch (message)
	{
	case WM_CREATE:
		lpcs = (LPCREATESTRUCT) lParam; /* structure with creation data */
		lpmcs = (LPMDICREATESTRUCT) lpcs->lpCreateParams;

		/* Allocate memory for window private data */
		pDocData = (PDOCDATA) HeapAlloc (GetProcessHeap (),
		                  HEAP_ZERO_MEMORY, sizeof (DOCDATA));
		
		GetWindowText (hwnd, pDocData->szFileTitle, MAX_PATH);
		lstrcpy( pDocData->szFileName, (LPCTSTR)lpmcs->lParam );
		SetWindowLong (hwnd, 0, (long) pDocData);
		
		/* Save some window handles */
		hwndClient = GetParent (hwnd);
		hwndFrame  = GetParent (hwndClient);
		return 0;
  	
	case WM_COMMAND:
		switch (LOWORD (wParam))
		{
			default:
				break;
		}
		return 0;
	  
	case WM_PAINT:
		/* Paint the window */
		   
		hdc = BeginPaint (hwnd, &ps);
		   
		pDocData = (PDOCDATA) GetWindowLong (hwnd, 0);
		SetTextColor (hdc, RGB(0,0,0));              
		GetClientRect (hwnd, &rect);
		   
		DrawText (hdc, pDocData->szFileTitle, -1, &rect,
		        DT_SINGLELINE | DT_CENTER | DT_VCENTER);
		   
		EndPaint (hwnd, &ps);
		return 0;
	       
	case WM_MDIACTIVATE:
		/* Set the Hello menu if gaining focus */
		if (lParam == (LPARAM) hwnd)
		   	SendMessage (hwndClient, WM_MDISETMENU,
		                (WPARAM) hMenuChild, (LPARAM) hMenuChildWindow);
		
		/* Set the Init menu if losing focus */
		if (lParam != (LPARAM) hwnd)
		   	SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuInit,
		                (LPARAM) hMenuInitWindow);
		   
		DrawMenuBar (hwndFrame);
		return 0;
	       
	case WM_QUERYENDSESSION:
	case WM_CLOSE:
		pDocData = (PDOCDATA) GetWindowLong (hwnd, 0);
		if (IDOK != MessageBox (hwnd, TEXT ("OK to close window?"),
		                      pDocData->szFileTitle, 
		                      MB_ICONQUESTION | MB_OKCANCEL))
			return 0;
		   
		break;   /* i.e., call DefMDIChildProc */
		   
	case WM_DESTROY:
		pDocData = (PDOCDATA) GetWindowLong (hwnd, 0);
		HeapFree (GetProcessHeap (), 0, pDocData);
		return 0;
	}
	
	/* Pass unprocessed message to DefMDIChildProc */
	return DefMDIChildProc (hwnd, message, wParam, lParam);
}