#ifndef FIXATION_FILTER_H
#define FIXATION_FILTER_H

// some additions made by ARF: Andrew R. Freed
// original fixfunc.c found at:
// http://www.freedville.com/professional/thesis/eyetrack/source-code/fixfunc.c
// (last accessed 2/7/2009)

#define MOVING 0
#define FIXATING 1
#define FIXATION_COMPLETED 2

#define RING_SIZE 30	// length of delay in detectFixation() -- should be
			// greater than minimum_fix_samples

// Mike Ashmore wrote: This is by no means my original work.
// For details on the source from which this class was created,
// please see the implementation file fixationfilter.cpp
// (short version: LC technologies made a C version of these
// methods available on the web at http://www.eyegaze.com)

class FixationFilter {
   public:
      FixationFilter(float gaze_dev_threshold = 0.91,
		       int minimum_fix_samples = 5);

   private:
      void initFixation(int minimum_fix_samples);
      void resetPresentFixation(void);
      void resetNewFixation(void);
      void startPresentFixationAtGazepoint(float x_gaze, float y_gaze);
      void startNewFixationAtGazepoint(float x_gaze, float y_gaze);
      void updatePresentFixation(float x_gaze, float y_gaze);
      void updateNewFixation(float x_gaze, float y_gaze);
      void calculateGazeDeviationFromPresentFixation(float x_gaze, float y_gaze);
      void calculateGazeDeviationFromNewFixation(float x_gaze, float y_gaze);
      void checkIfFixating(void);
      void moveNewFixationToPresentFixation(void);
      void declareCompletedFixation(void);
      void restoreOutPoints(void);

   public:
      // parameters that can be set and forgotten
      float gaze_deviation_threshold;	// distance that a gazepoint may deviate
					// from the average fixation point and
					// still be considered part of that
					// fixation
      int minimum_fixation_samples;	// minimum number of samples necessary
					// to call a fixation

      // output parameters that store current state and can be queried
      // externally
      unsigned char gazepoint_found_delayed;
					// sample gazepoint-found flag,
					//   minimum_fixation_samples ago 
      float x_gaze_delayed;		// sample gazepoint coordinates
      float y_gaze_delayed;		//   minimum_fixation_samples ago 
      float gaze_deviation_delayed;	// deviation of the gazepoint from the
					//   present fixation
					//   minimum_fixation_samples ago 
					// fixation data -- delayed:
      float x_fix_delayed;		// fixation point as estimated
      float y_fix_delayed;		//   minimum_fixation_samples ago
      int saccade_duration_delayed;	// duration of the saccade preceeding
					//   the present fixation (samples)
      int fix_duration_delayed;		// duration of present fixation
					//   (samples)

      // public member function (main member that gets called)
      int detectFixation(bool gazepoint_found, float x_gaze, float y_gaze);

      int getPrevSaccadeDuration()	{ return saccade_duration_delayed; }
      int getFixationDuration()		{ return fix_duration_delayed; }
      float getFixation_x()		{ return x_fix_delayed; }
      float getFixation_y()		{ return y_fix_delayed; }

   private:
      // GLOBAL FIXFUNC VARIABLES
      long callCount;			// times called since initialization
      int nNoEyeFound;			// successive samples with no eye found
      // DATA ON PREVIOUS FIXATION
      long prevFixEndCount;		// count that the previous fixation
					//   ended
      // DATA ON PRESENT FIXATION
      long presFixStartCount;		// call count that the fixation starts
      long presFixEndCount;		// call count that the fixation ends
      int nPresFixSamples;		// number of samples in the present fix
      float xPresFixSum;		// summations for calculation of average
      float yPresFixSum;		//   fixation position
      float xPresFix;			// average coordinate of the present
					//   fixation (x-part)
      float yPresFix;			// average coordinate of the present
					//   fixation (y-part)
      int nPresOut;			// number of samples outside the
					//   fixation
      float presDr;			// difference between gazepoint and
					//   fixation (x, y, and radius)
      // DATA ON NEW FIXATION
      long new_fix_start_count;		// call count that the new fixation
					//   starts
      long new_fix_end_count;		// call count that the new fixation ends
      int n_new_fix_samples;		// number of samples in the new fixation
      float x_new_fix_sum;		// summations for the FIR filter
      float y_new_fix_sum;		//   calculations of the eye motion
      float x_new_fix;			// average coordinate of the eye
					//   fixation point
      float y_new_fix;			// y-portion of that coordinate
      float new_dr;			// difference between gazepoint and
					//   fixation (x, y, and radius)
      // RING BUFFERS STORING PAST VALUES
      float x_gaze_ring[RING_SIZE];
      float y_gaze_ring[RING_SIZE];
      bool gaze_found_ring[RING_SIZE];
      int eye_motion_state[RING_SIZE];
      float x_fix_ring[RING_SIZE];
      float y_fix_ring[RING_SIZE];
      float gaze_deviation_ring[RING_SIZE];
      int sac_duration_ring[RING_SIZE];
      int fix_duration_ring[RING_SIZE];
      int ringIndex;			// ring index of the present gaze sample
      int ringIndexDelay;		// rind index of the gaze sample taken
					//   minimum_fix_samples ago
};

#endif
