#include "nmm_Microscope.h"
#include "BCGrid.h"

#define NANOM_VERSION    7     // Version 7
#define NANOM_REVISION   1     // Release 1

#define SIN30    0.5
#define COS30    0.8660254037844

#define STM_SCAN_MODE           (2)
#define STM_POINT_MODE          (3)
#define STM_IDLE_MODE           (4)
#define STM_SHUTDOWN_MODE       (5)
#define STM_APPROACH_MODE       (6)
#define STM_ENTER_MODE          (7)
#define STM_PULSE_MODE          (8)
#define STM_ZAG_MODE            (9)
#define STM_ZIG_MODE            (10)
#define SPM_SNAP_MODE           (11)
#define SPM_FORCECURVE_MODE     (12)

#define BOUNCE_ERROR                    100
#define BOUNCE_QUIT                     101
#define BOUNCE_STATUSMESSAGE            102

#define CONNECT_PORT    (5558)
#define BUF_SIZE        (4000)

#define WINSOCK_EVENT   901    // Event happened in the socket
#define WINSOCK_ACCEPT  902    // Sent when connection ready in socket

#define SR_STEPS  10

#define MAX_VAR_SAMPLES (256)
#define MAX_ECHO_DATA   (100)   // Max 4byte words to be echoed back

#define IMAGING_MODE      1

// values for afm_mode
#define TAPPING_MODE   1
#define CONTACT_MODE   2
#define TAP_CON_MODE   3
#define SEWING_MODE    4

#define N_ADC 3


// TODO:
//   Replace with bool, true, false on those systems whose compilers
// support it;  phase out when every OS we need supports bool.

typedef int nm_boolean;
#define NM_TRUE 1
#define NM_FALSE 0

