// **********************************************
// File: PRINT.CPP
// Printing functions

#include "muzika.h"
#include <string.h>
#include <values.h>

// **********************************************
// PrintSinglePart dumps the given part to a printer device context.

void PrintSinglePart(HDC hPrinterDC, int part)
{
  // Print a single part
  Part &p = *((Part *) &melody.part[part]);
  Escape(hPrinterDC, STARTDOC, strlen(programTitle), programTitle, NULL);
  Escape(hPrinterDC, NEWFRAME, NULL, NULL, NULL);

  // Draw the staves in the device context
  for (int index = 0; index < p.staff.number(); ++index) {
    Staff &s = *((Staff *) &p.staff[index]);

    int firstY, lastY, relY;
    if (index % p.multiplicity() == 0) {
      firstY = -1;
      lastY = MAXINT-24;
      relY = s.Y()-pixelsPerStaff;
    }

    // Draw the staff itself
    s.Draw(hPrinterDC, relY, FALSE);
    staffX = s.X();
    staffY = s.Y()-relY;

    // Check whether first or last staff in a group
    staffLoc = MIDSTAFF;
    if (index % p.multiplicity() == 0) {
      firstY = staffY;
      staffLoc = FIRSTSTAFF;
    }
    if ((index+1) % p.multiplicity() == 0) {
      lastY = staffY;
      staffLoc = LASTSTAFF;
    }
    if (p.multiplicity() == 1)
      staffLoc = SINGLESTAFF;
    currStaffHeight = (index+1 < p.staff.number()) ?
      ((Staff *) &p.staff[index+1])->Y()-s.Y() : pixelsPerStaff;

    // Draw the point objects inside the staff
    IndexedList &pointList = s.pointObject;
    for (int i = 0; i < pointList.number(); ++i)
      ((PointObject *) &pointList[i])->Draw(hPrinterDC);

    // Draw the continuous objects inside the staff
    IndexedList &contList = s.continuousObject;
    for (i = 0; i < contList.number(); ++i)
      ((ContinuousObject *) &contList[i])->Draw(hPrinterDC);

    if ((index+1)%p.multiplicity() == 0) {
      // Draw the connecting lines of a multiple staff
      MoveTo(hPrinterDC, s.X(), firstY);
      LineTo(hPrinterDC, s.X(), lastY+24);
      MoveTo(hPrinterDC, s.X()+s.width()-1, firstY);
      LineTo(hPrinterDC, s.X()+s.width()-1, lastY+24);

      // Dump the staff to the printer
      Escape(hPrinterDC, NEXTBAND, NULL, NULL, NULL);
    }
  }
  Escape(hPrinterDC, ENDDOC, NULL, NULL, NULL);
}

// **********************************************
// PrintScore makes a hard copy of an entire score.

void PrintScore(HDC hPrinterDC)
{
  int line = 0;
  int staffLeftX = 32;
  int staffRightX = 32+melody.GetStaffWidth();

  Escape(hPrinterDC, STARTDOC, strlen(programTitle), programTitle, NULL);
  Escape(hPrinterDC, NEWFRAME, NULL, NULL, NULL);

  for (int scoreIndex = 0; scoreIndex < scoreStaves; ++scoreIndex) {
    // Print a multiple staff
    for (int partIndex = 0; partIndex < melody.part.number();
      ++partIndex) {
      Part &p = *((Part *) &melody.part[partIndex]);
      for (int staffIndex = scoreIndex*p.multiplicity();
        staffIndex < (scoreIndex+1)*p.multiplicity(); ++staffIndex) {
        // Draw a single staff
        Staff &s = *((Staff *) &p.staff[staffIndex]);
        int tempY = s.Y();
        s.Y() = line += pixelsPerStaff;
        s.Draw(hPrinterDC, 0, FALSE);
        staffX = staffLeftX;
        staffY = line;

        // Draw the point objects inside the staff
        IndexedList &pointList = s.pointObject;
        for (int i = 0; i < pointList.number(); ++i)
          ((PointObject *) &pointList[i])->Draw(hPrinterDC);

        // Draw the continuous objects inside the staff
        IndexedList &contList = s.continuousObject;
        for (i = 0; i < contList.number(); ++i)
          ((ContinuousObject *) &contList[i])->Draw(hPrinterDC);

        s.Y() = tempY;
      }
    }

    // Draw the connecting lines of the score multiple staff
    MoveTo(hPrinterDC, staffLeftX,
      line-(scoreMultiplicity-1)*pixelsPerStaff);
    LineTo(hPrinterDC, staffLeftX, line+24);
    MoveTo(hPrinterDC, staffRightX,
      line-(scoreMultiplicity-1)*pixelsPerStaff);
    LineTo(hPrinterDC, staffRightX, line+24);

    // Dump the multiple staff to printer
    Escape(hPrinterDC, NEXTBAND, NULL, NULL, NULL);
  }

  Escape(hPrinterDC, ENDDOC, NULL, NULL, NULL);
}

// **********************************************
// PrintEditWindow creates a printer device context
// and calls either PrintSinglePart or PrintScore according
// to the current edit window display settings.

void PrintEditWindow()
{
  char pPrintInfo[80];
  LPSTR lpPrintType, lpPrintDriver, lpPrintPort;

  // Create a printer device context
  if (!GetProfileString("windows", "device", "", pPrintInfo, 80)) {
    MessageBox(hMainWnd, "Your system does not have a printer installed.", NULL,
      MB_ICONSTOP | MB_OK);
    return;
  }

  lpPrintType = pPrintInfo;
  lpPrintDriver = _fstrstr(pPrintInfo, ",");
  *lpPrintDriver++ = 0;
  lpPrintPort = _fstrstr(lpPrintDriver, ",");
  *lpPrintPort++ = 0;
  HDC hPrinterDC = CreateDC(lpPrintDriver, lpPrintType, lpPrintPort, NULL);

  if (!scoreDisplay)
    PrintSinglePart(hPrinterDC, displayedPart);
  else
    PrintScore(hPrinterDC);

  DeleteDC(hPrinterDC);
}
