// -*-c++-*-
// Adam P. Jenkins <ajenkins@cs.umass.edu>
// A class for controlling an Epson scanner.
#ifndef _SCANNER_H_
#define _SCANNER_H_

#include <sys/types.h>
#include <stdio.h>
#include <fstream.h>

// see ESC C, Set Color Mode, documentation.  Not all of these modes
// are supported by all scanners
enum ScanColorMode { 
  SCN_CLR_MONO = 0x0,		// Monochrome, no dropout color (B1-4)
  SCN_CLR_MONO_RED = 0x10,	// monochrome, dropout color red (B2-4)
  SCN_CLR_MONO_GREEN = 0x20,	// mono, dropout color green (B2-4)
  SCN_CLR_MONO_BLUE = 0x30,	// mono, dropout color blue (B2-4)
  SCN_CLR_COLOR_PAGE = 0x1,	// color scanning, page mode (B1-4)
  SCN_CLR_COLOR_LINE = 0x2	// color, line mode (B3,4)
};

// see ESC Z, Set Gamma Correction documentation.
enum ScanGamma {
  SCN_GAMMA_CRTA = 0x1,	// CRT display A (B2-4)
  SCN_GAMMA_CRTB = 0x2,	// CRT display B (B2-4)
  SCN_GAMMA_PRINTA = 0x0,	// Printer output A (B2-4)
  SCN_GAMMA_PRINTB = 0x10,	// Printer output B (B2-4)
  SCN_GAMMA_PRINTC = 0x20,	// Printer output C (B2-4)
  SCN_GAMMA_USER = 0x3		// User defined Gamma table (B4)
};

// see ESC Q, Set Sharpness documentation. Only supported in format B4
enum ScanSharpness {
  SCN_SHARP_XDEFOCUSED = 0xfe,	// very defocused
  SCN_SHARP_DEFOCUSED = 0xff,	// defocused
  SCN_SHARP_NORMAL = 0x0,	// normal
  SCN_SHARP_SHARP = 0x1,	// sharp
  SCN_SHARP_XSHARP = 0x2	// very sharp
};

// see ESC B, Set Halftoning Mode documentation
enum ScanHalftoning {
  SCN_HTONE_HARD = 0x0,	// halftoning mode A (hard tone) (B1-4)
  SCN_HTONE_SOFT = 0x10,	// mode B (soft tone). (B1-4)
  SCN_HTONE_NET = 0x20,	// mode C (net-screen?). (B1-4)
  SCN_HTONE_DITHERA = 0x80,	// dither mode A (4x4 Bayer). (B4)
  SCN_HTONE_DITHERB = 0x90,	// mode B (4x4 Spiral). (B4)
  SCN_HTONE_DITHERC = 0xa0,	// mode C (4x4 net-screen). (B4)
  SCN_HTONE_DITHERD = 0xb0,	// mode D (8x4 net-screen). (B4)
  SCN_HTONE_UDITHERA = 0xc0,	// user defined dither pattern A. (B4)
  SCN_HTONE_UDITHERB = 0xd0,	// user defined dither pattern B. (B4)
  SCN_HTONE_DISABLE = 0x1	// disable halftoning process (B1-4)
};

// see ESC M, Set Color Correction.  For B3,4
enum ScanColorCorrection {
  SCN_CLR_CORRECT_DOTMAT = 0x0, // color dot matrix printers
  SCN_CLR_CORRECT_USER = 0x01,	 // user defined color correction (B4)
  SCN_CLR_CORRECT_IMPACT = 0x10, // impact dot printers (B4)
  SCN_CLR_CORRECT_LASER = 0x20, // color laser
  SCN_CLR_CORRECT_INKJET = 0x40, // color inkjet
  SCN_CLR_CORRECT_CRT = 0x80	  // color monitors
};

// see ESC g, Set Scanning Mode.  For EXT format
enum ScanScanmode {
  SCN_MODE_NORMAL = 0x0,	// normal speed mode
  SCN_MODE_FAST = 0x1		// high speed mode
};

