#include "ledit.h"
#include "ledit_2.h"

#define NOTHING_OPEN   "  No open files"
#define INSERT_MODE    "Insert"
#define OVERWRITE_MODE "Overwrite"
#define MODIFIED       "Modified"
#define UNMODIFIED     ""
#define LINE_INFO      "  Line: %ld   Position: %d"
#define MAGIC          1233218

#ifdef WIN32
#define NOTIFY_CODE HIWORD(wParam)
#define COMMAND_CODE LOWORD(wParam)
#define SENDER_HWND (HWND)lParam
#else
#define NOTIFY_CODE HIWORD(lParam)
#define COMMAND_CODE wParam
#define SENDER_HWND (HWND)LOWORD(lParam)
#endif

typedef struct tagPOS
  {
    long Line;
    int  Pos;
  }
  POS;

static MSG Msg;
static LONG Header = (LONG)
"LEdit-Ask-User-TXT/Header files/*.h/C++ source/*.cpp/Pascal source/*.pas/\
Text files/*.txt/All files/*.*";
static HWND LGroup;                   // LEditGroup eindow
static HWND WndClient;                // Client window
static HWND WndModify;                // "Modify" part of status bar
static HWND WndInsert;                // "Insert" part of status bar
static HWND WndStatus;                // The rest of status bar
static WORD StatusBarHeight;
static WORD InsertWidth;
static WORD NumWin  = 0;
static WORD InsertMode = EMP_SET;
static HINSTANCE  hInst;
static char Buffer[64];

void Behaviour(HWND Wnd)
{
#include "ledit__s.inc"
}

