#include "ledit.h"

#define ID_CPP          101
#define ID_PAS          102
#define CPP_SYNTAX       27
#define PAS_SYNTAX       28
#define CPP_WORDS        11
#define PAS_WORDS        21
#define PAS_LEFT_BRACE   "begin"
#define PAS_RIGHT_BRACE  "end"
  // Actually "end" has multiple braces such as "case" or
  // "record", but multiple braces aren't supported now
  // Pascal source is written without such words and therefore
  // Find Brace will work properly on it  

static MSG Msg;
static char MsgBuf[2048];
static HWND WndPAS;                   // Pascal source window
static HWND WndCPP;                   // C++ source window
static HINSTANCE hInst;
static HWND Focus;
static WORD CPPSyntax[CPP_SYNTAX] = { // Small subset of C++ syntax
   '\"\\', // Quoting character
   '\'\\', // Alternative quoting character
   '//',   // Comment sign
   '/*',   // Left comment sign
   '*/',   // Right comment sign
   '(',')','[',']','{', '}','+','-','*','/','\\',',',';','=',':',
   '%','|','!','&','||','&&','=='
  };
static WORD PASSyntax[PAS_SYNTAX] = { // Small subset of Pascal syntax
   '\'\'', // Quoting character
   0x101,  // Alternative quoting character
   0x101,  // Comment sign
   '{',    // Left comment sign
   '}',    // Right comment sign
   '(',')','[',']','(*', '*)','+','-','*','/','\\',',',';','=',':',
   ':=','<>','>=','<=','@','#','. ','..'
  };
static LPSTR CPPWords[CPP_WORDS] = {  // Small subset of C++ keywords
  "switch","case","default","break","return","if","else","while","for",
  "#define","#include"};

static LPSTR PASWords[PAS_WORDS] = {  // Small subset of Pascal keywords
  "begin","end","case","break","exit","if","then","while","for","do",
  "uses","type","const","var","function",
  "or","and","div","mod","shl","shr"};


