#ifndef Var1_TringuCam_H
#define Var1_TringuCam_H
#include <Glasses/ZNode.h>
#include <Glasses/Tringula.h>
#include <Stones/TimeMakerClient.h>
#include <Gled/GTime.h>
#include <RnrBase/A_Rnr.h>
#include <Opcode/Opcode.h>
class WSTube;
class ScreenText;
class WGlWidget;
class TringuRep;
class TSPupilInfo;
class Eventor;
class TimeMaker;
class TringuCam : public ZNode,
		  public TimeMakerClient
{
  MAC_RNR_FRIENDS(TringuCam);
protected:
  
  
  
  Bool_t        bKeysVerbose;  
  Bool_t        bMouseVerbose; 
  
  
  
public:
  struct ValueInfo;
  struct KeyInfo
  {
    ValueInfo* fValueInfo;
    Bool_t     fIsInc;
    Bool_t  fIsDown;
    Float_t fDesiredValue; 
    Float_t fDecayTimeout;
    KeyInfo(ValueInfo* val_info, Bool_t is_inc) :
      fValueInfo(val_info), fIsInc(is_inc),
      fIsDown(false), fDesiredValue(0), fDecayTimeout(0) {}
  };
  struct KeyValueChangeParams
  {
    Float_t fValueAccel;
    Float_t fValueAccelDeltaFactor;
    Float_t fValueDecay;
    Float_t fValueDecayDeltaFactor;
    Float_t fValueDecayTimeout;
    Float_t fDesireIncStep;
    Float_t fDesireIncDeltaFactor; 
    Float_t fDesireDecay;
    Float_t fDesireDecayDeltaFactor;
    Float_t fDesireDecayTimeout;
    void SetValueParams(Float_t acc,   Float_t acc_df,
                        Float_t decay, Float_t decay_df,
                        Float_t decay_to)
    {
      fValueAccel = acc;   fValueAccelDeltaFactor = acc_df;
      fValueDecay = decay; fValueDecayDeltaFactor = decay_df;
      fValueDecayTimeout = decay_to;
    }
    void SetDesireParams(Float_t inc_step, Float_t inc_df,
                         Float_t decay,    Float_t decay_df,
                         Float_t decay_to)
    {
      fDesireIncStep = inc_step; fDesireIncDeltaFactor   = inc_df;
      fDesireDecay   = decay;    fDesireDecayDeltaFactor = decay_df;
      fDesireDecayTimeout = decay_to;
    }
  };
  struct ValueInfo
  {
    KeyValueChangeParams* fChangeParams;
    Float_t fValue;
    Float_t fMinValue, fMaxValue;
    Float_t fDecayTimeout;
    KeyInfo fIncKey;
    KeyInfo fDecKey;
    Bool_t  fSustain;
    Bool_t  fSustainSet;
    Float_t fSustainDesire;
    ValueInfo(KeyValueChangeParams* chg_prm=0) :
      fChangeParams(chg_prm),
      fValue(0), fDecayTimeout(0),
      fIncKey(this, true), fDecKey(this, false),
      fSustain(false), fSustainDesire(0)
    {}
    void SetMinMax(Float_t min, Float_t max) { fMinValue = min; fMaxValue = max; }
    void IncValue(Float_t& value, Float_t desire, Float_t step, Float_t delta_fac);
    void DecValue(Float_t& value, Float_t desire, Float_t step, Float_t delta_fac);
    void DecayValue(Float_t& value, Float_t decay, Float_t delta_fac=0);
    void DecayTimeoutOrValue(Float_t& timeout, Float_t& value, Float_t dt,
                             Float_t decay, Float_t delta_fac);
    void ApproachValue(Float_t& value, Float_t desire,
		       Float_t inc_step, Float_t inc_delta_fac,
		       Float_t dec_step, Float_t dec_delta_fac);
    void TimeTick(Float_t dt);
  };
private:
  void _init();
protected:
  KeyValueChangeParams mChgParCameraMove;
  KeyValueChangeParams mChgParCameraRotate;
  ValueInfo mFwdBck;
  ValueInfo mLftRgt;
  ValueInfo mUpDown;
  ValueInfo mSpinUp; 
  map<Int_t, KeyInfo*> mKeyStateMap;
  ZLink<ScreenText>  mInfoTxt;   
  
  
  
public:
  
  enum MouseAction_e { MA_Nothing, MA_RayCollide, MA_AddField, MA_SprayField,
                       MA_AddSource,
                       MA_PickExtendios,
		       MA_NewLandMark
  };
  enum ExpectBeta_e { EB_Nothing, EB_ConnectStaticos };
protected:
  MouseAction_e mMouseAction;   
  MouseAction_e mPrevAction;    
  ExpectBeta_e  mExpectBeta;    
  Float_t       mRayLength;     
  Bool_t        bMouseDown;
  
  
  
  ZLink<Tringula>          mTringula;    
  ZLink<TringuRep>         mTringuRep;   
  ZLink<TSPupilInfo>       mPupilInfo;   
  ZLink<Eventor>           mEventor;     
  ZLink<TimeMaker>         mTimeMaker;   
  ZLink<ZGlass>            mPrepBeta;    
  Int_t     mStampInterval;     
  Int_t     mStampCount;        
  Double_t  mHeight;            
  ZPoint    mMouseRayPos;
  ZPoint    mMouseRayDir;
  Opcode::RayCollider    mRayColl;    
  Opcode::CollisionFaces mCollFaces;  
  Opcode::CollisionFace  mCollFace;   
  Opcode::Point          mCollPoint;  
  Int_t                  mCollVertex; 
  TString                mGradName;   
  WSTube* make_tube(Statico* stato0, Statico* stato1, const TString& grad_name);
public:
  TringuCam(const Text_t* n="TringuCam", const Text_t* t=0) :
    ZNode(n,t) { _init(); }
  KeyInfo* FindKeyInfo(Int_t key);
  Int_t KeyDown(Int_t key);
  Int_t KeyUp(Int_t key);
  void MouseDown(A_Rnr::Fl_Event& ev);
  void MouseUp();
  void CalculateMouseRayVectors();
  void MouseRayCollide();
  void AddField(Float_t val);
  
  virtual void TimeTick(Double_t t, Double_t dt);
  
  void ExtendioDetails(Extendio* ext); 
  void ExtendioExplode(Extendio* ext); 
  void PrepConnectStatos(Statico* stato, Int_t id, const TString& grad); 
  void Suspend(); 
  void Resume();  
  void Help(); 
  
  void RandomStatico(); 
  void MakeLandMark();  
#include "TringuCam.h7"
  ClassDef(TringuCam, 1);
}; 
#endif