// **********************************************
// File: MAIN.CPP
// THE main module

#include "muzika.h"

HANDLE hInst;
HWND hMainWnd;

long FAR PASCAL MainWindowProc(HWND, unsigned, WORD, LONG);

// **********************************************
// WinMain is the program entry point.

int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR, int cmdShow)
{
  MSG msg;

  // Perform first initialization
  InitMain(hInstance, hPrevInstance, cmdShow);

  // Enter a message-polling loop
  while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  // When quit message received, close the application
  CloseMain(hInstance);
  return (msg.wParam);
}

// **********************************************
// InitMain performs an initialization of a MUZIKA application instance.

void InitMain(HANDLE hInstance, HANDLE hPrevInstance, int cmdShow)
{
  // Check whether first instance of the application
  if (!hPrevInstance)
    InitMainFirst(hInstance);
  else
    InitMainAdded(hInstance, hPrevInstance);

  // Do every-instance initialization
  InitMainEvery(hInstance, cmdShow);
}

// **********************************************
// InitMainFirst performs a first-instance initialization.
// It registers the main and edit window classes.

void InitMainFirst(HANDLE hInstance)
{
  WNDCLASS wc;

  // Register the main window class
  wc.lpszClassName = "MUZIKA";
  wc.hInstance = hInstance;
  wc.lpfnWndProc = MainWindowProc;
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hIcon = LoadIcon(hInstance, "I_MUZIKA");
  wc.lpszMenuName = "M_MUZIKA";
  wc.hbrBackground = COLOR_WINDOW+1;
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  RegisterClass(&wc);

  RegisterEditClass(hInstance);
}

// **********************************************
// InitMainAdded performs an initialization of any instance of MUZIKA
// other than the first. No class registration is necessary.

void InitMainAdded(HANDLE, HANDLE)
{
}

// **********************************************
// InitMainEvery does an every-instance initialization. It displays
// the main and edit windows, and initializes the main menu.

void InitMainEvery(HANDLE hInstance, int cmdShow)
{
  hInst = hInstance;

  // Create and display the main window
  hMainWnd = CreateWindow("MUZIKA",
    "MUZIKA (Untitled)",
    WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
    0, 0,
    CW_USEDEFAULT, 0,
    NULL,
    NULL,
    hInstance,
    NULL);
  ShowWindow(hMainWnd, cmdShow);
  UpdateWindow(hMainWnd);

  hMainMenu = GetMenu(hMainWnd);
  InitializeMenu(FALSE);

  CreateEditWindow(hInstance);
}

// **********************************************
// CloseMain destroys the melody database when the application is closed.

void CloseMain(HANDLE)
{
  for (int index = 0; index < melody.part.number(); ++index)
    melody.part.destroyAt(index);
}

// **********************************************
// MainWindowProc is the main window function, which responds to messages
// intended for the main window. The messages processed are described within.

long FAR PASCAL MainWindowProc(
  HWND hWnd, unsigned message, WORD wParam, LONG lParam)
{
  // Check message type
  switch(message) {
    case WM_PAINT:
      // Process a WM_PAINT message, indicating that the window
      // should be repainted.
      PaintMainWindow(hWnd);
      break;

    case WM_CLOSE:
      // Process a WM_CLOSE message, indicating that the user has
      // requested to close the window. If there is an unsaved melody,
      // it should be verified that the user indeed means to exit.
      AskSave();
      DestroyWindow(hWnd);
      break;

    case WM_DESTROY:
      // Process a WM_DESTROY message, indicating that the main window
      // has been closed. A quit message is to be sent to the application
      // in order to stop the main loop in WinMain.
      PostQuitMessage(0);
      break;

    case WM_LBUTTONDOWN:
      // Process a WM_LBUTTONDOWN message, indicating that the user has clicked
      // the left mouse button. The symbol on which the cursor is clicked
      // should be made current.
      if (IdentifyEditModeSymbol(lParam) || IdentifySymbol(lParam));
      break;

    case WM_SIZE:
      // Process a WM_SIZE message, indicating that the main window size
      // has changed. The edit window size should be adjusted appropriately.
      MoveWindow(hEditWnd, 73, 37, LOWORD(lParam)-72, HIWORD(lParam)-36, TRUE);
      break;

    case WM_COMMAND:
      // Process a WM_COMMAND message, indicating that the user has made
      // a menu selection. The selection is processed further in ProcessMenu.
      if (!ProcessMenu(wParam))
        return DefWindowProc(hWnd, message, wParam, lParam);
      break;

    default:
      // Unrecognized message: just let Windows take care of it.
      return DefWindowProc(hWnd, message, wParam, lParam);
  }

  return 0L;
}

// **********************************************
// PaintMainWindow is the main window painting function,
// activated whenever the main window receives a WM_PAINT message.
// It redraws the main window, including lines and symbols.

void PaintMainWindow(HWND hWnd)
{
  PAINTSTRUCT ps;
  HDC hDC;
  int LineIndex;
  RECT rect;

  // Obtain a display context
  hDC = BeginPaint(hWnd, &ps);

  // Set the mapping mode parameters
  SetMapMode(hDC, MM_TEXT);
  GetClientRect(hWnd, &rect);

  // Draw the layout of the lines
  MoveTo(hDC, 0, 36);
  LineTo(hDC, rect.right, 36);
  MoveTo(hDC, 0, 0);
  LineTo(hDC, 0, rect.bottom);
  MoveTo(hDC, 36, 0);
  LineTo(hDC, 36, rect.bottom);
  MoveTo(hDC, 72, 0);
  LineTo(hDC, 72, rect.bottom);
  MoveTo(hDC, 108, 0);
  LineTo(hDC, 108, 36);
  for (LineIndex = 60; LineIndex < rect.bottom; LineIndex += 24) {
    MoveTo(hDC, 0, LineIndex);
    LineTo(hDC, 72, LineIndex);
  }

  // Draw the symbols
  DisplayEditModeSymbols(hDC);
  RefreshSymbols(hDC);

  // Finish the window updating
  EndPaint(hWnd, &ps);
}
