/*
* Title:	ControlDataWin.cpp 
* Author:	M.Thomas BEAM Ltd
* Date:		2007-02-13
*
* Contents:	Control of data requests. Test code. 
*
* Mod Rec:
*
*/


#include <BFile.h>
#include <ControlDataWin.h>
#include <TmsD.h>
#include <qvalidator.h>
#include <qmessagebox.h>
#include <qhbox.h>
#include <qlayout.h>
#include <qvbox.h>
#include <Debug.h>
#include <BGraph.h>
#include <BGraphControls.h>
#include <math.h>
#include <Globals.h>
#include <qfiledialog.h>


using namespace Tms;
using namespace std;

static ComboDefinition cycleDef[] = {
	{ 0,	"CyclePeriodAll",		CyclePeriodAll,	0 },
	{ 1,	"CyclePeriodCalibration",	CyclePeriodCalibration,	0 },
 	{ 2,	"CyclePeriodEvent0",		CyclePeriodEvent0,	1 },
	{ 3,	"CyclePeriodEvent1",		CyclePeriodEvent1,	0 },
	{ 4,	"CyclePeriodEvent2",		CyclePeriodEvent2,	0 },
	{ 5,	"CyclePeriodEvent3",		CyclePeriodEvent3,	0 },
	{ 6,	"CyclePeriodEvent4",		CyclePeriodEvent4,	0 },
	{ 7,	"CyclePeriodEvent5",		CyclePeriodEvent5,	0 },
	{ 8,	"CyclePeriodEvent6",		CyclePeriodEvent6,	0 },
	{ 9,	"CyclePeriodEvent7",		CyclePeriodEvent7,	0 },
	{ 10,	"CyclePeriodEvent8",		CyclePeriodEvent8,	0 },
	{ 11,	"CyclePeriodEvent9",		CyclePeriodEvent9,	0 },
	{ 0,0,0,0 }
};

static ComboDefinition functionDef[] = {
	{ 0,	"DataFunctionRaw",		DataFunctionRaw,	1 },
	{ 1,	"DataFunctionMean",		DataFunctionMean,	0 },
	{ 2,	"DataFunctionMeanAll",		DataFunctionMeanAll,	0 },
	{ 3,	"DataFunctionMean0",		DataFunctionMean0,	0 },
 	{ 4,	"DataFunctionMean1",		DataFunctionMean1,	0 },
	{ 0,0,0,0 }
};

static ComboDefinition bunchDef[] = {
	{ 0,	"All Bunches",	0,	1 },
	{ 1,	"Bunch 1",	1,	0 },
 	{ 2,	"Bunch 2",	2,	0 },
 	{ 3,	"Bunch 3",	3,	0 },
	{ 4,	"Bunch 4",	4,	0 },
 	{ 5,	"Bunch 5",	5,	0 },
 	{ 6,	"Bunch 6",	6,	0 },
 	{ 7,	"Bunch 7",	7,	0 },
 	{ 8,	"Bunch 8",	8,	0 },
 	{ 9,	"Bunch 9",	9,	0 },
 	{ 10,	"Bunch 10",	10,	0 },
 	{ 11,	"Bunch 11",	11,	0 },
 	{ 12,	"Bunch 12",	12,	0 },
 	{ 13,	"Bunch 13",	13,	0 },
 	{ 14,	"Bunch 14",	14,	0 },
 	{ 15,	"Bunch 15",	15,	0 },
 	{ 16,	"Bunch 16",	16,	0 },
 	{ 17,	"Bunch 17",	17,	0 },
 	{ 18,	"Bunch 18",	18,	0 },
 	{ 19,	"Bunch 19",	19,	0 },
 	{ 20,	"Bunch 20",	20,	0 },
 	{ 21,	"Bunch 21",	21,	0 },
 	{ 22,	"Bunch 22",	22,	0 },
 	{ 23,	"Bunch 23",	23,	0 },
 	{ 24,	"Bunch 24",	24,	0 },
 	{ 25,	"Bunch 25",	25,	0 },
 	{ 26,	"Bunch 26",	26,	0 },
 	{ 27,	"Bunch 27",	27,	0 },
 	{ 28,	"Bunch 28",	28,	0 },
 	{ 29,	"Bunch 29",	29,	0 },
 	{ 30,	"Bunch 30",	30,	0 },
 	{ 31,	"Bunch 31",	31,	0 },
	{ 0,0,0,0 }
};