// to hold the current settings, as returned by ESC S
struct ScanSettings {
  ScanColorMode color_mode;	// ref (ESC C)
  int main_scan_res;		// main scan resolution (ref ESC R)
  int sub_scan_res;		// sub scan resolution
  int main_scan_offset;	// ref. ESC A
  int sub_scan_offset;
  int main_scan_area;
  int sub_scan_area;
  int bits_per_pixel;		// ref. ESC D
  ScanHalftoning halftone;	// ref. ESC B
  int brightness;		// ref. ESC L
  ScanGamma gamma;		// gamma correction ref. ESC Z
  int main_scan_zoom;		// horizontal zoom. ref. ESC H
  int sub_scan_zoom;		// vertical zoom
  ScanColorCorrection color_correction; // ref. ESC M
  ScanSharpness sharpness;	// ref. ESC Q
  ScanScanmode scanmode;	// ref ESC g
  int linecounter;		// number of line per block ref. ESC d
};

// to hold the current settings, as returned by ESC S.  This is a new
// version that takes the main and subscan areas in inches instead of
// pixels, and let's the driver figure out how many pixels that should
// be.  
struct ScanNewSettings {
  ScanColorMode color_mode;	// ref (ESC C)
  int main_scan_res;		// main scan resolution (ref ESC R)
  int sub_scan_res;		// sub scan resolution
  float main_scan_offset;	// ref. ESC A
  float sub_scan_offset;
  float main_scan_area;
  float sub_scan_area;
  int bits_per_pixel;		// ref. ESC D
  ScanHalftoning halftone;	// ref. ESC B
  int brightness;		// ref. ESC L
  ScanGamma gamma;		// gamma correction ref. ESC Z
  int main_scan_zoom;		// horizontal zoom. ref. ESC H
  int sub_scan_zoom;		// vertical zoom
  ScanColorCorrection color_correction; // ref. ESC M
  ScanSharpness sharpness;	// ref. ESC Q
  ScanScanmode scanmode;	// ref ESC g
  int linecounter;		// number of line per block ref. ESC d
};


// to hold info returned by ESC I
struct ScanIdentity {
  int software_level;	// B1-4
  int resolutions[30];	// 0 terminated list of available res.
  int max_resolution;	// need this in some places
  int max_horiz_area;	// max horizontal reading area
  int max_vert_area;	// max vertical reading area
};

// to hold info returned by ESC I, new version with max_horiz_area and
// max_vert_area in inches rather than in pixels
struct ScanNewIdentity {
  int software_level;	// B1-4
  int resolutions[30];	// 0 terminated list of available res.
  int max_resolution;	// need this in some places
  float max_horiz_area;	// max horizontal reading area
  float max_vert_area;	// max vertical reading area
};

class Scanner {
public:
  Scanner(void);		// use initialize() to init

  ~Scanner(void) {}
  
  int open(char const *device) { return 0; } // open the device
  int open() { return 0; }		     // try to find the scanner device
  int close(void) { return 0; }		     // close device


  const char *strError() const { return errStr; }
  void getSettings(ScanSettings& s) const { s = settings; }
  void getIdentity(ScanIdentity& i) const { i = identity; }
  int applySettings(const ScanSettings& s);

  // the new version of the above commands.
  void getSettings(ScanNewSettings& s) const;
  void getIdentity(ScanNewIdentity& i) const;
  int applySettings(const ScanNewSettings& s);

  // return the size the scanned image will take up.
  int scanSize(void) const; 
  // Start scanning (ESC G, B1-4)
  int startScan(ostream& out, int (*clbk)(int) = NULL) { return 0; }
  int startScan(const char *fname, int (*clbk)(int) = NULL);
  int initScan(const char *fname);
  int scanBlock(bool cancel = false);
  int cancelScan() { return 0; }
   
  // Execution commands
  int identify(void) { return 0; } // Identify the properties of scanner (ESC I, B1-4)
  int requestStatus(void) { return 0; } // Check status of scanner (ESC F, B1-4)
  int requestCondition(void) { return 0; } // Current parameter values (ESC S, B1-4)
  int initialize(void) { return 0; } // initialize device (ESC @, B2-4)

private:

  ScanIdentity identity;
  ScanSettings settings;

  int bytesRead;
  char errStr[200];
  FILE *outf;
  unsigned char *inp;
};

#endif // _SCANNER_H_
