// **********************************************
// File: SYMCLASS.CPP
// Symbols classes library

#include "muzika.h"
#include "dialog.h"
#include "objects.h"
#include <values.h>
#include <stdio.h>

// **********************************************
// Following are the member function definitions for
// the generic SymbolClass class, from which all the symbol
// classes are derived.

// **********************************************
// SymbolClass::BitmapName returns the bitmap name
// (without the "B_" prefix) of the symbol in the resource file.

int SymbolClass :: BitmapName(LPSTR lpBuffer, int nBufferMax)
{
  // Load the bitmap name from the string table in the resource file
  return LoadString(hInst, symbolID, lpBuffer, nBufferMax);
}

// **********************************************
// SymbolClass::DrawSymbol draws the symbol at its place
// on the screen, derived from its ID code. The symbol is drawn
// in normal or reverse video, according to whether it is active or not.

void SymbolClass :: DrawSymbol(HDC hDC, HDC hBitmapDC, BOOL active)
{
  HBITMAP hBitmap, hOldBitmap;
  char name[19] = "B_";

  // Test if the symbol exists at all
  if (BitmapName(name+2, sizeof(name)-2)) {
    // Load the symbol bitmap from the resource file
    hBitmap = LoadBitmap(hInst, name);
    hOldBitmap = SelectObject(hBitmapDC, hBitmap);

    // Display the bitmap in normal or reverse video
    if (active)
      BitBlt(hDC, 2+36*(symbolID%2), 38+24*(symbolID%0x10/2), 32, 20,
        hBitmapDC, 0, 0, NOTSRCCOPY);
    else
      BitBlt(hDC, 2+36*(symbolID%2), 38+24*(symbolID%0x10/2), 32, 20,
        hBitmapDC, 0, 0, SRCCOPY);
    SelectObject(hBitmapDC, hOldBitmap);
    DeleteObject(hBitmap);
  }
}

// **********************************************
// The NullSymbol class, derived from SymbolClass,
// is the default for the "empty slot" symbols.
// It does nothing except drawing an empty rectangle
// as its DrawSymbol function.

NullSymbol :: NullSymbol()
{
  symbolID = MAXINT;
}

void NullSymbol :: DrawSymbol(HDC hDC, int ID)
{
  Rectangle(hDC, 36*(ID%2), 36+24*(ID%0x10/2),
    36*(ID%2+1)+1, 36+24*(ID%0x10/2+1)+1);
}

NullSymbol nullSymbol;

// **********************************************
// Following are definitions of various symbol classes,
// all derived from the generic SymbolClass.
// For each symbol class there is a constructor,
// putting values in the symbolID and symbolType variables,
// and a CreateObject function, which returns a pointer
// to a newly created MusicalObject corresponding to the symbol.
// Any future extensions of symbols should be added here.

class FullNoteSymbol : virtual public SymbolClass {
  public:
    FullNoteSymbol() {symbolID = 16; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int Y);
} FullNoteSymbol;

MusicalObject *FullNoteSymbol :: CreateObject(int, int X, int Y)
{
  return new Note(X, Y, FULLDURATION);
}

class FullPauseSymbol : virtual public SymbolClass {
  public:
    FullPauseSymbol() {symbolID = 17; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int);
} FullPauseSymbol;

MusicalObject *FullPauseSymbol :: CreateObject(int, int X, int)
{
  return new Pause(X, FULLDURATION);
}

class HalfNoteSymbol : virtual public SymbolClass {
  public:
    HalfNoteSymbol() {symbolID = 18; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int Y);
} HalfNoteSymbol;

MusicalObject *HalfNoteSymbol :: CreateObject(int, int X, int Y)
{
  return new Note(X, Y, HALFDURATION);
}

class HalfPauseSymbol : virtual public SymbolClass {
  public:
    HalfPauseSymbol() {symbolID = 19; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int);
} HalfPauseSymbol;

MusicalObject *HalfPauseSymbol :: CreateObject(int, int X, int)
{
  return new Pause(X, HALFDURATION);
}

class QuarterNoteSymbol : virtual public SymbolClass {
  public:
    QuarterNoteSymbol() {symbolID = 20; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int Y);
} QuarterNoteSymbol;

