// **********************************************
// File: FILE.CPP
// File menu dialog box functions

#include "muzika.h"
#include "dialog.h"
#include <dir.h>
#include <fstream.h>
#include <stdlib.h>
#include <string.h>

char programTitle[MAXPATH+7] = "MUZIKA "; // Main window caption
char *filepath = programTitle+7;  // Pointer to file path in caption
BOOL melodyModified = FALSE;      // Becomes TRUE whenever melody modified

// **********************************************
// AskSave requests the user to confirm qutting
// the current melody after modification. Return TRUE
// if whatever the user requests succeeds (allowing therefore
// to proceed with the previous operation), or FALSE if either
// the user chooses CANCEL or the save fails.

BOOL AskSave()
{
  int reply;

  // If melody has been modified, display an asking message box
  // and save the melody if the user selects YES
  return melodyModified ?
    ((reply = MessageBox(hMainWnd, "Current melody has been modified. "
      "Do you wish to save it?", "Warning",
      MB_ICONINFORMATION | MB_YESNOCANCEL)) == IDYES) ?
      Save() : (reply == IDNO) : TRUE;
}

// **********************************************
// DialogNew is the "File/New..." dialog box function,
// processing messages intended for this dialog box.

BOOL FAR PASCAL DialogNew(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
{
  static const unsigned widths[]={640-144, 800-144, 1024-144, 0};

  switch (message) {
    case WM_INITDIALOG:
      // Process a WM_INITDIALOG message, indicating that
      // the DialogNew function is called for the first time.
      // A list box with the widths list is created.
      for (int index = 0; widths[index]; ++index) {
        char wstr[5];
        itoa(widths[index], wstr, 10);
        SendMessage(GetDlgItem(hDlg, ID_STAFFWIDTH),
          LB_INSERTSTRING, -1, (LONG) wstr);
      }
      SendMessage(GetDlgItem(hDlg, ID_STAFFWIDTH), LB_SETCURSEL, 0, 0);
      return TRUE;

    case WM_COMMAND:
      // Process a WM_COMMAND message, indicating that the user
      // has finished making a selection either by pressing OK, CANCEL,
      // or double-clicking the requested width.
      if (wParam == IDOK || HIWORD(lParam) == LBN_DBLCLK) {
        // Set the melody staff width according to what the user selected
        melody.SetStaffWidth(widths[(int)
          SendMessage(GetDlgItem(hDlg, ID_STAFFWIDTH), LB_GETCURSEL, 0, 0)]);
        EndDialog(hDlg, TRUE);

        // Initialize the database:
        // create a melody with only one UNNAMED part in it,
        // and reset the various Boolean flags.
        while (melody.part.number())
          melody.part.destroyAt(melody.part.number()-1);
        melodyExists = TRUE;
        melody.part.insertAt(*new Part("UNNAMED", 1), 0);
        scoreDisplay = FALSE;
        displayedPart = 0;
        filepath[0] = 0;
        melodyModified = FALSE;

        // Refresh the screen
        SetWindowText(hMainWnd, "MUZIKA (Untitled)");
        InitializeMenu(TRUE);
        SetScrollRange(hEditWnd, SB_VERT, 0, 0, TRUE);
        ShowScrollBar(hEditWnd, SB_VERT, TRUE);
        InvalidateRect(hMainWnd, NULL, TRUE);
        InvalidateRect(hEditWnd, NULL, TRUE);
        IdentifyEditModeSymbol(0x00020002L);
        return TRUE;
      }

      if (wParam == IDCANCEL) {
        // The user cancelled the operation:
        // just exit the dialog box without doing anything
        EndDialog(hDlg, FALSE);
        return TRUE;
      }
  }

  return FALSE;
}

// **********************************************
// LoadError is a generic load error recovery function,
// called whenever there is an error loading a file (probably
// because the file does not conform to MUZIKA format).

void LoadError()
{
  // Display an error message box
  SetCursor(LoadCursor(NULL, IDC_ARROW));
  MessageBox(hEditWnd, "The file is not a valid MUZIKA file.", NULL,
    MB_SYSTEMMODAL | MB_OK);

  // Delete the currently stored melody
  while (melody.part.number())
    melody.part.destroyAt(melody.part.number()-1);
  melodyExists = FALSE;
  filepath[0] = 0;
  SetWindowText(hMainWnd, "MUZIKA (Untitled)");
  InitializeMenu(FALSE);
  hEditCursor = LoadCursor(NULL, IDC_ARROW);
  ShowScrollBar(hEditWnd, SB_VERT, FALSE);
  InvalidateRect(hMainWnd, NULL, TRUE);
  InvalidateRect(hEditWnd, NULL, TRUE);
}

// **********************************************
// DialogOpen is the "File/Open..." dialog box function,
// processing messages intended for this dialog box.

BOOL FAR PASCAL DialogOpen(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
{
  char path[MAXPATH];
  char drive[MAXDRIVE], dir[MAXDIR], file[MAXFILE], ext[MAXEXT];

  switch (message) {
    case WM_INITDIALOG:
      // Process a WM_INITDIALOG message, indicating that
      // the DialogOpen function is called for the first time.
      // The file and directory lists are filled.
      DlgDirList(hDlg, "*.MUZ", ID_FILELIST, NULL, 0x0000);
      DlgDirList(hDlg, "*.*", ID_DIRLIST, ID_DIRNAME, 0xC010);
      SetDlgItemText(hDlg, ID_FILENAME, "*.MUZ");
      SendDlgItemMessage(hDlg, ID_FILENAME, EM_SETSEL, NULL, 0x7FFF0000L);
      return TRUE;

    case WM_COMMAND:
      // Process a WM_COMMAND message, indicating an action
      // of some kind in the dialog box.
      switch (wParam) {
        case ID_FILELIST:
          switch (HIWORD(lParam)) {
            case LBN_SELCHANGE:
              // The user has made a selection in the file list:
              // respond by copying the selection to the text field
              DlgDirSelect(hDlg, path, ID_FILELIST);
              SetDlgItemText(hDlg, ID_FILENAME, path);
              SendDlgItemMessage(hDlg, ID_FILENAME, EM_SETSEL, NULL, 0x7FFF0000L);
              SendDlgItemMessage(hDlg, ID_DIRLIST, LB_SETCURSEL, -1, NULL);
              break;

            case LBN_DBLCLK:
              // The user has double-clicked a selection in the file list:
              // go on and open the file
              goto openfile;
          }
          return TRUE;

        case ID_DIRLIST:
          switch(HIWORD(lParam)) {
            case LBN_SELCHANGE:
              // The user has made a selection in the file list:
              // respond by copying the selection to the text field
              DlgDirSelect(hDlg, path, ID_DIRLIST);
              strcat(path, "*.MUZ");
              SetDlgItemText(hDlg, ID_FILENAME, path);
              SendDlgItemMessage(hDlg, ID_FILENAME, EM_SETSEL, NULL, 0x7FFF0000L);
              SendDlgItemMessage(hDlg, ID_FILELIST, LB_SETCURSEL, -1, NULL);
              break;

            case LBN_DBLCLK:
              // The user has double-clicked a selection
              // in the directory list:
              // go on and change the directory
              goto openfile;
          }
          return TRUE;

        case IDOK:
openfile:
          // This point is reached whenever the user chooses OK
          // or double-clicks a file or directory selection.
          GetDlgItemText(hDlg, ID_FILENAME, path, MAXPATH);
          if (strchr(path, '*')) {
            // The path still contains an '*', meaning that
            // it's not a file name yet:
            // update the file and directory lists
            DlgDirList(hDlg, path, ID_FILELIST, NULL, 0x0000);
            DlgDirList(hDlg, "*.*", ID_DIRLIST, ID_DIRNAME, 0xC010);
            SetDlgItemText(hDlg, ID_FILENAME, "*.MUZ");
            SendDlgItemMessage(hDlg, ID_FILENAME, EM_SETSEL, NULL, 0x7FFF0000L);
          }
          else if (path[0]) {
            // Append a ".MUZ" extension if none given
            if (!(fnsplit(path, drive, dir, file, ext) & EXTENSION))
              strcpy(ext, ".MUZ");
            fnmerge(path, drive, dir, file, ext);

            // Check that the file exists
            ifstream in;
            in.open(path, ios::in | ios::nocreate | ios::binary);
            if (in.fail())
              MessageBox(hDlg, "File does not exist.", NULL,
                MB_ICONEXCLAMATION | MB_OK);
            else {
              // The file exists: close it, and ask if the user
              // wants to save the current melody (in case it
              // has been modified).
              EndDialog(hDlg, TRUE);
              in.close();
              if (!AskSave())
                return TRUE;
              melodyModified = FALSE;

              // Clear the workspace
              while (melody.part.number())
                melody.part.destroyAt(melody.part.number()-1);

              // Use the LoadFrom() virtual function to load the melody
              HCURSOR hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
              in.open(path, ios::in | ios::binary);
              if (melody.LoadFrom(in, LoadError)) {
                // The melody has been successfully loaded:
                // reset a few Boolean flags and make
                // part 0 as the displayed part
                melodyExists = TRUE;
                strcpy(filepath, path);
                SetWindowText(hMainWnd, programTitle);
                InitializeMenu(TRUE);
                scoreDisplay = FALSE;
                displayedPart = 0;
                Part &p = *((Part *) &melody.part[0]);
                SetScrollRange(hEditWnd, SB_VERT, 0,
                  p.staff.number() ?
                  ((Staff *) &p.staff[p.staff.number()-1])->Y() : 0, TRUE);
                InvalidateRect(hMainWnd, NULL, TRUE);
                InvalidateRect(hEditWnd, NULL, TRUE);
                SetCursor(hPrevCursor);
              }
            }
            in.close();
          }
          return TRUE;

        case IDCANCEL:
          // The user cancelled the operation:
          // just exit the dialog box without doing anything
          EndDialog(hDlg, FALSE);
          return TRUE;
      }
  }

  return FALSE;
}

// **********************************************
// Save saves the current melody, asking for a file name
// (i.e. calling SaveAs) if no current file name exists.

BOOL Save()
{
  ofstream out;

  if (filepath[0]) {
    // The melody already has a file name:
    // open the stream and use Melody::printOn to save the melody
    HCURSOR hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
    out.open(filepath, ios::out | ios::binary);
    melody.printOn(out);
    out.close();
    melodyModified = FALSE;
    SetCursor(hPrevCursor);
    return TRUE;
  }
  else {
    // No current file name:
    // open a "Save As..." dialog box
    FARPROC lpDialog = MakeProcInstance((FARPROC) DialogSaveAs, hInst);
    BOOL saved = DialogBox(hInst, "D_FILESAVEAS", hMainWnd, lpDialog);
    FreeProcInstance(lpDialog);
    return saved;
  }
}

// **********************************************
// DialogSaveAs is the "File/Save As..." dialog box function,
// processing messages intended for this dialog box.

BOOL FAR PASCAL DialogSaveAs(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
{
  char path[MAXPATH];
  char drive[MAXDRIVE], dir[MAXDIR], file[MAXFILE], ext[MAXEXT];

  switch (message) {
    case WM_INITDIALOG:
      // Process a WM_INITDIALOG message, indicating that
      // the DialogSaveAs function is called for the first time.
      // The directory list is filled.
      DlgDirList(hDlg, "*.*", ID_DIRLIST, ID_DIRNAME, 0xC010);
      return TRUE;

    case WM_COMMAND:
      // Process a WM_COMMAND message, indicating an action
      // of some kind in the dialog box.
      switch (wParam) {
        case ID_DIRLIST:
          switch(HIWORD(lParam)) {
            case LBN_SELCHANGE:
              // The user has selected a directory:
              // respond by copying the selection to the text field
              DlgDirSelect(hDlg, path, ID_DIRLIST);
              SetDlgItemText(hDlg, ID_FILENAME, path);
              SendDlgItemMessage(hDlg, ID_FILENAME, EM_SETSEL, NULL, 0x7FFF0000L);
              break;

            case LBN_DBLCLK:
              // The user has double-clicked a directory:
              // go on and update the directory list
              goto savefile;
          }
          return TRUE;

        case IDOK:
savefile:
 	  // This point is reached when the user selects OK
          // or double-clicks a directory selection.
          GetDlgItemText(hDlg, ID_FILENAME, path, MAXPATH);
          if (path[strlen(path)-1] == ':' || path[strlen(path)-1] == '\\') {
            // The text field ends with a ':' or '\\', meaning
            // that no file name has been selected yet:
            // refill the directory list box
            DlgDirList(hDlg, path, ID_DIRLIST, ID_DIRNAME, 0xC010);
            SetDlgItemText(hDlg, ID_FILENAME, "");
          }
          else if (path[0]) {
            // Append a ".MUZ" extension to the file name if necessary
            if (!(fnsplit(path, drive, dir, file, ext) & EXTENSION))
              strcpy(ext, ".MUZ");
            fnmerge(path, drive, dir, file, ext);

            // Check if the file already exists
            ofstream out;
            out.open(path, ios::out | ios::noreplace | ios::binary);
            if (out.fail())
              // The file already exists:
              // confirm that it should be overwritten
              if (MessageBox(hDlg, "File already exists. Overwrite?",
                "Warning", MB_ICONINFORMATION | MB_YESNOCANCEL) != IDYES) {
                out.close();
                return TRUE;
              }
            out.close();
            HDC hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));;
            out.open(path, ios::out | ios::trunc | ios::binary);
            EndDialog(hDlg, TRUE);

            // Use the printOn() virtual function to save the melody
            melody.printOn(out);
            out.close();
            melodyModified = FALSE;
            strcpy(filepath, path);
            SetWindowText(hMainWnd, programTitle);
            SetCursor(hPrevCursor);
          }
          return TRUE;

        case IDCANCEL:
          // The user cancelled the operation:
          // exit the dialog box without doing anything
          EndDialog(hDlg, FALSE);
          return TRUE;
      }
  }

  return FALSE;
}

// **********************************************
// DialogCreateMIDI is the "File/Create MIDI..." dialog box function,
// processing message intended for this dialog box.

BOOL FAR PASCAL DialogCreateMIDI(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
{
  char path[MAXPATH];
  char drive[MAXDRIVE], dir[MAXDIR], file[MAXFILE], ext[MAXEXT];

  switch (message) {
    case WM_INITDIALOG:
      // Process a WM_INITDIALOG message, indicating that the
      // DialogCreateMIDI function is called for the first time.
      // The directory list is filled.
      DlgDirList(hDlg, "*.*", ID_DIRLIST, ID_DIRNAME, 0xC010);
      return TRUE;

    case WM_COMMAND:
      // Process a WM_COMMAND message, indicating an action
      // of some kind in the dialog box.
      switch (wParam) {
        case ID_DIRLIST:
          switch(HIWORD(lParam)) {
            case LBN_SELCHANGE:
              // The user has selected a directory:
              // respond by copying the selection to the text field
              DlgDirSelect(hDlg, path, ID_DIRLIST);
              SetDlgItemText(hDlg, ID_FILENAME, path);
              SendDlgItemMessage(hDlg, ID_FILENAME, EM_SETSEL, NULL, 0x7FFF0000L);
              break;

            case LBN_DBLCLK:
              // The user has double-clicked a directory selection:
              // go on and update the directory list
              goto savefile;
          }
          return TRUE;

        case IDOK:
savefile:
          // This point is reached when the user selects OK
          // or double-clicks a directory selection.
          GetDlgItemText(hDlg, ID_FILENAME, path, MAXPATH);
          if (path[strlen(path)-1] == ':' || path[strlen(path)-1] == '\\') {
            // The text field ends with ':' or '\\', meaning
            // that no file has been selected yet:
            // refill the directory list box
            DlgDirList(hDlg, path, ID_DIRLIST, ID_DIRNAME, 0xC010);
            SetDlgItemText(hDlg, ID_FILENAME, "");
          }
          else if (path[0]) {
            // Append a ".MUZ" extension if necessary
            if (!(fnsplit(path, drive, dir, file, ext) & EXTENSION))
              strcpy(ext, ".MID");
            fnmerge(path, drive, dir, file, ext);

            // Check if the file already exists
            ofstream out;
            out.open(path, ios::out | ios::noreplace | ios::binary);
            if (out.fail())
              // The file already exists:
              // confirm that the user wants it overwritten
              if (MessageBox(hDlg, "File already exists. Overwrite?",
                "Warning", MB_ICONINFORMATION | MB_YESNOCANCEL) != IDYES) {
                out.close();
                return TRUE;
              }
            out.close();
            HDC hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));;
            out.open(path, ios::out | ios::trunc | ios::binary);
            EndDialog(hDlg, TRUE);

            // Create the MIDI file
            CreateMIDIFile(out);
            out.close();
            SetCursor(hPrevCursor);
          }
          return TRUE;

        case IDCANCEL:
          // The user cancelled the operation:
          // exit the dialog box without doing anything
          EndDialog(hDlg, FALSE);
          return TRUE;
      }
  }

  return FALSE;
}
