//
// A1526Control.h               
//
#ifndef A1526CONTROL_H
#define A1526CONTROL_H

//Update time of the values on this window (in milliseconds)
//#define UPDATE_TIME 250
#define UPDATE_TIME 3000
//Interval time for storing the values in files (in milliseconds)
#define WRITE_TIME 10000
//Interval when graphs are saved (in milliseconds)
#define SAVE_TIME 300000

//Write to file function on (true) or off (false)
#define WRITETOFILE true 
//Save graphs separately
#define SAVEGRAPHS true 

//data-format of the graphs
#define FORMAT "png"

//See channel characteristic table of the A1526 manual, p9
//The current characteristics can be changed by a dip switch
#define VSTEP 100
#define MINI 0
#define MAXI 100
#define ISTEP .1
#define IPRECISION 2 // 2 means .01 uA or 10 nA 

#define MAXNSLOT 8   // maximum number of slots available for A1526 in SY1527

// Reference pressure and temperature for computation of effective HV
#define P_REF 1010.
#define T_REF 293.

#include <MainWindow.h>
#include <A1526Timer.h>
#include <enviro.h>
#include <TQtWidget.h>
#include <TGraph.h>
#include <TGraphErrors.h>
#include <TMultiGraph.h>
#include <TH1F.h>
#include <TAxis.h>
#include <TCanvas.h>
#include <TLegend.h>
#include <TFile.h>
#include <TError.h>
#include <TGFrame.h>
#include <TRootEmbeddedCanvas.h>
#include <RQ_OBJECT.h>
#include <QtGui>
#include <stdio.h>

using namespace std;

class MainWindow;
class QVvalSpinBox;
class QIsetSpinBox;
class OnOffButton;
class RPCcodeEdit;
class A1526TimerWindow;
class A1526Control;
class enviro;
class GraphPushButton;
class CanvasWindow;

const QString stylesheets[] = { "color:black; background-color:lightGray",
				"color:black; background-color:white",
				"color:black; background-color:green",
				"color:black; background-color:yellow",
				"color:white; background-color:darkGray",
				"color:white; background-color:darkRed",
				"color:white; background-color:red",
				"color:white; background-color:black" };

/***********************************
 * Extended class of the QLineEdit *
 ***********************************/
class RPCcodeEdit : public QLineEdit
{
    Q_OBJECT

public:
    RPCcodeEdit(A1526Control* parent = 0, const QString contents = "", 
		int j_=0, int i_=0) 
      {
        myA1526Control = parent;
        j = j_, i = i_;
	connect(this, SIGNAL(returnPressed()), this, SLOT(emitSignal()));
	this->setText(contents);
	emitSignal();
      }

public slots:
    void emitSignal(){ emit RPCcodeChanged(j, i);}

signals:
    void RPCcodeChanged(int j_, int i_);

private:
    A1526Control* myA1526Control;
    int j, i;
};

class VvalCheckBox : public QCheckBox
{
  Q_OBJECT

public:
  VvalCheckBox() {
    this->setText("Set Veff");
    this->setChecked(false);
    checked = false;
    connect( this, SIGNAL(stateChanged(int)), 
	     this, SLOT(updateVvalmode()));
  }
  bool isChecked() { return checked; }

public slots:
  void updateVvalmode() {
    if ( this->isChecked() ) 
      checked = true;
    else
      checked = false;
  }     
  
private:
  bool checked;
};

/**********************
 * A1526Control class *
 **********************/
