//========================================================================
//
// Function.h
//
// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================

//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
// Copyright (C) 2009, 2010, 2018, 2019 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
// Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
// Copyright (C) 2012 Adam Reichold <adamreichold@myopera.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================

#ifndef FUNCTION_H
#define FUNCTION_H

#include "Object.h"
#include <set>

class Dict;
class Stream;
struct PSObject;
class PSStack;

//------------------------------------------------------------------------
// Function
//------------------------------------------------------------------------

#define funcMaxInputs        32
#define funcMaxOutputs       32
#define sampledFuncMaxInputs 16

class Function {
public:

  Function();

  virtual ~Function();

  Function(const Function &) = delete;
  Function& operator=(const Function &other) = delete;

  // Construct a function.  Returns NULL if unsuccessful.
  static Function *parse(Object *funcObj);

  // Initialize the entries common to all function types.
  bool init(Dict *dict);

  virtual Function *copy() const = 0;

  // Return the function type:
  //   -1 : identity
  //    0 : sampled
  //    2 : exponential
  //    3 : stitching
  //    4 : PostScript
  virtual int getType() const = 0;

  // Return size of input and output tuples.
  int getInputSize() const { return m; }
  int getOutputSize() const { return n; }

  double getDomainMin(int i) const { return domain[i][0]; }
  double getDomainMax(int i) const { return domain[i][1]; }
  double getRangeMin(int i) const { return range[i][0]; }
  double getRangeMax(int i) const { return range[i][1]; }
  bool getHasRange() const { return hasRange; }
  virtual bool hasDifferentResultSet(const Function *func) const { return false; }

  // Transform an input tuple into an output tuple.
  virtual void transform(const double *in, double *out) const = 0;

  virtual bool isOk() const = 0;

protected:
  static Function *parse(Object *funcObj, std::set<int> *usedParents);

  Function(const Function *func);

  int m, n;			// size of input and output tuples
  double			// min and max values for function domain
    domain[funcMaxInputs][2];
  double			// min and max values for function range
    range[funcMaxOutputs][2];
  bool hasRange;		// set if range is defined
};

//------------------------------------------------------------------------
// IdentityFunction
//------------------------------------------------------------------------

class IdentityFunction: public Function {
public:

  IdentityFunction();
  ~IdentityFunction() override;
  Function *copy() const override { return new IdentityFunction(); }
  int getType() const override { return -1; }
  void transform(const double *in, double *out) const override;
  bool isOk() const override { return true; }

private:
};

//------------------------------------------------------------------------
// SampledFunction
//------------------------------------------------------------------------

class SampledFunction: public Function {
public:

  SampledFunction(Object *funcObj, Dict *dict);
  ~SampledFunction() override;
  Function *copy() const override { return new SampledFunction(this); }
  int getType() const override { return 0; }
  void transform(const double *in, double *out) const override;
  bool isOk() const override { return ok; }
  bool hasDifferentResultSet(const Function *func) const override;

  int getSampleSize(int i) const { return sampleSize[i]; }
  double getEncodeMin(int i) const { return encode[i][0]; }
  double getEncodeMax(int i) const { return encode[i][1]; }
  double getDecodeMin(int i) const { return decode[i][0]; }
  double getDecodeMax(int i) const { return decode[i][1]; }
  const double *getSamples() const { return samples; }
  int getSampleNumber() const { return nSamples; }

private:

  SampledFunction(const SampledFunction *func);

  int				// number of samples for each domain element
    sampleSize[funcMaxInputs];
  double			// min and max values for domain encoder
    encode[funcMaxInputs][2];
  double			// min and max values for range decoder
    decode[funcMaxOutputs][2];
  double			// input multipliers
    inputMul[funcMaxInputs];
  int *idxOffset;
  double *samples;		// the samples
  int nSamples;			// size of the samples array
  double *sBuf;			// buffer for the transform function
  mutable double cacheIn[funcMaxInputs];
  mutable double cacheOut[funcMaxOutputs];
  bool ok;
};

//------------------------------------------------------------------------
// ExponentialFunction
//------------------------------------------------------------------------

class ExponentialFunction: public Function {
public:

  ExponentialFunction(Object *funcObj, Dict *dict);
  ~ExponentialFunction() override;
  Function *copy() const override { return new ExponentialFunction(this); }
  int getType() const override { return 2; }
  void transform(const double *in, double *out) const override;
  bool isOk() const override { return ok; }

  const double *getC0() const { return c0; }
  const double *getC1() const { return c1; }
  double getE() const { return e; }

private:

  ExponentialFunction(const ExponentialFunction *func);

  double c0[funcMaxOutputs];
  double c1[funcMaxOutputs];
  double e;
  bool isLinear;
  bool ok;
};

//------------------------------------------------------------------------
// StitchingFunction
//------------------------------------------------------------------------

class StitchingFunction: public Function {
public:

  StitchingFunction(Object *funcObj, Dict *dict, std::set<int> *usedParents);
  ~StitchingFunction() override;
  Function *copy() const override { return new StitchingFunction(this); }
  int getType() const override { return 3; }
  void transform(const double *in, double *out) const override;
  bool isOk() const override { return ok; }

  int getNumFuncs() const { return k; }
  const Function *getFunc(int i) const { return funcs[i]; }
  const double *getBounds() const { return bounds; }
  const double *getEncode() const { return encode; }
  const double *getScale() const { return scale; }

private:

  StitchingFunction(const StitchingFunction *func);

  int k;
  Function **funcs;
  double *bounds;
  double *encode;
  double *scale;
  bool ok;
};

//------------------------------------------------------------------------
// PostScriptFunction
//------------------------------------------------------------------------

class PostScriptFunction: public Function {
public:

  PostScriptFunction(Object *funcObj, Dict *dict);
  ~PostScriptFunction() override;
  Function *copy() const override { return new PostScriptFunction(this); }
  int getType() const override { return 4; }
  void transform(const double *in, double *out) const override;
  bool isOk() const override { return ok; }

  const GooString *getCodeString() const { return codeString; }

private:

  PostScriptFunction(const PostScriptFunction *func);
  bool parseCode(Stream *str, int *codePtr);
  GooString getToken(Stream *str);
  void resizeCode(int newSize);
  void exec(PSStack *stack, int codePtr) const;

  GooString *codeString;
  PSObject *code;
  int codeSize;
  mutable double cacheIn[funcMaxInputs];
  mutable double cacheOut[funcMaxOutputs];
  bool ok;
};

#endif