ControlDataWin::ControlDataWin(QWidget* w,Control& c) : ocontrol(c)  {
	int		row = 0;
	int		col = 0;
	int		width = 170;

	QVBox* 		mv = new QVBox(this);
			oplotSigma = new BGraph(mv);
			oplotDeltaX = new BGraph(mv);
			oplotDeltaY = new BGraph(mv);

	ographControls = new BGraphControlBasic(mv);

	QWidget*	t = new QWidget(mv);
	QGridLayout* 	v = new QGridLayout(t);
	
	ographControls->addGraph(oplotSigma);
	ographControls->addGraph(oplotDeltaX);
	ographControls->addGraph(oplotDeltaY);

	oticker = new QTimer(this);
	QValidator* validator = new QIntValidator(0, (int)pow(2,31), this );


	
	ocurrentCycle = new QLabel("",t);
	ocurrentCycle->setFixedWidth(width);
	

	ocyclePeriod		= new BQComboBox(cycleDef,t,"");
	ofunction		= new BQComboBox(functionDef,t,"");
	obunchNumber		= new BQComboBox(bunchDef,t,"");

	ocycleNumber		= new QLineEdit(t,"");ocycleNumber->setValidator(validator);
	oautoCycleNumber	= new QCheckBox(t,"");
	
	ostartTime		= new QLineEdit(t,"");ostartTime->setValidator( validator );
	oorbitNumber		= new QLineEdit(t,"");oorbitNumber->setValidator( validator );
	oargument		= new QLineEdit(t,"");oargument->setValidator( validator );
	obeyondPeriod	= new QCheckBox(t,"");
	onumValues		= new QLineEdit(t,"");onumValues->setValidator( validator );
	oallChannels		= new QCheckBox(t,"");
	ochannel		= new QSpinBox(1,60,1,t,"");
	
	ochannel->setWrapping(true);
	onumValues->setText("2048");
	oautoCycleNumber->setChecked(true);
	obeyondPeriod->setChecked(false);

	ostartTime->setText("0");
	oorbitNumber->setText("0");
	oargument->setText("0");

	oautoCycleNumber->setMaximumWidth(width);
	ocycleNumber->setMaximumWidth(width);
	oallChannels->setMaximumWidth(width);
	ochannel->setMaximumWidth(width);
	ocyclePeriod->setMaximumWidth(width);
	ostartTime->setMaximumWidth(width);
	oorbitNumber->setMaximumWidth(width);

	oargument->setMaximumWidth(width);
	obeyondPeriod->setMaximumWidth(width);
	onumValues->setMaximumWidth(width);
	obunchNumber->setMaximumWidth(width);
	ofunction->setMaximumWidth(width);


	col = 0;row = 0;
	v->addWidget(new QLabel("Auto Cycle Num",t,""),row,col);	v->addWidget(oautoCycleNumber,row,col+1);row++;
	v->addWidget(new QLabel("Cycle Number",t,""),row,col);		v->addMultiCellWidget(ocycleNumber,row,row,col+1,col+2);	row++;
	
	v->addWidget(new QLabel("All Channels",t,""),row,col);  	v->addMultiCellWidget(oallChannels,row,row,col+1,col+2);	row++;
	v->addWidget(new QLabel("Channel",t,""),row,col);      		v->addMultiCellWidget(ochannel,row,row,col+1,col+2);	row++;
	v->addWidget(new QLabel("Cycle Period",t,""),row,col);      	v->addMultiCellWidget(ocyclePeriod,row,row,col+1,col+2);	row++;
	v->addWidget(new QLabel("Start Time",t,""),row,col);      	v->addMultiCellWidget(ostartTime,row,row,col+1,col+2);	row++;

	col = 3;row = 0;	
	v->addWidget(new QLabel("Orbit Number",t,""),row,col);      	v->addMultiCellWidget(oorbitNumber,row,row,col+1,col+2);row++;
	v->addWidget(new QLabel("Data Beyond Period",t,""),row,col);      	v->addWidget(obeyondPeriod,row,col+1);	row++;
	v->addWidget(new QLabel("Num Values",t,""),row,col);      	v->addWidget(onumValues,row,col+1);	row++;
	v->addWidget(new QLabel("Bunch Number",t,""),row,col);      	v->addWidget(obunchNumber,row,col+1);	row++;
	v->addWidget(new QLabel("Function",t,""),row,col);      	v->addWidget(ofunction,row,col+1);	row++;
	v->addWidget(new QLabel("Argument",t,""),row,col);      	v->addWidget(oargument,row,col+1);	row++;

	col = 5;row = 0;	
	v->addWidget(new QLabel("Current Cycle",t,""),row,col);		v->addWidget(ocurrentCycle,row,col+1);

	v->setSpacing(5);


	QHBox*		h = new QHBox(mv);
	
	QPushButton*	refreshData = new QPushButton("Fetch Data",h,"refresh");
	QPushButton*	saveFile = new QPushButton("Save To File",h,"save");

	h->setMargin(4);
	refreshData->setMaximumWidth(200);
	saveFile->setMaximumWidth(200);

	oplotSigma->setMinimumHeight(180);
	oplotDeltaX->setMinimumHeight(180);
	oplotDeltaY->setMinimumHeight(200);

	oplotSigma->installEventFilter(this);
	oplotDeltaX->installEventFilter(this);
	oplotDeltaY->installEventFilter(this);
	oplotDeltaY->setXLabel("Sample");
	
	connect(refreshData,SIGNAL(clicked()),this,SLOT(refresh()));
	connect(saveFile,SIGNAL(clicked()),this,SLOT(saveFile()));

        connect(oautoCycleNumber, SIGNAL(stateChanged(int)), this, SLOT(updateAutoCycle()));
        connect(oallChannels, SIGNAL(stateChanged(int)), this, SLOT(updateAllChannels()));
        connect(oticker, SIGNAL(timeout()), this, SLOT(updateStatus()));

}
	