class A1526Control : public QWidget
{
    Q_OBJECT
	    
public slots:
  void updateStatus_( unsigned short, unsigned short, 
		      const QString, unsigned short );
  void changeVval(unsigned short, unsigned short, float);
  void changeVset(unsigned short, unsigned short, float);
  void changeIset(unsigned short, unsigned short, float);
  void changeOnOff(unsigned short, unsigned short);
  void changeVvalmode( unsigned short, unsigned short, bool );
  void updateWindow();
  void write();
  void save();
  void save_();
  void saveij_(int, int);
  void setNewRPCcode(int i, int j) { 
    RPCcodeString[i][j] = RPCcode[i][j]->text();
    RPCcode[i][j]->setReadOnly(false);
    RPCcode[i][j]->setStyleSheet( "color:black; background-color:white" );
  }
  void cleanGraphs(int, int);
  void cleanGraphs_(int, int);
  void resetGraphs(unsigned short, unsigned short);
  void showGraphs(int, int);
  void initGraphs(int, int);
  void globalstart();
  void globalstop();

signals:
  void graphsCleared( int, int );
  void consolewrite( const QString );
  void updateStatus( unsigned short, unsigned short, 
		     const QString, unsigned short );

public:
  A1526Control( MainWindow *parent = 0 );
  ~A1526Control();
  //  QTextEdit* getConsole(){ return myconsole; }
  //  QTextStream* getOConsole() { return oconsole;  }
  QString getRPCCodeString(unsigned short slot, unsigned short channel) { 
    return RPCcodeString[getSlotIndex(slot)][channel];
  } 
  enviro* getEnviro() { return myenviro; }
  bool getStatus(unsigned short, unsigned short);
  int getStatusval( unsigned short slot, unsigned short channel) { 
    return Statusval[getSlotIndex(slot)][channel]; 
  }
  void setReadOnly(unsigned short, unsigned short, bool);
  TGraph* getImonGraph(int i, int j) { return ImonGraphs[i][j];}
  TGraph* getImonGraph2(int i, int j) { return ImonGraphs2[i][j];}
  TGraph* getVsetGraph(int i, int j) { return VsetGraphs[i][j];}
  TGraph* getVmonGraph(int i, int j) { return VmonGraphs[i][j];}
  TGraph* getVeffGraph(int i, int j) { return VeffGraphs[i][j];}
  TMultiGraph* getVGraph(int i, int j) { return VGraphs[i][j];}
  bool getReplaceGraph(int i, int j) { return replaceGraph[i][j];}
  void setReplaceGraph(int i, int j, bool replace) { 
    replaceGraph[i][j] = replace;
  }
  void setEnableGraph(unsigned short slot, unsigned short channel, 
		      bool onoff) { 
    enableGraph[getSlotIndex(slot)][channel] = onoff;
  }
  QString getGraphFilenameTag( unsigned short slot, unsigned short channel ) {
    return GraphFilenameTag[getSlotIndex(slot)][channel];
  }
  void setGraphFilenameTag(unsigned short slot, unsigned short channel, 
			   char nametag[20]) {
    GraphFilenameTag[getSlotIndex(slot)][channel] = nametag;
  }
  char* getTimeString(){ return timestring;}
  bool notFinished(){ return saving;} 
  unsigned int getSlotIndex( unsigned int);
  void setEnableImonGraphs2( unsigned short slot, unsigned short channel, 
			     bool enable) {
    enableImonGraphs2[getSlotIndex(slot)][channel] = enable;
  }
  float getImonMean( unsigned short, unsigned short );
  float getImonRMS( unsigned short, unsigned short );
  float getImonMin( unsigned short, unsigned short );
  float getImonMax( unsigned short, unsigned short );
  int getVeff( int );
  int getVset( int );
  float getParameter(unsigned short, unsigned short, const char*);
  void setParameter(unsigned short, unsigned short, const char*, float);
  void setVmax(int);
  void setRup(int);
  void setRdown(int);
  QStringList getMeasurements() { return measurements; }

private:
  void print(const char*, ...);
  void printc(const char*, ...);
  void testBdPresence(unsigned short slot = 0);

private:
  QStringList measurements;
  enviro* myenviro;
  const char* name;
  unsigned short nslots, slot[MAXNSLOT], NrOfCh;
  QVvalSpinBox* Vval[MAXNSLOT][6];
  QCheckBox* Vvalmode[MAXNSLOT][6];
  QLineEdit* Vset[MAXNSLOT][6];
  QLineEdit* Vmon[MAXNSLOT][6];
  QLineEdit* Veff[MAXNSLOT][6];
  QIsetSpinBox* Iset[MAXNSLOT][6];
  QLineEdit* Imon[MAXNSLOT][6];
  RPCcodeEdit* RPCcode[MAXNSLOT][6];
  QString RPCcodeString[MAXNSLOT][6];
  OnOffButton* OnOff[MAXNSLOT][6];
  GraphPushButton* Graph[MAXNSLOT][6];
  QLineEdit* Status[MAXNSLOT][6];
  int Statusval[MAXNSLOT][6];
  QTimer* updateTimer;
  QTimer* writeTimer;
  QTimer* saveTimer;
  time_t startTime, now;
  TDatime *startTimeDa;
  A1526TimerWindow* A1526Timer[MAXNSLOT][6];
  QPushButton* StartStopTimer[MAXNSLOT][6];
  QPushButton* GlobalStartTimer;
  QPushButton* GlobalStopTimer;
  QString GraphFilenameTag[MAXNSLOT][6];
  CanvasWindow* myCanvasWindow;
  TCanvas* Canvas;
  TGraph *PenvGraph[MAXNSLOT][6], *TenvGraph[MAXNSLOT][6], 
    *HenvGraph[MAXNSLOT][6], *TgasGraph[MAXNSLOT][6], 
    *HgasGraph[MAXNSLOT][6];
  TGraph* ImonGraphs[MAXNSLOT][6];
  TGraph* ImonGraphs2[MAXNSLOT][6];    // separate Imon for each V setting
  bool enableImonGraphs2[MAXNSLOT][6]; // enable such Imon measurement
  TGraph* VmonGraphs[MAXNSLOT][6];
  TGraph* VsetGraphs[MAXNSLOT][6];
  TGraph* VeffGraphs[MAXNSLOT][6];
  TMultiGraph *VGraphs[MAXNSLOT][6], *TGraphs[MAXNSLOT][6], 
    *HGraphs[MAXNSLOT][6];
  TGraphErrors* IvsVGraphs[MAXNSLOT][6];
  TQtWidget* GraphWindow[MAXNSLOT][6];
  char timebuff[20];
  char* timestring;
  bool replaceGraph[MAXNSLOT][6];
  bool enableGraph[MAXNSLOT][6];
  int vsetval[MAXNSLOT][6];
  int veffval[MAXNSLOT][6];
  QMutex mutex, mutex2, mutex3, mutex4;	
  bool saving;

};