// Main frame function
LRESULT CALLBACK _export FrameProc (HWND     Wnd,
					 UINT     Msg,
					 WPARAM   wParam,
					 LPARAM   lParam)
{
  switch (Msg)
	 {
		case WM_CREATE:
		  {
          LGroup  = CreateWindow(LEDITGROUP_CLASS,
                                 NULL,
                                 WS_CHILD,
                                 0,0,0,0,
                                 Wnd, 0, hInst, NULL);

			 // Create MDI Client
	  CLIENTCREATESTRUCT csClient;
	  csClient.hWindowMenu  = GetSubMenu(GetMenu(Wnd),4);
	  csClient.idFirstChild = START_WIN + 1;
	  WndClient = CreateWindow("MDICLIENT",
					NULL,
					WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE |
					WS_HSCROLL | WS_VSCROLL,
					0,0,0,0,
					Wnd,(HMENU)4, hInst, &csClient);

			 // Create status bar windows
	  WndModify = CreateWindow("STATIC",
					NULL,
					WS_CHILD | WS_VISIBLE | WS_BORDER
					| SS_CENTER,
					0,0,0,0,
					Wnd,(HMENU)-1, hInst, NULL);
	  WndInsert = CreateWindow("STATIC",
					INSERT_MODE,
					WS_CHILD | WS_VISIBLE | WS_BORDER
					| SS_CENTER,
					0,0,0,0,
					Wnd,(HMENU)-1, hInst, NULL);
	  WndStatus = CreateWindow("STATIC",
					NOTHING_OPEN,
					WS_CHILD | WS_VISIBLE | WS_BORDER,
					0,0,0,0,
					Wnd,(HMENU)-1, hInst, NULL);
			 break;
		  }
		case WM_SIZE:
	{
			 // Move MDI client
			 MoveWindow(WndClient,0,0,
			  LOWORD(lParam),HIWORD(lParam)-StatusBarHeight,TRUE);

			 // Move status bar windows
			 MoveWindow(WndModify,0,HIWORD(lParam)-StatusBarHeight,
			  InsertWidth,StatusBarHeight,TRUE);
			 MoveWindow(WndInsert,InsertWidth,HIWORD(lParam)-StatusBarHeight,
			  InsertWidth,StatusBarHeight,TRUE);
			 MoveWindow(WndStatus,InsertWidth*2,HIWORD(lParam)-StatusBarHeight,
			  LOWORD(lParam)-2*InsertWidth,StatusBarHeight,TRUE);

			 // Don't call DefFrameProc()
			 return 0;
		  }
		case WM_COMMAND:
		  {
	  switch ( COMMAND_CODE )
		 {
			case EC_FILENEW:
			case EC_FILEOPEN:
		{
						// Create LEdit child
		  MDICREATESTRUCT csWindow;
		  csWindow.szClass  = LEDIT_CLASS;
		  csWindow.szTitle  =
			 ( wParam == EC_FILEOPEN ) ? (LPSTR) Header : NULL;
		  csWindow.hOwner   = hInst;
		  csWindow.x        = CW_USEDEFAULT;
		  csWindow.y        = CW_USEDEFAULT;
		  csWindow.cx       = CW_USEDEFAULT;
		  csWindow.cy       = CW_USEDEFAULT;
		  csWindow.style    = WS_HSCROLL | WS_VSCROLL |
									 ES_MDICHILD | ES_CANCHANGEFONT |
						ES_USESHORTNAME | ES_FILELOWER;
		  csWindow.lParam   = NULL;
				 HWND Child = (HWND) SendMessage(WndClient,WM_MDICREATE,0,
			 (LONG) &csWindow);

		  if ( Child )
			 {
							 // Change a little LEdit behaviour
				SendMessage(Child,EM_SETFILEFILTER,0,Header+15);
				SendMessage(Child,EM_SETFONT,
				  (WPARAM) GetStockObject(DEVICE_DEFAULT_FONT),0L);
				SendMessage(Child,EM_SETSYNTAX,0,1);
                                Behaviour(Child);

                                // Attach LEdit to the group
                                SendMessage(Child,EM_ATTACH,(WPARAM)LGroup,0);
                                /* Or SendMessage(LGroup,EM_ATTACH,Child,0); */

				SetFocus(Child);
			 }
		  return 0;
			  }
			case EC_WINDOWTILE:
		{
						// Tile children
		  SendMessage(WndClient,WM_MDITILE,0,0L);
						return 0;
			  }
			case EC_WINDOWCASCADE:
		{
						// Cascade children
		  SendMessage(WndClient,WM_MDICASCADE,0,0L);
                  return 0;
	        }
	      case EC_WINDOWICONS:
		{
                  // Arrange icons
		  SendMessage(WndClient,WM_MDIICONARRANGE,0,0L);
                  return 0;
	        }
	      case EC_WINDOWCLOSEALL:
		{
                  // If it's impossible to close then do nothing
		  if ( !SendMessage(LGroup,EM_CLOSE,0,0) )
		    return 0;

                  // Take first child
		  HWND Child = (HWND)SendMessage(WndClient,WM_MDIGETACTIVE,0,0L);
		  while ( Child )
		    {
                      // Destroy the child
		      SendMessage(WndClient,WM_MDIDESTROY,(WPARAM)Child,0L);

                      // Take next child
		      Child = (HWND)SendMessage(WndClient,WM_MDIGETACTIVE,0,0L);
		    }
                  return 0;
                }
	      case EC_HELPABOUT:
		{
                  // Show copyright message
		  MessageBox(Wnd,
		    "LEdit MDI demonstration\r\n(c) 1995 Andrey B. Yastrebov",
                    "About LEDIT_E2",MB_OK | MB_ICONINFORMATION);
                  return 0;
                }
	      case EC_FILEEXIT:
		{
                  // Close the window if it's possible
		  SendMessage(Wnd,WM_CLOSE,0,0L);
                  return 0;
                }
	    }
	  if ( (COMMAND_CODE > START_WIN) && (COMMAND_CODE < END_WIN) )
	    {
              // Handle LEdit notifications
	      switch ( NOTIFY_CODE )
	        {
		  case EN_SETFOCUS:
                    // Set insertion mode according to current state
		    SendMessage(SENDER_HWND,EM_SETINSERTMODE,
		      InsertMode,0L);
                    // Pass next to change status bar
		  case EN_CHANGE:
		    {
                      // Show modify status
		      WORD MStatus =
		        SendMessage(SENDER_HWND,EM_GETMODIFY,0,0L);
		      SetWindowText(WndModify,
			(MStatus) ? MODIFIED : UNMODIFIED);

                      // Show current position
		      POS CurPos;
		      LEDITPOSITION LPos;
		      SendMessage(SENDER_HWND,EM_GETSEL,0,(LONG) &LPos);
		      CurPos.Line = LPos.EndLine;
		      CurPos.Pos  = LPos.EndPosition;
		      wvsprintf((LPSTR) &Buffer,LINE_INFO,&CurPos);
		      SetWindowText(WndStatus, (LPSTR) &Buffer);
		      break;
                    }
		  case EN_INSERTMODE:
		    {
		      // Change insertion mode and show it
                      InsertMode = EMP_SET;
		      SetWindowText(WndInsert,INSERT_MODE);
                      break;
                    }
		  case EN_OVERWRITEMODE:
		    {
		      // Change insertion mode and show it
		      InsertMode = EMP_CLEAR;
		      SetWindowText(WndInsert,OVERWRITE_MODE);
                      break;
		    }
		  case EN_CREATED:
		    {
                      // Increase number of LEdit windows
		      NumWin++;
                      break;
                    }
	          case EN_DESTROY:
		    {
                      // Decrease number of LEdit windows
		      NumWin--;

                      // Correct status bar view if there are no windows
		      if ( !NumWin )
		        SetWindowText(WndModify,NULL);
		        SetWindowText(WndStatus,NOTHING_OPEN);
                      break;
		    }
		}

	      // Return zero for all unhanled LEdit notifications
              // because DefFrameProc () does it wrong
			if ( NOTIFY_CODE != 0 )
			  return 0;
	    }
	  else
              // pass the Comand to active hild
	      SendMessage(LGroup,WM_COMMAND,wParam,lParam);
          break;
        }
      case WM_INITMENU:
        {
           // DisableMenu will be called automatically
	   SendMessage(LGroup,EM_ENABLEMENU,wParam,0L);
           break;
        }
      case WM_CLOSE:
      case WM_QUERYENDSESSION:
	{
	  // If LEdit windows report that they can be closed
          // then let DefFrameProc() decides
          if ( SendMessage(LGroup,EM_CLOSE,0,0) )
	    break;

          // Otherwise don't allow to close
          return 0;
        }
      case WM_DESTROY:
	{
          // Stop the application
	  PostQuitMessage(0);
	  break;
        }
    }
  // Call DefFrameProc() for the rest of messages
  return DefFrameProc(Wnd,WndClient,Msg,wParam,lParam);
}

