/**********************************************************************
 *     EPSCAN, an EPSON ES-1200 scanner driver     
 *     Adam P. Jenkins <ajenkins@cs.umass.edu>
 *     
 *     This program is free software; you can redistribute it and/or
 *     modify it under the terms of the GNU General Public License
 *     as published by the Free Software Foundation; either version 2
 *     of the License, or (at your option) any later version.
 *     
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *     
 *     You should have received a copy of the GNU General Public License
 *     along with this program; if not, write to the Free Software
 *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **********************************************************************/

// -*-c++-*-

#include <qobject.h>

#include "Scanner.h"

class SScanner;

class SScanSettings
{
  Q_OBJECT;
public:
  SScanSettings();
  //  SScanSettings(const SScanSettings& s);
  ScanColorMode colorMode() const;

  // access functions
  int resolution() const;
  float horOffset() const;
  float verOffset() const;
  float horLength() const;
  float verLength() const;
  int depth() const;
  ScanHalftoning halftoning() const;
  int brightness() const;
  ScanGamma gamma() const;
  int zoom() const;
  ScanColorCorrection colorCorrection() const;
  ScanSharpness sharpness() const;
  ScanScanmode scanMode() const;
  int maxBlockSize() const;
  const int *resolutions() const;
       
  float maxHorLength() const;
  float maxVerLength() const;

  // set functions
  void setColorMode(ScanColorMode mode);
  void setResolution(int res);
  void setScanArea(float hoff, float voff, float hlen, float vlen);
  void setDepth(int depth);	// bits per sample
  void setHalftoning(ScanHalftoning half);
  void setBrightness(int bright);
  void setGamma(ScanGamma gamma);
  void setZoom(int z);
  void setColorCorrection(ScanColorCorrection correct);
  void setSharpness(ScanSharpness sharp);
  void setScanMode(ScanScanmode mode);
  void setMaxBlockSize(int size);

  void setDefaults();
protected:
  friend class SScanner;
  const ScanSettings &getSettings();
  const ScanIdentity &getIdentity() const;  

  void setSettings(ScanSettings& set);
  void setIdentity(ScanIdentity& id);
private:
  ScanSettings
    settings,
    defaults;

  ScanIdentity identity;
  
  float
    hoffset,			// offsets and length are in inches
    voffset,
    hlength,
    vlength;

  int maxblocksize;

  void calculate();		// finds the real lengths in pixels. this
				// be called after all settings have been
				// made, but before sending to the scanner  
};


class SScanner : public SScanSettings
{
  Q_OBJECT;
public:
  SScanner();
  ~SScanner();

  int open(const char *device = 0);
  void close();

  bool ok() const;		// returns true if no errors pending
  void clear();			// clear any errors

  SScanSettings getScanSettings() const;
  void setScanSettings(const SScanSettings& s);
public slots:
  void acquire(const char *fname); // acquire an image and save it fname

private:
  Scanner *dev;
  bool ok;
};


  
// SScanSettings inline functions
inline
SScanSettings::SScanSettings()
{
  maxblocksize = 32*1024;	// Really I should use SG_BIG_BUFF from sg.h
}

inline ScanColorMode
SScanSettings::colorMode() const
{ return settings.color_mode; }

inline int
SScanSettings::resolution() const
{ return settings.main_scan_res; }

inline float
SScanSettings::horOffset() const
{ return hoffset; }

inline float
SScanSettings::verOffset() const
{ return voffset; }

inline float
SScanSettings::horLength() const
{ return hlength; }

inline float
SScanSettings::verLength() const
{ return vlength; }

inline int
SScanSettings::depth() const
{ return settings.bits_per_pixel; }

inline ScanHalftoning
SScanSettings::halftoning() const
{ return settings.halftone; }

inline int
SScanSettings::brightness() const
{ return settings.brightness; }

inline ScanGamma
SScanSettings::gamma() const
{ return settings.gamma; }

inline int
SScanSettings::zoom() const
{ return settings.main_scan_zoom; }

inline ScanColorCorrection
SScanSettings::colorCorrection() const
{ return settings.color_correction; }

inline ScanSharpness
SScanSettings::sharpness() const
{ return settings.sharpness; }

inline ScanScanmode
SScanSettings::scanMode() const
{ return settings.scanmode; }

inline int
SScanSettings::maxBlockSize() const
{ return maxblocksize; }

inline const int *
SScanSettings::resolutions() const
{ return identity.resolutions; }

inline float
SScanSettings::maxHorLength() const
{
  return (float)identity.max_horiz_area / (float)identity.max_resolution;
}

inline float
SScanSettings::maxVerLength() const
{
  return (float)identity.max_vert_area / (float)identity.max_resolution;
}

// inline slots for SScanSettings
inline void
SScanSettings::setColorMode(ScanColorMode mode)
{ settings.color_mode = mode; }

inline void
SScanSettings::setScanArea(float hoff, float voff,
			   float hlen, float vlen)
{
  if (hoff >= 0.0 && hoff < maxHorLength())
    hoffset = hoff;
  if (voff >= 0.0 && voff < maxVerLength())
    voffset = voff;
  if (hlen > 0.0 && hlen < maxHorLength())
    hlength = hlen;
  if (vlen > 0.0 && vlen < maxHorLength())
    vlength = vlen;
}

inline void
SScanSettings::setDepth(int depth)
{
  switch (depth) {
  case 1:
  case 4:
  case 8:
    settings.bits_per_pixel = depth;
  }
}

inline void
SScanSettings::setHalftoning(ScanHalftoning half)
{ settings.halftone = half; }

inline void
SScanSettings::setBrightness(int bright)
{
  if (bright >= -3 && bright <= 3)
    settings.brightness = bright;
}

inline void
SScanSettings::setGamma(ScanGamma gamma)
{ settings.gamma = gamma; }

inline void
SScanSettings::setZoom(int zoom)
{
  if (zoom >= 50 && zoom <= 200)
    settings.main_scan_zoom = settings.sub_scan_zoom = zoom;
}

inline void
SScanSettings::setColorCorrection(ScanColorCorrection correct)
{ settings.color_correction = correct; }

inline void
SScanSettings::setSharpness(ScanSharpness sharp)
{ settings.sharpness = sharp; }

inline void
SScanSettings::setScanMode(ScanScanmode mode)
{ settings.scanmode = mode; }

inline void
SScanSettings::setMaxBlockSize(int size)
{ maxblocksize = size; }

inline const ScanSettings&
SScanSettings::getSettings()
{
  calculate();
  return settings;
}

inline const ScanIdentity&
SScanSettings::getIdentity() const
{ return identity; }


inline void
SScanSettings::setIdentity(ScanIdentity& id)
{ identity = id; }

inline bool
SScanner::ok() const
{ return ok; }

inline void
SScanner::clear()
{ ok = true; }

inline SScanSettings
SScanner::getScanSettings() const
{ return (SScanSettings)(*this); }

inline void
SScanner::setScanSettings(const SScanSettings& s)
{
  SScanSettings *pthis = this;
  *pthis = s;
}
