/* General Printer Class to output to a printer
   Mark Solinksi, The Whitewater Group.
*/!!

inherit(Object, #Printer, #(hPrintDC  /* handle to the printer display context */
docName /* name of document */
device  /* current printer */
driver  /* driver file for printer */
port    /* Printer port */
), 2, nil)!!

now(PrinterClass)!!

/* new send an init to instance of self */
Def new(self)
{ ^init(new(self:Behavior))
}!!

now(Printer)!!

/* Change the current printer position to be the 
  receiver point using the printer handle to a device 
  context. */
Def moveTo(self, thePoint)
{ moveTo(thePoint, hPrintDC);
}!!

/* Draw a line from the current position up to, but 
  not including, self, using the printer handle to a 
  display context. Reset the current printer position 
  to be the receiver Point. */
Def lineTo(self, thePoint)
{ lineTo(thePoint, hPrintDC);
}!!

/* End of File. Return a nil if this command is 
  unsuccessful */
Def eof(self)
{ if newPage(self) > 0
  then endDoc(self);
    ^deleteContext(self);
  else ^nil;
  endif;
}!!

/* generic escape which returns a point */
Def escapePoint(self, prtEscape | ans, lpPt, pt, struct)
{ ans := escape(self, prtEscape, 0, 0,
    lpPt:= lP(struct := "    "));
  pt := pointAt(lpPt);
  freeHandle(struct);
  if ans > 0
  then ^pt
  endif;
  ^nil
}!!

/* Turn draft mode off */
Def draftModeOff(self | ans, aStruct)
{ aStruct := new(Struct, 2);
  putWord(aStruct, 0, 0);
  ans := escape(self, DRAFTMODE, 2, lP(aStruct), 0);
  freeHandle(aStruct);
  ^ans;
}!!

/* Turn draft mode on */
Def draftModeOn(self | ans, aStruct)
{ aStruct := new(Struct, 2);
  putWord(aStruct, 1, 0);
  ans := escape(self, DRAFTMODE, 2, lP(aStruct), 0);
  freeHandle(aStruct);
  ^ans;
}!!

/* create a new device context for the printer */
Def  createDC(self)
{ hPrintDC := Call CreateDC(lP(driver), lP(device), lP(port), 0);
  freeHandle(driver);
  freeHandle(device);
  freeHandle(port);
  if hPrintDC > 0
  then ^hPrintDC
  else ^hPrintDC := nil
  endif;
}!!

/* restore the Device Context. */
Def  restoreDC(self, nSavedDC)
{ ^Call RestoreDC(hPrintDC, nSavedDC);
}!!

/* save the DC */
Def  saveDC(self)
{ ^Call SaveDC(hPrintDC);
}!!

/* Printer Escape QUERYESCSUPPORT */
Def  queryEscSupport(self, escNum | ans, aStruct)
{ aStruct := new(Struct, 2);
  putWord(aStruct, escNum, 0);
  ans := escape(self, QUERYESCSUPPORT, 2, lP(aStruct), 0);
  freeHandle(aStruct);
  if not(ans = 0)
  then ^true
  endif;
  ^nil
}!!

/* Printer Escape NEXTBAND */
Def  nextBand(self | rect, ans, bandRect)
{ ans := escape(self, NEXTBAND, 0, 0, lP(rect := &(0, 0, 0, 0)));
  bandRect := getData(rect);
  freeHandle(rect);
  if ans > 0
  then ^bandRect
  endif;
  ^nil
}!!

/* Printer Escape GETSCALINGFACTOR */
Def  getScalingFactor(self)
{ ^escapePoint(self, GETSCALINGFACTOR);
}!!

/* Printer Escape NEWFRAME */
Def newFrame(self)
{ ^escape(self, NEWFRAME, 0, 0, 0);
}!!

/* Printer Escape GETPRINTINGOFFSET */
Def  getPrintingOffset(self)
{ ^escapePoint(self, GETPRINTINGOFFSET);
}!!

/* delete the printer device context */
Def deleteContext(self)
{ ^Call DeleteDC(hPrintDC);
}!!

/* Get the printer parameters from the WIN.INI file */
Def getPrinterParms(self | aStr, aStrm, topic, subject, extra)
{ aStr := getProfileString(self, "windows","device", "", 64);
  if size(aStr) > 0
  then aStrm := streamOver(aStr);
    device := leftJustify(word(aStrm,','));
    driver := leftJustify(word(aStrm,','));
    port := leftJustify(word(aStrm,','));
    ^device;
  endif;
  ^nil
}!!

/* Return the printer display context for self. */
Def getContext(self)
{ ^hPrintDC;
}!!

/* Printer Escape GETPHYSPAGESIZE */
Def  getPhysPageSize(self)
{ ^escapePoint(self, GETPHYSPAGESIZE);
}!!

/* Printer Escape STARTDOC */
Def  startDoc(self | dName, ans)
{ ans := escape(self, STARTDOC, size(docName), lP(docName), 0);
  freeHandle(docName);
  if ans > 0
  then ^ans
  endif;
  ^nil
}!!

/* set the document name to the string */
Def  setDocName(self, aName)
{ docName := aName;
}!!

/* Escape GETCOLORTABLE procedure.  Returns a long 
  integer value corresponding to the RGB color value 
  for the given table entry or nil if unsuccessful */
Def  getColorTable(self, colorTableIndex | idx, rgbStruct, ans, rgb)
{ idx := new(Struct, 2);
  putWord(idx, colorTableIndex, 0);
  rgbStruct := new(Struct, 4);
  ans := escape(self, GETCOLORTABLE, 0, lP(idx), lP(rgbStruct));
  freeHandle(idx);
  rgb := getData(rgbStruct);
  freeHandle(rgbStruct);
  if ans > 0
  then ^longAt(rgb, 0);
  endif;
  ^nil;
}!!

/* Escape FLUSHOUTPUT procedure */
Def  flushOutput(self)
{ ^escape(self, FLUSHOUTPUT, 0, 0, 0);
}!!

/* Escape ENDDOC procedure */
Def  endDoc(self)
{ ^escape(self, ENDDOC, 0, 0, 0);
}!!

/* Escape ABORTDOC procedure */
Def  abortDoc(self)
{ ^escape(self, ABORTDOC, 0, 0, 0);
}!!

/* Escape Code call to Windows */
Def  escape(self, nEscCode, count, inData, outData | ret)
{ ret := Call Escape(errorIfNil(hPrintDC, #printerError), nEscCode, count, inData, outData);
  if ret = 0
  then ^nil
  endif;
  ^ret
}!!
