/****************************************************************************/
/* Copyright (c) 2000 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : Simulator.h                                                   */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 02/07/2000                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#ifndef _SIMULATOR_H
#define _SIMULATOR_H
#define CMLEN   256            //UTM Package

#include "SimulatorIF_SK.h"
#include "VehicleConfigurationIF.h"
#include "Attributes.h"
#include "DropWeightIF.h"
#include "EventLogIF.h"
#include "LayeredControlIF.h"
#include "MissionClock.h"
#include "Exception.h"
#include "SimulationLog.h"

class Simulator : public SimulatorIF_SK {

public:

  friend class SimulationLog;

  Simulator(const char *configFileName, const char *outputFileName);

  ~Simulator();

  // Exception 
  class Error : public Exception {

  public:

    Error(char *errorMsg) : Exception(errorMsg) {
    }
  };


protected:

  virtual long setCurrent(double north, double east);

  virtual long command(double propOmega, double elevator, double rudder);

  virtual long state(SimulatorIF::Vector position,
		     SimulatorIF::Vector positionRate,
		     SimulatorIF::Vector eulerAngles,
		     SimulatorIF::Vector rotationRate);

  virtual long rotationalVelocity(SimulatorIF::Vector velocity, 
				  SimulatorIF::Vector backDiff);

  virtual long translationalVelocity(SimulatorIF::Vector velocity, 
				     SimulatorIF::Vector backDiff);

  virtual long translationalBottomVelocity(SimulatorIF::Vector vel_Bo_N_N);

  virtual long controlSurfaces(double *rudder, double *elevator);

  virtual long force(SimulatorIF::Vector vector);

  virtual long torque(SimulatorIF::Vector vector);

  virtual long propOmega(double *omega);

  virtual long motorCurrent(double *motor);

  virtual long waterSpeed(double *speed);

  virtual double waterDepth();

  virtual double simTime();

  virtual int spawnAuxTasks();

  virtual long nTs();

private:

  struct InputData {

    InputData();
    float vehicleMass;
    double propOmega;
    double rudder;
    double elevator;
    double northCurrent;
    double eastCurrent;
    double vehicleSpeed;
  };

  struct OutputData {
    OutputData();
    void initialize();

    double position[3];
    double eulerAngles[3];
    double rotationalVelocity[3];
    double rotationalBackDiff[3];
    double translationalVelocity[3];
    double vel_Bo_N_B[3];
    double translationalBackDiff[3];
    double rudder;
    double elevator;
    double rudderCmd;
    double elevatorCmd;
    double force[3];
    double torque[3];
    double propOmega;
    double M1_1;
    double M2_1;
    double M3_1;
    double M4_1;
    double M1_2;
    double M2_2;
    double M3_2;
    double M4_2;
  };

  //
  // This is the original logging class, Log.  It's been replaced by 
  // SimulationLog.
  //
  class Log {

  public:

    Log(const char *fileName);
    ~Log();

    int write(double time, OutputData *output);

  private:

    FILE *_outputFile;

  };

  //Log *_log;                                           /* The old way */
  SimulationLog *_log;                                   /* The new way */


  VehicleConfigurationIF *_configuration;
  DropWeightIF *_dropWeight;
  EventLogIF _eventLog;
  EventLogIF::Message _eventMsg;
  LayeredControlIF *_layeredControl;

  InputData _input;
  OutputData _output;

  void init_simulation( void );

  MissionClock *_missionClock;

  // Calculates left-hand-side of the eqn 
  void lhs();

  // Subroutine motion() uses 4th-order Runge-Kutta method.  Variables are:
  void motion( double e[], double p[], double Amps, double Del13,
			  double Del24, double dt );

  // Get the right-hand sides of the dynamic equations.
  void hydro( double *e, double *p, double Amps, double Del13, 
			 double Del24, double dt );

  // Compute forces generated by control surfaces
  void fins( double *e, double rud_ang, double elev_ang );

  // Move at either zero, full forward, or full backward speed.
  double act_model(double des_angle, double angle, double dt);

  // Hysteresis: applied to an arbitrary input, probably elevator or
  // rudder.  Width and center of loop are defined with other physical
  // variables.
  double hysteresis( double x, double x_last, double y_last, 
				double wide, double center);

  // Computation of the thruster force from the Amps
  double thruster_force( double real_amps, double w_speed );

  // Computation of the thruster torque from the Amps
  double thruster_torque( double real_amps, double w_speed );

  // Matrix calculations, not sure where their from, probably
  // numerical recipes in fortran (note array element[0] unused!)
  int matinv( double a[][7], double ainv[][7], int n, 
			 double adum[][7] );