// Main window function
LRESULT CALLBACK _export FrameProc (HWND     Wnd,
				    UINT     Msg,
				    WORD     wParam,
				    DWORD    lParam)
{
  switch (Msg)
    {
      case WM_CREATE:
        {
          // Create two LEdit children
	  WndCPP = CreateWindow("LEdit",
				"LEdit-File-Init-ledit_e4.cpp",
				WS_CHILD | WS_VISIBLE | ES_BIGINDENT
				| ES_SMALLSPACING | ES_HIGHLIGHT
				| WS_VSCROLL | WS_BORDER,
				0,0,0,0,
				Wnd,ID_CPP, hInst, NULL);
	  WndPAS = CreateWindow("LEdit",
				"LEdit-File-Init-ledit_e4.pas",
				WS_CHILD | WS_VISIBLE | ES_BIGINDENT
				| ES_SMALLSPACING | ES_HIGHLIGHT
				| WS_VSCROLL | WS_BORDER,
				0,0,0,0,
				Wnd,ID_PAS, hInst, NULL);

	  // Choose first focused window
	  Focus = WndCPP;

	  // Change a little LEdit behaviour
	  SendMessage(WndCPP,EM_SETFONT,
	    GetStockObject(DEVICE_DEFAULT_FONT),0L);
	  SendMessage(WndPAS,EM_SETFONT,
	    GetStockObject(DEVICE_DEFAULT_FONT),0L);

	  // Set appropriate syntaxes
	  SendMessage(WndCPP,EM_SETSYNTAX,CPP_SYNTAX,(LONG) &CPPSyntax);
	  SendMessage(WndPAS,EM_SETSYNTAX,PAS_SYNTAX,(LONG) &PASSyntax);
	  break;
        }
      case WM_SIZE:
	{
	  // Move LEdit windows
	  WORD Part1 = HIWORD(lParam) / 2;
          WORD Part2 = Part1 + HIWORD(lParam) % 2;
          MoveWindow(WndCPP,0,0,
		     LOWORD(lParam),Part1,FALSE);
          MoveWindow(WndPAS,0,Part1,
		     LOWORD(lParam),Part2,FALSE);
          return 0;
	}
      case WM_CTLCOLOR:
	{
          // Set default colors. Actually these are comment colors
	  SetBkColor(wParam,RGB(192,192,192));
	  SetTextColor(wParam,RGB(128,128,128));
          return 0;
        }
      case EM_CTLCOLOREX:
	{
	  switch ( (*(LPWORDDESC)lParam).wCode )
	    {
	      case WD_SIMPLEWORD:
		{
                  // Set default text color for words
		  SetTextColor(wParam,RGB(0,0,0));

                  // Mark C++ keywords if this is CPP window
		  if ( (*(LPWORDDESC)lParam).hwndSender == WndCPP )
		    {
                      int i;
		      for (i = 0; i < CPP_WORDS; i++)
			{
			  if ( lstrcmp((*(LPWORDDESC)lParam).caWord,
			    CPPWords[i]) == 0)
			    {
			       SetTextColor(wParam,RGB(0,0,255));
                               return 0;
                            }
			}
		    }

                  // Mark Pascal keyword if this is PAS window
		  else
		    {
		      int i;
		      for (i = 0; i < PAS_WORDS; i++)
			{
			  if ( lstrcmpi((*(LPWORDDESC)lParam).caWord,
			    PASWords[i]) == 0)
			    {
			       SetTextColor(wParam,RGB(0,0,255));
                               return 0;
                            }
			}
		    } 
		  return 0;
                }
	      case WD_SYNTAXITEM:
		{
                  // Set text color for syntax words
		  SetTextColor(wParam,RGB(0,0,192));
                  return 0;
		}
	      case WD_BADLYQUOTEDTEXT:
	      case WD_QUOTEDTEXT:
		{
                  // Set text color for quoted text
                  if ( HIWORD((*(LPWORDDESC)lParam).dwValue) )
		    SetTextColor(wParam,RGB(0,128,0));
		  else
                    SetTextColor(wParam,RGB(255,0,0));
                  return 0;
		}
	      default:
		// Set text color for the rest of words, that is
                // for numbers
                SetTextColor(wParam,RGB(0,128,0));
            }
          return 0;
	}
      case EM_WORDCLICK:
        {
	  if ( lParam )
	    {
              // Show message about word supplied if it exists
	      lstrcpy(MsgBuf,(*(LPWORDDESC)lParam).caWord);
	      lstrcat(MsgBuf,"\r\n");
	      if ( (*(LPWORDDESC)lParam).wCode == WD_SYNTAXITEM )
		{
                  WORD SyntaxIndex = HIWORD((*(LPWORDDESC)lParam).dwValue);
		  wvsprintf(MsgBuf+lstrlen(MsgBuf),"Syntax: %d",
		    &SyntaxIndex);
		}
	      else if ( (*(LPWORDDESC)lParam).wCode & WDF_INTEGER )
		{
		  wvsprintf(MsgBuf+lstrlen(MsgBuf),"Integer: %ld",
		    &(*(LPWORDDESC)lParam).dwValue);
		}
	      MessageBox(Wnd,MsgBuf,"Click",MB_OK | MB_ICONINFORMATION);
            }
	  else
            // Show "White space" message
            MessageBox(Wnd,"White space","Click",MB_OK | MB_ICONINFORMATION);
          return 1;
	}
      case EM_FINDBRACE:
	{
	  if ( (*(LPWORDDESC)lParam).wCode == WD_SYNTAXITEM )
	    {
              // Indicate braces for parantheises, brackets etc.
	      WORD SyntaxIndex = HIWORD((*(LPWORDDESC)lParam).dwValue);
              if ( SyntaxIndex > 10 )
		return EMF_NOBRACE;
              LRESULT LResult;
	      if ( SyntaxIndex % 2)
                {
		  SyntaxIndex++;
		  LResult = EMF_HASRIGHT;
                }
	      else
                {
		  SyntaxIndex--;
		  LResult = EMF_HASLEFT;
                }
	      (*(LPWORDDESC)lParam).dwValue = MAKELONG(0,SyntaxIndex);
              return LResult;
	    }
	  else
	    {
              // If this is CPP window then no more braces
              if ( wParam == WndCPP )
		return EMF_NOBRACE;

              // If this is PAS window then look for "begin"
	      if ( lstrcmpi( (*(LPWORDDESC)lParam).caWord,
	        PAS_LEFT_BRACE) == 0)
                {
		  lstrcpy( (*(LPWORDDESC)lParam).caWord, PAS_RIGHT_BRACE );
                  return EMF_HASRIGHT | EMF_CASEINSENSITIVE;
		}

              // Look also for "end"
	      if ( lstrcmpi( (*(LPWORDDESC)lParam).caWord,
	        PAS_RIGHT_BRACE) == 0)
                {
		  lstrcpy( (*(LPWORDDESC)lParam).caWord, PAS_LEFT_BRACE );
                  return EMF_HASLEFT | EMF_CASEINSENSITIVE;
		}
	    } 
        }
      case WM_COMMAND:
	{
          // Only LEdit notifications
	  switch ( HIWORD(lParam) )
	    {
              // Store current focus
	      case EN_SETFOCUS:
	        Focus = LOWORD(lParam); 
	    }
          return 0;
	}
      case WM_SETFOCUS:
	{
          // Set current focus
          SetFocus(Focus);
          return 0;
        }
      case WM_DESTROY:
	{
          // Stop the application
	  PostQuitMessage(0);
	  break;
        }
    }
  // Call DefWindowProc() for the rest of messages
  return DefWindowProc(Wnd,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;

  // Set constant
  hInst = hInstance;

  // Register 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  = 0;
  wc.lpszClassName = "LEditFrame";
  RegisterClass(&wc);

  // Create main window
  HWND Wnd = CreateWindow("LEditFrame",
			  "C++ vs Pascal",
			  WS_OVERLAPPEDWINDOW,
			  0, 0,
			  GetSystemMetrics(SM_CXSCREEN),
			  GetSystemMetrics(SM_CYSCREEN),
			  0, 0, hInstance, NULL);
  if ( Wnd )
    {
      // Show window
      ShowWindow(Wnd,SW_SHOW);

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