ControlDataWin::~ControlDataWin() {}

void ControlDataWin::show() {
	updateAutoCycle();
	updateAllChannels();
	QWidget::show();
	oticker->start( 1000, FALSE ); 	
}
	
void ControlDataWin::hide() {
	oticker->stop();
	QWidget::hide();
}

void ControlDataWin::refresh() {
	BError		err;
	QString		s;
	UInt32 		cycleNumber;
	BString		cycleType;
	UInt32		c;
	Tms::ConfigInfo	info;

	if (oautoCycleNumber->isChecked()) {
		BString	s;
		if(err = ocontrol.getCycleInfo(cycleNumber,cycleType)){
			warningDialog("Reading Data", err);
			return;
		}
		odataInfo.cycleNumber	= cycleNumber;
		s.printf("%d",odataInfo.cycleNumber);
		ocycleNumber->setText(s.retStr());
	}
	else {
		odataInfo.cycleNumber	= ocycleNumber->text().toUInt();
	}	
	
	if (odataInfo.numValues != onumValues->text().toUInt()) {
		oplotSigma->setXRange(0,0);
		oplotDeltaX->setXRange(0,0);
		oplotDeltaY->setXRange(0,0);
	}

	if(oallChannels->isChecked()){
		BUInt32	s;
		BUInt32	n;
		Data	data;
		
		// Collect data
		odataInfo.channel = 0;
		odataInfo.startTime = ostartTime->text().toUInt();
		odataInfo.orbitNumber = oorbitNumber->text().toUInt();
		odataInfo.argument = oargument->text().toUInt();
		odataInfo.numValues = onumValues->text().toUInt();
		odataInfo.beyondPeriod = obeyondPeriod->isChecked();
		odataInfo.bunchNumber = (int)obunchNumber->getValue();
		odataInfo.cyclePeriod = (int)ocyclePeriod->getValue();
		odataInfo.function = (int)ofunction->getValue();

		if(err = ocontrol.getData(odataInfo, data)){
			warningDialog("Reading Data",err);
			return;
		}

//		printf("Got: NumValues: %d NumBunches: %d NumChannels: %d\n", data.numValues, data.numBunches, data.numChannels);

		if(data.numBunches == 0){
			data.numBunches = 1;
		}
		
		if(data.numChannels == 0){
			warningDialog("Error number of channels was 0", err);
			return;
		}
		
		// Merge data into bunch, then channel, then sample form 
		odata = data;

		memset(odata.dataValues.data(), 0, odata.dataValues.size() * sizeof(DataValue));
		n = data.numValues / (data.numBunches * data.numChannels);
		for(s = 0; s < n; s++){
			for(c = 0; c < data.numChannels; c++){
				memcpy(&odata.dataValues[s * data.numBunches * data.numChannels + c * data.numBunches], &data.dataValues[s * odata.numBunches + c * data.numBunches * n], data.numBunches * sizeof(DataValue));
			}
		}
	}
	else {
		odataInfo.channel = ochannel->text().toUInt();
		odataInfo.startTime = ostartTime->text().toUInt();
		odataInfo.orbitNumber = oorbitNumber->text().toUInt();
		odataInfo.argument = oargument->text().toUInt();
		odataInfo.numValues = onumValues->text().toUInt();
		odataInfo.beyondPeriod = obeyondPeriod->isChecked();
		odataInfo.bunchNumber = (int)obunchNumber->getValue();
		odataInfo.cyclePeriod = (int)ocyclePeriod->getValue();
		odataInfo.function = (int)ofunction->getValue();

		if (gdebug & DBG_STD)
			printDataInfo();

		if (err = ocontrol.getData(odataInfo,odata)) {
			warningDialog("Reading Data",err);
			return;
		}
	}

	setPlotData();
	plot();	
}	