  double gasdev( void );

  double drand48( void );

  // Called when event is received from LayeredControlIF object
  void missionStatusCallback(TaskInterface *taskInterface,
			     EventCode eventCode);

  Attributes _attributes;

  VehicleConfigurationIF::Vector _centerOfMass;
  VehicleConfigurationIF::Vector _centerOfBuoyancy;
  VehicleConfigurationIF::Vector _dropWt1Location;
  VehicleConfigurationIF::Vector _dropWt2Location;
  double omega_P;
  double Pit;
  double Area;
  double Eta;
  double Cdf1;         /* Emperical Coef. of Drag Modifier */
  double Kthr;         /* Factor relating commanded speed, uC, to omega_P */

  double rho;          /* Density of seawater */
  double rhs[7];       /* calculated in hydro, used in motion */
  double ainv[7][7];   /* calculated by lhs, used in motion   */

  /* coordinate transformation matrix, we use only indices 1-6 */
  static double ctrn[7][7];

  int jjj;  /* runge-kutta index (shouldn't be global) but is ? */

/* FINS.  Note fin #1 is lower rudder, #2 is port elevator, #3 is
   upper rudder, #4 is stbd elevator.  This fin model is taken
   directly from PNA, which cites Whicker and Fehlner, 1958.  */
  double r1[4], r2[4], r3[4], r4[4];

  /*---- Forces and moments due to the fins ----*/
  double F1[4], F2[4], F3[4], F4[4];
  double M1[4], M2[4], M3[4], M4[4];

  double Wdw1;
  double Bdw1;
  double Xdw1;
  double Ydw1;
  double Zdw1;

  double Wdw2;
  double Bdw2;
  double Xdw2;
  double Ydw2;
  double Zdw2;

  // Simulation time increment
  static const double _timeIncr;

  static const double Ixy;
  static const double Izx;
  static const double Iyz;

  static const double fin_speed;
  static const double cdo;         /* Cd from NACA 0015 section */
  static const double ec;            /* "Oswald" efficiency factor */

  static const int delay;

/* THRUSTER. ------------------------------------------------------------*/
  static const double Kt;  /* torque constant (in Nm/A) - inc gearbox */
  double thrAmps; /* Motor current, amps. */



  double Ixx;
  double Iyy;
  double Izz;

  /* hydrodynamic parameters ----------------------------------------------*/

  /* quadratic drag */
  double Kpabp;             /* we do fin drag effects separately*/
  double Mqabq;          /* value from get_drag.tex; G/T had -9800*/
  double Nrabr;
  double Xuabu;
  double Yvabv;
  double Zwabw;

  /* added mass */
  double Kpdot;
  double Mqdot;
  double Nrdot;
  double Xudot;
  double Yvdot;
  double Zwdot;

  /* added mass cross terms */
  double Kvdot;
  double Mwdot;
  double Nvdot;
  double Yrdot;
  double Ypdot;
  double Zqdot;

  /* quadratic drag cross terms */
  double Mwabw;
  double Nvabv;
  double Yrabr;
  double Zqabq;

  /* in-line lift and drag */
  double Muq;
  double Muw;
  double Mpr;

  double Nur;
  double Nuv;
  double Npq;

  double Xvv;
  double Xww;
  double Xvr;
  double Xwq;
  double Xrr;
  double Xqq;

  double Yur;
  double Yuv;
  double Ywp;

  double Zuq;
  double Zuw;
  double Zvp;

  double Kvt2;

  double aspect_ratio;               /* effective aspect ratio */
  double stall_angle;                /* fin stall angle */
  double wide_hyst_rud;              /* hysteresis loop double width */
  double center_hyst_rud;            /* hysteresis loop center */
  double wide_hyst_elev;
  double center_hyst_elev;


  double S;                          /* fin area (m^2) */
  double CDc;                        /* crossflow Cd, fsh changed from 0.1 */
  double dCL;                        /* lift coefficient slope */

  double zMax;                       /* Bottom Depth */

  // In keeping with the custom established by whoever wrote this
  // simulator, we use an extra dimension in these arrays, so we
  // can index things starting at 1 (Gawd!)
  static double _position[7];
  static double _rate[7];

  double northCurrent, eastCurrent;

  double _simTime;
  double mTs;             //Control system sampling period, seconds.
  long   mTsMsec;  
  long   kk;              //Control system sample period counter

  // False until we get LayeredControlIF::MissionStarted event
  Boolean _missionStarted;


};

#endif