// Main Windows function
#pragma argsused
int PASCAL WinMain (HINSTANCE hInstance,
		    HINSTANCE hPrevInst,
		    LPSTR     lpszCmdLine,
		    int       nCmdShow)

{
  // To ensure static loading of LEDIT.DLL
  LVer();

  // Don't allow multiple instances
  if ( hPrevInst != 0 )
    return 0;

  // Determine constants
  hInst = hInstance;
  StatusBarHeight = GetSystemMetrics(SM_CYMENU);
  InsertWidth = GetSystemMetrics(SM_CXVSCROLL)*8;

  // Register frame window class
  WNDCLASS wc;
  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = (WNDPROC) FrameProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon         = LoadIcon(0,IDI_APPLICATION);
  wc.hCursor       = LoadCursor(0,IDC_ARROW);
  wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1);
  wc.lpszMenuName  = "STD_MDI_MENU";
  wc.lpszClassName = "LEditFrame";
  RegisterClass(&wc);

  // Create main window
  HWND Wnd = CreateWindow("LEditFrame",
			  "MDI Editor",
			  WS_OVERLAPPEDWINDOW,
			  CW_USEDEFAULT, CW_USEDEFAULT,
			  CW_USEDEFAULT, CW_USEDEFAULT,
			  0, 0, hInstance, NULL);
  if ( Wnd )
    {
      // Show window
      ShowWindow(Wnd,SW_SHOW);

      // Run message loop
      while ( GetMessage(&Msg,0,0,0) )
        {
	  if ( !TranslateMDISysAccel(WndClient,&Msg) )
            {
              TranslateMessage(&Msg);
	      DispatchMessage(&Msg);
            }
        }
    }
return 0;
}