void	ControlDataWin::setPlotData() {
	unsigned int	n = 0;

	osigma.resize(odata.numValues);
	odeltaX.resize(odata.numValues);
	odeltaY.resize(odata.numValues);

	for (n = 0;n < odata.numValues;n++) {
		osigma[n] = odata.dataValues[n].sigma;
		odeltaX[n] = odata.dataValues[n].deltaX;
		odeltaY[n] = odata.dataValues[n].deltaY;
	}	
	oplotSigma->setData(osigma);
	oplotDeltaX->setData(odeltaX);
	oplotDeltaY->setData(odeltaY);
	
	oplotSigma->setYLabel("Sigma");
	oplotDeltaX->setYLabel("Delta X");
	oplotDeltaY->setYLabel("Delta Y");

	oplotSigma->setGrid(16,2);
	oplotDeltaX->setGrid(16,2);
	oplotDeltaY->setGrid(16,2);
	ographControls->setMax(odata.numValues);

}


void ControlDataWin::plot() {
}	

void	ControlDataWin::warningDialog(BString title, BError err){
	BString	m;
	
	m = BString("<h5>") + title + "</h5><p>" + err.getString() + "</p>";
	QMessageBox::warning(this, "Warning", m.retStr());
}


void	ControlDataWin::saveFile() {
	unsigned int		n;
	
	BFile	f;
	BString	fname = "data.txt";

	QFileDialog saveDialog(
        	            ".",
                	    "Pupe Data Dump File (*.txt)",
                	    this,
                	    "save file dialog",
                	    "Choose a file" );
	saveDialog.setMode(QFileDialog::QFileDialog::AnyFile);
	saveDialog.setSelection(fname.retStr());
		
	switch (n = saveDialog.exec()) {
	case 0:		return;		//Cancel Button
			break;	
	case 1:		break;		//Save Button
		default:	printf("Unknown Button (%d)\n",n);
	}
	if ((fname = saveDialog.selectedFile().ascii()) == "")
		return;
	if (f.open(fname,"w+")) {
		printf("Cannot open save file (%s)\n",fname.retStr());
		return;
	}
	f.printf("sigma deltaX deltaY\n");

	for (n = 0;n < odata.dataValues.size();n++) {
		f.printf("%d %d %d\n",
			odata.dataValues[n].sigma,
			odata.dataValues[n].deltaX,
			odata.dataValues[n].deltaY);
	}
	f.close();
	BString msg;
	msg =  BString("File Saved (") + fname + ")";
	gstatusbar->message(msg.retStr(),2000);
}


void ControlDataWin::updateAutoCycle() {
	if (oautoCycleNumber->isChecked())
		ocycleNumber->setEnabled(false);
	else
		ocycleNumber->setEnabled(true);
	updateStatus();	
}

void ControlDataWin::updateAllChannels() {
	if (oallChannels->isChecked())
		ochannel->setEnabled(false);
	else
		ochannel->setEnabled(true);
	updateStatus();	
}

void ControlDataWin::updateStatus() {
	BError		err;
	UInt32 		cycleNumber;
	BString		cycleType;
	BString		s;
	
	if(err = ocontrol.getCycleInfo(cycleNumber,cycleType))
			return;
	s.printf("%d %s",cycleNumber,cycleType.retStr());
	ocurrentCycle->setText(s.retStr());	
}

void ControlDataWin::printDataInfo() {
	printf("Channel Number\t(%d)\n",odataInfo.channel);
	printf("Cycle Number\t(%d)\n",odataInfo.cycleNumber);
	printf("Period\t\t(%d)\n",odataInfo.cyclePeriod);
	printf("Start Time\t(%d)\n",odataInfo.startTime);
	printf("Orbit Number\t(%d)\n",odataInfo.orbitNumber);
	printf("Bunch Number\t(%d)\n",odataInfo.bunchNumber);
	printf("Function\t(%d)\n",odataInfo.function);
	printf("Argument\t(%d)\n",odataInfo.argument);
	printf("Num Values\t(%d)\n",odataInfo.numValues);
}
bool ControlDataWin::eventFilter( QObject *o, QEvent *e )
    {
        if ( e->type() == QEvent::Wheel ) {
        	QWheelEvent*	we = (QWheelEvent*)e;
	    
	    	int	delta = (we->delta() > 0) ? -1 : 1;
		ographControls->scroll(delta);
            return TRUE; 
        } else {
            // standard event processing
            return FALSE;
        }
    }