MusicalObject *QuarterNoteSymbol :: CreateObject(int, int X, int Y)
{
  return new Note(X, Y, QUARTERDURATION);
}

class QuarterPauseSymbol : virtual public SymbolClass {
  public:
    QuarterPauseSymbol() {symbolID = 21; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int);
} QuarterPauseSymbol;

MusicalObject *QuarterPauseSymbol :: CreateObject(int, int X, int)
{
  return new Pause(X, QUARTERDURATION);
}

class EighthNoteSymbol : virtual public SymbolClass {
  public:
    EighthNoteSymbol() {symbolID = 22; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int Y);
} EighthNoteSymbol;

MusicalObject *EighthNoteSymbol :: CreateObject(int, int X, int Y)
{
  return new Note(X, Y, EIGHTHDURATION);
}

class EighthPauseSymbol : virtual public SymbolClass {
  public:
    EighthPauseSymbol() {symbolID = 23; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int);
} EighthPauseSymbol;

MusicalObject *EighthPauseSymbol :: CreateObject(int, int X, int)
{
  return new Pause(X, EIGHTHDURATION);
}

class SixteenthNoteSymbol : virtual public SymbolClass {
  public:
    SixteenthNoteSymbol() {symbolID = 24; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int Y);
} SixteenthNoteSymbol;

MusicalObject *SixteenthNoteSymbol :: CreateObject(int, int X, int Y)
{
  return new Note(X, Y, SIXTEENTHDURATION);
}

class SixteenthPauseSymbol : virtual public SymbolClass {
  public:
    SixteenthPauseSymbol() {symbolID = 25; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int);
} SixteenthPauseSymbol;

MusicalObject *SixteenthPauseSymbol :: CreateObject(int, int X, int)
{
  return new Pause(X, SIXTEENTHDURATION);
}