typedef struct {
  int numsets;
  short idAcqType[MAX_REQUEST_POINT_SETS];
  char  units[MAX_REQUEST_POINT_SETS][64];
  float scale[MAX_REQUEST_POINT_SETS];             // The real unit values are computed DAC*scale+offset
  float offset[MAX_REQUEST_POINT_SETS];
  int   num_samples[MAX_REQUEST_POINT_SETS];

typedef struct {
  char name[64];           // Label for this data set          SHO1
  char units[64];          // Units it will be in once conversion is applied  SHO1
  float scale;             // The real unit values are computed DAC*scale+offset 
  float offset;          
  short type;              // Type 

typedef struct {
  int changed;
  int numsets;

#define   sqr(x) ((x)*(x))

typedef struct {
  float max;
  float min;
  float cur;

// Start and stop server and create the simulator object
void StartServer (int, int);
void StopServer (void);

// Added by JakeK and AFMS team for simulator

int mic_start;          // Added by JakeK to determine when connection
int mic_Started();      // is active

static float ** surface = NULL;         // added by JakeK since there is
void set_Surface_Data(BCPlane *);       // no microscope to get data
                                        // from this holds the data

float set_point;                        // added by JakeK to do surface
                                        // modifications

float last_point_x, last_point_y;       // keeps track of last point
                                        // modified to do line connects


class nmm_Microscope_Simulator;

extern vrpn_Connection * connection;
extern nmm_Microscope_Simulator * AFMSimulator;

class nmm_Microscope_Simulator: public nmm_Microscope

        // Simulator server for Microscope



    nmm_Microscope_Simulator (const char * name,
                                vrpn_Connection *);
        // Constructor. Takes as arguments the name of the microscope,
        //      a pointer to a vrpn_Connection.

    virtual ~nmm_Microscope_Simulator (void);
        // Destructor


//    virtual void mainloop (void);
        // virtual from nmm_Microscope.
        // A VRPN mainloop. This function should be called regularly
        //      by the application using an object of this class to
        //      make sure outgoing message buffers get flushed and
        //      incoming messages get read and responded to.

    void stm_init(void);

        void helpShutdown(void);

        void ShutdownSession (void);

        void helpGetConnection();

    int ProcessPendingScanRange();

    int spm_report_latest_PID(float pv, float iv, float dv);

    int spm_report_latest_scanrate(float speed);

    int spm_report_latest_resolution();

    int spm_report_latest_data_sets( SET_OF_DATA_SETS * set );

    int spm_report_latest_point_sets( SET_OF_POINT_SETS point );

    int spm_report_latest_region();

    int spm_report_current_mode(void);

    int spm_report_topo_header();

    int time_to_relax(float x, float y);

    float ScanUnitsToNm( void );

    int spm_is_register_amp_enabled(void);

    int Send( long len, long msg_type, char * buf );

    void spm_store_current_driveamp(float damp);
    float spm_read_current_driveamp(void);

    void set_the_scan_rate (float speed);
    void get_current_xy( float *posx, float *posy );

    int vReportNewScanRange(float vleft, float vright,
                                float vtop, float vbottom);

    int spm_report_force_curve_data();

    int spm_report_window_line_data( int );

    float GetClientScanRateInNm(void);

    int spm_report_latest_angle(void);

    void spm_stop_scan();


    int spmFirstPointSinceZoom;

    //* Custom Timer 2 : For Set Region command
    nm_boolean ProcessSuspended;             // Process Suspended flag
    int cTimer2;                       // Custom Timer 2


    // static CB        callbacks [];

         long d_Shutdown_type;          // HACK XXX Tiger
         long d_GetConnectionFromClient_type;           // HACK XXX Tiger

     float      stm_nmeters_per_second;
     float      stm_max_move;

     long       stm_grid_num_x;
     long       stm_grid_num_y;
     long       stm_window_xmin;
     long       stm_window_ymin;
     long       stm_window_xmax;
     long       stm_window_ymax;

     float      stm_region_xmin;
     float      stm_region_ymin;
     float      stm_region_xmax;
     float      stm_region_ymax;
     float      stm_region_angle;

 *   startup settings   // XXX do I still need them?
     float      startup_p;
     float      startup_i;
     float      startup_d;
     float      startup_setpoint;
     float      startup_scanrate;
     float      startup_scanmode;

 *   Sewing machine mode
     float      afm_sm_set_point;
     unsigned int afm_sm_bot_delay;  //in 0.1 milli-seconds
     unsigned int afm_sm_top_delay;  //in 0.1 milli-seconds
     float      afm_sm_pull_dist;
     float      afm_sm_move_dist;
     float      afm_sm_rate;         // in nM per second
     float      afm_sm_max_close_nm; // the max dist to punch regarless
                                     // of the set point.

     float      afm_last_punch_x;
     float      afm_last_punch_y;
     float      afm_prev_point_x;
     float      afm_prev_point_y;

     float      IS_scale;   // Internal Sensor scale
     float      IS_offset;  // Internal Sensor offset

     nm_boolean         afm_first_punch;
     float      afm_first_punch_distance;

     unsigned int num_punch;

 *   Force curve mode
     float      spm_last_fc_x;
     float      spm_last_fc_y;
     float      spm_fc_move_dist;
     float      spm_fc_start_delay;
     float      spm_fc_z_start;
     float      spm_fc_z_end;
     float      spm_fc_z_pullback;
     float      spm_fc_force_limit;
     long       spm_fc_num_layers;
     long       spm_fc_num_halfcycles;

//* Set region gradual : Changing the region gradually
     float      stm_region_xmin_work;
     float      stm_region_ymin_work;
     float      stm_region_xmax_work;
     float      stm_region_ymax_work;
     float      stm_region_xmin_unit;
     float      stm_region_ymin_unit;
     float      stm_region_xmax_unit;
     float      stm_region_ymax_unit;
     float      stm_region_xmin_actual;
     float      stm_region_ymin_actual;
     float      stm_region_xmax_actual;
     float      stm_region_ymax_actual;

     int        isrStep;
     nm_boolean         SetRegionReceived;
     nm_boolean         ReportAngle;

     long       stm_current_mode;

     float      stm_current_x;          // Where we are right now
     float      stm_current_y;          //

     float      stm_desired_x;          // Where we are seeking to be
     float      stm_desired_y;          //

     float      stm_desired_approach;   // Desired approach location, nm
     float      stm_coarse_z;           // Coarse Z position

     long       stm_scan_style;         // Style of scanning
     long       stm_scan_x;             // Where the area scan is right now
     long       stm_scan_y;
     long       stm_scan_dx;            // Current direction of scan
     long       stm_scan_dy;

     long       StdDelay, StPtDelay;

// These are default settings for the system contact force
     long       fmods_enabled;          // Is cotact force control available?

     struct timeval sewing_start_time;

// Default values for delays after changing contact force before return to scan
     long       RelaxDelay;

     long       stm_num_samples;        // Number of A/D samples to read
     float      stm_sample_freq;        // Sample at 160kHz

     float      fDACtoWorld, fDACtoWorldZero;

     int        force_mode;

     int        afm_mode;
     float      spm_driveamp_set_last;  // Tracks the currently-set drive
                                        // amplitude in the dialog box

     int        ADC1held, ADC2held;     // 1 if currenlty holding ADC

     int UpdateFeedbackParamsNow;       // Enables reporting of PID
                                        //  Setpoint, Amplitude
     int RegisterAmpEnabled;            // Enables registering drive amplitude
                                        // in noncont.c


     char * encode_ScanDataset (long * len, int, char *, char *, int, int);

     char * encode_PointDataset (long * len, int, char *, char *, int, int);

     int report_selected_scanner_desc(void);

     int spm_report_region_clipped( double xmin, double ymin,
                                        double xmax, double ymax );

     int stm_set_grid_size( const char *bufptr );

     int stm_scan_window( const char *bufptr );

     int stm_resume_window_scan();

     int stm_set_rate_nmeters( const char *bufptr );

     int stm_scan_point_nm( const char *bufptr );

     int spm_set_region_angle_gradual( const char *bufptr );

     int stm_set_region_nm_gradual( const char *bufptr );

     int stm_sweep_point_nm( const char *bufptr );

     int spm_query_scan_range( void );

     int spm_set_max_move( const char *bufptr );

     int spm_set_relax( const char *bufptr );

     int spm_blunt_point_nm( const char *bufptr );

     int spm_request_scan_datasets( const char *bufptr );

     int spm_request_point_datasets( const char *bufptr );

     int spm_set_pid( const char *bufptr );

     int afm_sewing_mode( const char *bufptr );

     int afm_contact_mode( const char *bufptr );

     int afm_tapping_mode( const char *bufptr );

     int spm_echo( const char *bufptr );

     int spm_enable_voltsource( const char *bufptr );

     int spm_disable_voltsource( const char *bufptr );

     int spm_enable_amp( const char *bufptr );

     int spm_disable_amp( const char *bufptr );

     int spm_set_slow_scan( const char *bufptr );

     int spm_sharp_line( const char *bufptr );

     int spm_sweep_line( const char *bufptr );

     int spm_sweep_arc( const char *bufptr );

     void PostProcessScanRange();

     int spm_report_angle( float xmin, float ymin, float xmax, float ymax );

     int spm_report_angle_clipped( float xmin, float ymin,
                                        float xmax, float ymax );

     int spm_sweep_step(float to_x, float to_y, float sw_angle, float sw_len); 

     int move_in_sewing_mode( float point_x, float point_y );

     int move_in_forcecurve_mode( float point_x, float point_y );

     int solve_for_intersection( float cx, float cy, float r,
                        float x0, float y0, float x1, float y1,
                        float *ix, float *iy );

     int move_and_punch( float the_desired_x, float the_desired_y );

     int move_and_forcecurve( float the_desired_x, float the_desired_y );

     int punch_out(void);

     int punch_in( float posx, float posy );

     float spm_get_z_value (int NUM_SAMPLES);

     int report_point_set( float x, float y );

     float spm_get_z_piezo_like_scan (int NUM_SAMPLES);

     float spm_get_z_piezo_nM( int NUM_SAMPLES );

     int spm_report_point_datasets( long type, double x, double y,
                                        float* data, int count );

     void spm_goto_xynm( float x, float y );

     int gather_data_and_report(long report_type, float the_desired_x,
                                float the_desired_y, unsigned int wait_time);

     int goto_point_and_report_it(float the_desired_x, float the_desired_y);

     void spm_enable_param_reporting(void);

     void spm_disable_param_reporting(void);

     void spm_enable_register_amp(void);

     void spm_disable_register_amp(void);

     int spm_report_contact_mode(void);

     int spm_report_tapping_mode(void);

         void get_startup_params(float *pv, float *iv, float *dv,
                                                                float *setpoint, float *scanrate, nm_boolean *scanmode);

         void helpTimer2();


     // Receive callbacks
     static int RcvShutdown( void *_userdata, vrpn_HANDLERPARAM _p );
         static int RcvGetConnection( void *_userdata, vrpn_HANDLERPARAM _p ); 
     static int RcvSetRate( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetGridSize( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvScanWindow( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvScanPoint( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvIdle( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvResumeWindowScan( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetStdDevParams( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvQStdDevParams( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetScanStyle( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetContactForce( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvQContactForce( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetRegionNM( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvScanPointNM( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSampleApproachNM( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvQueryScanRange( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvEcho( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvZagPointNM( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetMaxMove( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetStdDelay( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetStPtDelay( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetRelax( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvMeasureResist( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvZigPointNM( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSnapShot( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSnapCancel( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvBluntPointNM( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvReqScanDataset( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetSlowScan( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvReqPotDataset( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetPID( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetRatenMeters( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvEnableVoltsource( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvDisableVoltsource( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvEnableAmp( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvDisableAmp( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSetRegAndAngle( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvClientPacketTimestamp(void *_userdata, vrpn_HANDLERPARAM _p);
     static int RcvSharpLine( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSweepLine( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvSweepArc( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvClientHello( void *_userdata, vrpn_HANDLERPARAM _p );

     static int RcvSewingMode( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvContactMode( void *_userdata, vrpn_HANDLERPARAM _p );
     static int RcvTappingMode( void *_userdata, vrpn_HANDLERPARAM _p );