/**********************************
 * Extended class of the QSpinBox *
 **********************************/
class QVvalSpinBox : public QSpinBox
{
    Q_OBJECT

public:
    QVvalSpinBox(A1526Control* parent = 0, unsigned short j=0, unsigned short i=0){
	myA1526Control = parent;
	slot = j; channel = i;
	changing = false;

	this->setSingleStep(VSTEP);
	this->setSuffix(" V");

	connect( this, SIGNAL(valueChanged(int)), this, SLOT(wait()));
	connect( this, SIGNAL(editingFinished()), this, SLOT(change()));
    }
    bool isChanging(){ return changing;}

public slots:
    void wait(){ changing = true;}
    void change() { 
      myA1526Control->changeVval(slot, channel, (unsigned long) value());
      changing = false;
    }

private:
    bool changing;
    A1526Control* myA1526Control;
    unsigned short slot, channel;
};


/****************************************
 * Extended class of the QDoubleSpinBox *
 ****************************************/
class QIsetSpinBox : public QDoubleSpinBox
{
    Q_OBJECT

public:
    QIsetSpinBox(A1526Control* parent = 0, unsigned short j=0, unsigned short i=0){
	myA1526Control = parent;
	slot = j; channel = i;
	changing = false;

	this->setRange(MINI, MAXI);
	this->setDecimals(IPRECISION);
	this->setSingleStep(ISTEP);
	this->setSuffix(QString::fromUtf8(" \u03BCA"));

	connect( this, SIGNAL(valueChanged(double)) , this, SLOT(wait()));
	connect( this, SIGNAL(editingFinished()), this, SLOT(change()));
    }
    bool isChanging(){ return changing;}

public slots:
    void wait(){ changing = true; }
    void change(){
      myA1526Control->changeIset(slot, channel, (float) value());
	changing = false;	
    }

private:
    bool changing;
    A1526Control* myA1526Control;
    unsigned short slot, channel;
};

/*************************************
 * Extended class of the QPushButton *
 *************************************/
class OnOffButton : public QPushButton
{
    Q_OBJECT

public:
    OnOffButton( A1526Control* parent = 0, const QString text = "",  
		 unsigned short j=0, unsigned short i=0 ) {
	this->setText(text);
        myA1526Control = parent;
        slot = j, channel = i;
	readonly = false;

	connect(this, SIGNAL(clicked()), this, SLOT(change()));
    }
    void setReadOnly(bool readonly_){ 
	readonly = readonly_;
	this->setFlat(readonly);
	this->setText("");
    }
    bool ReadOnly(){ return readonly; }

public slots:
    void change(){ 
      if (!readonly) myA1526Control->changeOnOff(slot, channel); 
    }

private:
    A1526Control* myA1526Control;
    unsigned short slot, channel;
    bool readonly;
};

class GraphPushButton : public QPushButton
{
  Q_OBJECT

public:
  GraphPushButton( A1526Control *parent = 0,
		   unsigned int slot = 0, unsigned int channel = 0) {
    myA1526Control = parent;
    j = myA1526Control->getSlotIndex(slot);
    i = channel;
    //connect( this, SIGNAL(clicked()), this, SLOT(showGraph()));  
    this->setText("Graph");
  }

public slots:
  void showGraph() { myA1526Control->showGraphs(j, i); } 

private:
  A1526Control* myA1526Control;
  unsigned int j;
  unsigned int i;
};

class CanvasWindow {
   RQ_OBJECT("HVtest Graphs")

private:
   TGMainFrame *fMain;

public:
   TRootEmbeddedCanvas *fEcanvas;

public:
   CanvasWindow(const TGWindow *p,UInt_t w,UInt_t h) {
     // Create a main frame
     fMain = new TGMainFrame(p,w,h);

     // Create canvas widget
     fEcanvas = new TRootEmbeddedCanvas("Ecanvas",fMain,200,200);
     fMain->AddFrame( fEcanvas, new TGLayoutHints( kLHintsExpandX | 
						   kLHintsExpandY,
						   10,10,10,1) );
     // Initialize the layout algorithm
     fMain->Resize(fMain->GetDefaultSize());
     // Map main frame
     fMain->MapWindow();
   }
   virtual ~CanvasWindow() {
     // Clean up used widgets: frames, buttons, layout hints
     fMain->Cleanup();
     delete fMain;
   }
   TCanvas* getCanvas() { return fEcanvas->GetCanvas(); }
};


#endif