class KeySolSymbol : virtual public SymbolClass {
  public:
    KeySolSymbol() {symbolID = 32; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} KeySolSymbol;

MusicalObject *KeySolSymbol :: CreateObject(int, int X, int)
{
  return new Key(X, KEYSOL);
}

class KeyFaSymbol : virtual public SymbolClass {
  public:
    KeyFaSymbol() {symbolID = 33; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} KeyFaSymbol;

MusicalObject *KeyFaSymbol :: CreateObject(int, int X, int)
{
  return new Key(X, KEYFA);
}

class BeatCSymbol : virtual public SymbolClass {
  public:
    BeatCSymbol() {symbolID = 48; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} BeatCSymbol;

MusicalObject *BeatCSymbol :: CreateObject(int, int X, int)
{
  return new Beat(X, BEATC);
}

class BeatCBarSymbol : virtual public SymbolClass {
  public:
    BeatCBarSymbol() {symbolID = 49; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} BeatCBarSymbol;

MusicalObject *BeatCBarSymbol :: CreateObject(int, int X, int)
{
  return new Beat(X, BEATCBAR);
}

class Beat28Symbol : virtual public SymbolClass {
  public:
    Beat28Symbol() {symbolID = 50; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} Beat28Symbol;

MusicalObject *Beat28Symbol :: CreateObject(int, int X, int)
{
  return new Beat(X, BEAT28);
}

class Beat24Symbol : virtual public SymbolClass {
  public:
    Beat24Symbol() {symbolID = 51; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} Beat24Symbol;

MusicalObject *Beat24Symbol :: CreateObject(int, int X, int)
{
  return new Beat(X, BEAT24);
}

class Beat38Symbol : virtual public SymbolClass {
  public:
    Beat38Symbol() {symbolID = 52; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} Beat38Symbol;

MusicalObject *Beat38Symbol :: CreateObject(int, int X, int)
{
  return new Beat(X, BEAT38);
}

class Beat34Symbol : virtual public SymbolClass {
  public:
    Beat34Symbol() {symbolID = 53; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} Beat34Symbol;

MusicalObject *Beat34Symbol :: CreateObject(int, int X, int)
{
  return new Beat(X, BEAT34);
}

class Beat48Symbol : virtual public SymbolClass {
  public:
    Beat48Symbol() {symbolID = 54; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} Beat48Symbol;

MusicalObject *Beat48Symbol :: CreateObject(int, int X, int)
{
  return new Beat(X, BEAT48);
}

class Beat44Symbol : virtual public SymbolClass {
  public:
    Beat44Symbol() {symbolID = 55; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} Beat44Symbol;

MusicalObject *Beat44Symbol :: CreateObject(int, int X, int)
{
  return new Beat(X, BEAT44);
}

class Beat68Symbol : virtual public SymbolClass {
  public:
    Beat68Symbol() {symbolID = 56; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} Beat68Symbol;

MusicalObject *Beat68Symbol :: CreateObject(int, int X, int)
{
  return new Beat(X, BEAT68);
}

class BarSymbol : virtual public SymbolClass {
  public:
    BarSymbol() {symbolID = 64; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} BarSymbol;

MusicalObject *BarSymbol :: CreateObject(int, int X, int)
{
  return new Bar(X, BAR);
}

class DoubleBarSymbol : virtual public SymbolClass {
  public:
    DoubleBarSymbol() {symbolID = 65; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} DoubleBarSymbol;

MusicalObject *DoubleBarSymbol :: CreateObject(int, int X, int)
{
  return new Bar(X, DOUBLEBAR);
}

class StartBarSymbol : virtual public SymbolClass {
  public:
    StartBarSymbol() {symbolID = 66; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} StartBarSymbol;

MusicalObject *StartBarSymbol :: CreateObject(int, int X, int)
{
  return new Bar(X, STARTBAR);
}

class EndBarSymbol : virtual public SymbolClass {
  public:
    EndBarSymbol() {symbolID = 67; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int X, int);
} EndBarSymbol;

MusicalObject *EndBarSymbol :: CreateObject(int, int X, int)
{
  return new Bar(X, ENDBAR);
}

class ForteSymbol : virtual public SymbolClass {
  public:
    ForteSymbol() {symbolID = 80; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int);
} ForteSymbol;

MusicalObject *ForteSymbol :: CreateObject(int, int X, int)
{
  return new Loudness(X, FORTE);
}

class FortissimoSymbol : virtual public SymbolClass {
  public:
    FortissimoSymbol() {symbolID = 81; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int);
} FortissimoSymbol;

MusicalObject *FortissimoSymbol :: CreateObject(int, int X, int)
{
  return new Loudness(X, FORTISSIMO);
}

class PianoSymbol : virtual public SymbolClass {
  public:
    PianoSymbol() {symbolID = 82; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int);
} PianoSymbol;

MusicalObject *PianoSymbol :: CreateObject(int, int X, int)
{
  return new Loudness(X, PIANO);
}

class PianissimoSymbol : virtual public SymbolClass {
  public:
    PianissimoSymbol() {symbolID = 83; symbolType = POINTOBJECT;}
    virtual MusicalObject *CreateObject(int, int X, int);
} PianissimoSymbol;

MusicalObject *PianissimoSymbol :: CreateObject(int, int X, int)
{
  return new Loudness(X, PIANISSIMO);
}

class CrescendoSymbol : virtual public SymbolClass {
  public:
    CrescendoSymbol() {symbolID = 84; symbolType = CONTINUOUSOBJECT;}
    MusicalObject *CreateObject(int, int Xleft, int Xright);
} CrescendoSymbol;

MusicalObject *CrescendoSymbol :: CreateObject(int, int Xleft, int Xright)
{
  return new Crescendo(Xleft, Xright, CRESCENDO);
}

class DiminuendoSymbol : virtual public SymbolClass {
  public:
    DiminuendoSymbol() {symbolID = 85; symbolType = CONTINUOUSOBJECT;}
    MusicalObject *CreateObject(int, int Xleft, int Xright);
} DiminuendoSymbol;

MusicalObject *DiminuendoSymbol :: CreateObject(int, int Xleft, int Xright)
{
  return new Crescendo(Xleft, Xright, DIMINUENDO);
}

class TextSymbol : virtual public SymbolClass {
  public:
    TextSymbol() {symbolID = 96; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int staff, int X, int Y);
} TextSymbol;

char _text[MAXTEXT+1];

// **********************************************
// DialogText is the function of the dialog box
// that appears when a Text object is inserted.

BOOL FAR PASCAL _export DialogText(HWND hDlg, unsigned message, WORD wParam, LONG)
{
  switch (message) {
    case WM_INITDIALOG:
      SendDlgItemMessage(hDlg, ID_TEXT, EM_LIMITTEXT, MAXTEXT, 0);
      return TRUE;

    case WM_COMMAND:
      if (wParam == IDOK) {
        GetDlgItemText(hDlg, ID_TEXT, _text, MAXTEXT);
        EndDialog(hDlg, 0);
      }
      return TRUE;
  }

  return FALSE;
}

MusicalObject *TextSymbol :: CreateObject(int, int X, int Y)
{
  FARPROC lpDialog = MakeProcInstance((FARPROC) DialogText, hInst);
  DialogBox(hInst, "D_TEXT", hMainWnd, lpDialog);
  FreeProcInstance(lpDialog);
  return new Text(X, Y, _text);
}

// **********************************************
// The block operation symbols are in no way different
// from any other symbols; their constructors and
// CreateObject functions are similar to those of any
// of the symbols above. However, the CreateObject function
// in these symbols returns a NULL value, indicating
// that no object has been created as a result of the operation.

class MarkBlockSymbol : virtual public SymbolClass {
  public:
    MarkBlockSymbol() {symbolID = 112; symbolType = CONTINUOUSOBJECT;}
    MusicalObject *CreateObject(int staff, int Xleft, int Xright);
} MarkBlockSymbol;

MusicalObject *MarkBlockSymbol :: CreateObject(int staff, int Xleft, int Xright)
{
  MarkBlock(staff, Xleft, staff, Xright);
  return NULL;
}

class CutBlockSymbol : virtual public SymbolClass {
  public:
    CutBlockSymbol() {symbolID = 113; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int, int);
} CutBlockSymbol;

MusicalObject *CutBlockSymbol :: CreateObject(int, int, int)
{
  CutBlock();
  return NULL;
}

class CopyBlockSymbol : virtual public SymbolClass {
  public:
    CopyBlockSymbol() {symbolID = 114; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int, int, int);
} CopyBlockSymbol;

MusicalObject *CopyBlockSymbol :: CreateObject(int, int, int)
{
  CopyBlock();
  return NULL;
}

class PasteBlockSymbol : virtual public SymbolClass {
  public:
    PasteBlockSymbol() {symbolID = 115; symbolType = POINTOBJECT;}
    MusicalObject *CreateObject(int staff, int X, int);
} PasteBlockSymbol;

MusicalObject *PasteBlockSymbol :: CreateObject(int staff, int X, int)
{
  Part &p = *((Part *) &melody.part[displayedPart]);
  PasteBlock(staff/p.multiplicity()*p.multiplicity(), X);
  return NULL;
}

// **********************************************
// The symbolArray is a global array of symbol classes
// in which a symbol with a given ID is searched.
// The list is sorted in the order of increasing ID,
// and ends with a NullSymbol (with the ID of MAXINT).

SymbolClass *symbolArray[] = {
  &FullNoteSymbol, &FullPauseSymbol,
  &HalfNoteSymbol, &HalfPauseSymbol,
  &QuarterNoteSymbol, &QuarterPauseSymbol,
  &EighthNoteSymbol, &EighthPauseSymbol,
  &SixteenthNoteSymbol, &SixteenthPauseSymbol,
  &KeySolSymbol, &KeyFaSymbol,
  &BeatCSymbol, &BeatCBarSymbol,
  &Beat28Symbol, &Beat24Symbol,
  &Beat38Symbol, &Beat34Symbol,
  &Beat48Symbol, &Beat44Symbol,
  &Beat68Symbol,
  &BarSymbol, &DoubleBarSymbol,
  &StartBarSymbol, &EndBarSymbol,
  &ForteSymbol, &FortissimoSymbol,
  &PianoSymbol, &PianissimoSymbol,
  &CrescendoSymbol, &DiminuendoSymbol,
  &TextSymbol,
  &MarkBlockSymbol, &CutBlockSymbol,
  &CopyBlockSymbol, &PasteBlockSymbol,
  &nullSymbol};
