#include "CalcDlg.h"
#include <iostream>
	
// Public
CalcDlg::CalcDlg(QWidget * parent,Qt::WindowFlags f): QDialog(parent,f){
	/* Current =0 neede for init of combo boxes without calling
	 * calcChanged(). Else -> Segmentation False
	 */
	current=0;
	
	mPlot = (MultiPlot *)parent;
	topLayout = new QGridLayout;
	reqLayout = new QVBoxLayout;
		
	buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
	connect(buttonBox, SIGNAL(rejected()), this, SLOT(cancelClicked()));
	connect(buttonBox, SIGNAL(accepted()), this, SLOT(okClicked()));
	
	sourcePlot = new QComboBox(this);
	
	for (int i=0; i<mPlot->getPlots().size(); i++){
		if (!mPlot->getPlots().at(i)->isEmpty()){
			QVariant index(i);
			sourcePlot->addItem("Plot "+QString::number(i+1),index);
		}
	}
	connect(sourcePlot, SIGNAL( currentIndexChanged(int) ), this, SLOT( refreshCombos() ) );
	
	
	// Create All Widgets
	createSampQuantWidget();
	createAddMultiWidget();
	createErrorPane();
	createFftWidget();
	
	// Supported Calculations
	calculation = new QComboBox(this);
	
	calculation->addItem("Sampling/Quantization");
	calculation->addItem("Adding");
	calculation->addItem("Multipling");
	calculation->addItem("Convolution");
	calculation->addItem("Fourier Transform");

	connect(calculation, SIGNAL( currentIndexChanged(int) ), this, SLOT( calcChanged() ) );
	
	// Required Info Box
	QGroupBox * reqBox = new QGroupBox("Required Info");
	reqLayout->addWidget(SamplingQuant);
	reqBox->setLayout(reqLayout);
	
	refreshCombos();
	
	// Set Current
	current=SamplingQuant;
	
	// TOP
	topLayout->addWidget(new QLabel("Source Plot"),0,0);
	topLayout->addWidget(sourcePlot,0,1);
	topLayout->addWidget(new QLabel("Calculation"),1,0);
	topLayout->addWidget(calculation,1,1);
	
	topLayout->addWidget(reqBox,2,0,1,2);
	topLayout->addWidget(buttonBox,3,0,1,2);

	//
	setLayout(topLayout);
	mPlot->setEnabled(false);
	setEnabled(true);
}
CalcDlg::~CalcDlg(){}

// Private
void CalcDlg::createSampQuantWidget(){
	//--- Sampling/Quantization Panel ---
	QGridLayout * widLayout = new QGridLayout;
	
	SamplingQuant = new QWidget();

	samplingStep = new QLineEdit(this);
	samplingStep->setMaxLength (3);
	samplingStep->setAlignment(Qt::AlignRight);
	samplingStep->setValidator(new QIntValidator(2,999,samplingStep));
	
	samplingTarget = new QComboBox(this);
	connect( samplingTarget,  SIGNAL(currentIndexChanged(int)), this, SLOT(refresh2ndCombo()) );
	
	quantLevels= new QLineEdit(this);
	quantLevels->setMaxLength (4);
	quantLevels->setAlignment(Qt::AlignRight);
	quantLevels->setValidator(new QIntValidator(2,9999,quantLevels));
	
	quantTarget = new QComboBox(this);
	
	widLayout->addWidget(new QLabel("Sampling Step "),0,0);
	widLayout->addWidget(samplingStep,0,1);
	widLayout->addWidget(new QLabel("Sampling Target "),1,0);
	widLayout->addWidget(samplingTarget,1,1);
	widLayout->addWidget(new QLabel("Quantization Levels "),2,0);
	widLayout->addWidget(quantLevels,2,1);
	widLayout->addWidget(new QLabel("Quantization Target "),3,0);
	widLayout->addWidget(quantTarget,3,1);
	
	SamplingQuant->setLayout(widLayout);
}


void CalcDlg::createAddMultiWidget(){
	//--- Add Panel ---
	QGridLayout * widLayout = new QGridLayout;
	
	AddMulti = new QWidget();
	
	withLab=new QLabel("Add With ");
	
	with=new QComboBox(this);
	connect( with,  SIGNAL(currentIndexChanged(int)), this, SLOT(refresh2ndCombo()) );
	
	calcTarget = new QComboBox(this);
	
	widLayout->addWidget(withLab,0,0);
	widLayout->addWidget(with,0,1);
	widLayout->addWidget(new QLabel("Target Plot"),1,0);
	widLayout->addWidget(calcTarget,1,1);
	
	AddMulti->setLayout(widLayout);
	
}
void CalcDlg::createFftWidget(){
	//-- FFT Panel ---
	QGridLayout * widLayout = new QGridLayout;
	
	Fft = new QWidget();
	
	realTarget=new QComboBox(this);
	connect( realTarget,  SIGNAL(currentIndexChanged(int)), this, SLOT(refresh2ndCombo()) );
	
	imagTarget=new QComboBox(this);
	connect( imagTarget,  SIGNAL(currentIndexChanged(int)), this, SLOT(refresh3dCombo()) );
	
	powerTarget=new QComboBox(this);
	
	widLayout->addWidget(new QLabel("Real Data Target"),0,0);
	widLayout->addWidget(realTarget,0,1);
	widLayout->addWidget(new QLabel("Imaginary Data Target"),1,0);
	widLayout->addWidget(imagTarget,1,1);
	widLayout->addWidget(new QLabel("Power Data Target"),2,0);
	widLayout->addWidget(powerTarget,2,1);
	
	Fft->setLayout(widLayout);
}

void CalcDlg::createErrorPane(){
	errorPane = new QWidget();
	
	QVBoxLayout * widLayout = new QVBoxLayout;
	widLayout->addWidget(new QLabel("Not Enought Signals or Plots\n for this calculation. Sorry..."));
	
	errorPane->setLayout(widLayout);
}


// SLOTS
void CalcDlg::okClicked(){

	// Source always needed
	int selSource=sourcePlot->itemData(sourcePlot->currentIndex()).toInt();
	
	//Check Calculation
	QString calcText=calculation->currentText();
	
	if (calcText=="Sampling/Quantization") {
		/*
		 * If non of the step or levels are entered -> ERROR
		 * If there is only step -> only Sampling
		 * If there is only levels -> only Quantization
		 */
		if (samplingStep->text()=="" && quantLevels->text()=="") {
			QMessageBox::critical(this,"ERROR","You must enter at least one of the fileds.");
			return;
		}

		

		int newAnimSpeed=mPlot->getPlots().at(selSource)->getAnimSleepTime();
		
		if (samplingStep->text()!=""){
			
			if (samplingStep->text().toDouble()==0) {
				QMessageBox::critical(this,"ERROR","Sampling Step Cant be zero (0).");
				return;
			}

			
			Signal sig=mPlot->getPlots().at(selSource)->getSignal().getSampledBy(samplingStep->text().toInt());
			int target=samplingTarget->itemData(samplingTarget->currentIndex()).toInt();
			
			//Settings for Plot
			newAnimSpeed*=samplingStep->text().toInt();
			int newDist=mPlot->getPlots().at(selSource)->getSamplesDist()*samplingStep->text().toInt();
			mPlot->getPlots().at(target)->setSamplesDist(newDist);
			mPlot->getPlots().at(target)->setAnimSleepTime(newAnimSpeed);
			mPlot->getPlots().at(target)->setDrawAnalog(false);

			mPlot->getPlots().at(target)->setSignal(sig);
		}
		
		// Quant Source (not else...!!!)
		if (quantLevels->text()!="" && samplingStep->text()==""){
			
			if (quantLevels->text().toDouble()<2) {
				QMessageBox::critical(this,"ERROR","Quantization levels MUST be more than 1");
				return;
			}
			
			
			Signal sig=mPlot->getPlots().at(selSource)->getSignal().getQuantedWith(quantLevels->text().toInt());
			int target=quantTarget->itemData(quantTarget->currentIndex()).toInt();
			mPlot->getPlots().at(target)->setDrawAnalog(false);
			mPlot->getPlots().at(target)->setSignal(sig);
		}
		// Quant Samplig Result
		else if (quantLevels->text()!="" && samplingStep->text()!=""){

			if (quantLevels->text().toDouble()<2) {
				QMessageBox::critical(this,"ERROR","Quantization levels MUST be more than 1");
				return;
			}
			

			int sampRes=samplingTarget->itemData(samplingTarget->currentIndex()).toInt();
			Signal sig=mPlot->getPlots().at(sampRes)->getSignal().getQuantedWith(quantLevels->text().toInt());
			int target=quantTarget->itemData(quantTarget->currentIndex()).toInt();
			// Before Set Signal
			mPlot->getPlots().at(target)->setAnimSleepTime(newAnimSpeed);
			int newDist=mPlot->getPlots().at(selSource)->getSamplesDist()*samplingStep->text().toInt();
			mPlot->getPlots().at(target)->setSamplesDist(newDist);
			mPlot->getPlots().at(target)->setDrawAnalog(false);
			mPlot->getPlots().at(target)->setShowGrid(false);
			mPlot->getPlots().at(target)->setShowLines(true);
			
			// Set Signal Redraws
			mPlot->getPlots().at(target)->setSignal(sig);
		}
		
	}
	else if (calcText=="Adding") {
		// Get result. OK cannot be pressed if everything is not ok...
		Signal result=mPlot->getPlots().at(selSource)->getSignal() + 
			mPlot->getPlots().at(with->itemData(with->currentIndex()).toInt())->getSignal();
		
		if (result.isEmpty()) {
			QMessageBox::critical(this,"Calculation ERROR",
							"To have meaning adding 2 Signals there must:\n - Both have the same step on x-values\n - Have a common area on x-axes.");
			return;
		}
		
		int target=calcTarget->itemData(calcTarget->currentIndex()).toInt();
		mPlot->getPlots().at(target)->setSignal(result);
	}
	else if (calcText=="Multipling") {
		// Get result. OK cannot be pressed if everything is not ok...
		Signal result=mPlot->getPlots().at(selSource)->getSignal() * 
			mPlot->getPlots().at(with->itemData(with->currentIndex()).toInt())->getSignal();
		
		if (result.isEmpty()) {
			QMessageBox::critical(this,"Calculation ERROR",
							"To have meaning multipling 2 Signals there must:\n - Both have the same step on x-values\n - Have a common area on x-axes.");
			return;
		}
		
		int target=calcTarget->itemData(calcTarget->currentIndex()).toInt();
		mPlot->getPlots().at(target)->setSignal(result);
	}else if (calcText=="Convolution"){
		Signal result=mPlot->getPlots().at(selSource)->getSignal().convolution (mPlot->getPlots().at(with->itemData(with->currentIndex()).toInt())->getSignal());

		if (result.isEmpty()) {
			QMessageBox::critical(this,"Calculation ERROR",
				"To have atsaxala axalala 2 Signals there must:\n - Both have the same step on x-values\n - Have a common area on x-axes.");
			return;
		}

		int target=calcTarget->itemData(calcTarget->currentIndex()).toInt();
		mPlot->getPlots().at(target)->setSignal(result);
	}
	else if (calcText=="Fourier Transform"){
		Signal real,imag,power;

		//setVisible(false);
		setModal(false);
	
		//Old impl -> mPlot->getPlots().at(selSource)->getSignal().fft(real,imag,power);
		fft_thread=new FftThread(mPlot->getPlots().at(selSource)->getSignal(),mPlot);
		connect(fft_thread,SIGNAL(finished()),this,SLOT(fftFinished()));
		
		fft_thread->start();
		
	}
	
	if (calcText!="Fourier Transform")
		mPlot->setEnabled(true);

	accept();

}

void CalcDlg::cancelClicked(){
	mPlot->setEnabled(true);
	reject();
}

void CalcDlg::fftFinished(){

	if (fft_thread->getReal().isEmpty() || fft_thread->getImag().isEmpty() || fft_thread->getPow().isEmpty()) {
		QMessageBox::critical(this,"Calculation ERROR","UnKnown Error Occured... Sorry");
		fft_thread->terminate();
		return;
	}
	
	// Place Results 
	int target=realTarget->itemData(realTarget->currentIndex()).toInt();
	mPlot->getPlots().at(target)->setSignal(fft_thread->getReal());
	
	target=imagTarget->itemData(imagTarget->currentIndex()).toInt();
	mPlot->getPlots().at(target)->setSignal(fft_thread->getImag());
	
	target=powerTarget->itemData(powerTarget->currentIndex()).toInt();
	mPlot->getPlots().at(target)->setSignal(fft_thread->getPow());

	mPlot->setEnabled(true);

	fft_thread->terminate();

}

void CalcDlg::refresh3dCombo(){
	int selSource=sourcePlot->itemData(sourcePlot->currentIndex()).toInt();
	
	//Check Calculation
	QString calcText=calculation->currentText();
	
	if (calcText=="Fourier Transform"){
		int selreal=realTarget->itemData(realTarget->currentIndex()).toInt();
		int selimag=imagTarget->itemData(imagTarget->currentIndex()).toInt();
		powerTarget->clear();
		
		for (int i=0; i<mPlot->getPlots().size(); i++){
			if (i!=selSource && i!=selreal && i!=selimag){
				QVariant index(i);
				powerTarget->addItem("Plot "+QString::number(i+1),index);
			}
		}
	}
}

// Fix 2nd Combo Box without changing the first
void CalcDlg::refresh2ndCombo(){
	// Hold selected source plot index (QVariant data)
	int selSource=sourcePlot->itemData(sourcePlot->currentIndex()).toInt();
	
	//Check Calculation
	QString calcText=calculation->currentText();
	
	if (calcText=="Sampling/Quantization") {
		int selSampTarget=samplingTarget->itemData(samplingTarget->currentIndex()).toInt();
		quantTarget->clear();
	
		
		for (int i=0; i<mPlot->getPlots().size(); i++){
			if (i!=selSource && i!=selSampTarget){
				QVariant index(i);
				quantTarget->addItem("Plot "+QString::number(i+1),index);
			}
		}
	}
	else if (calcText=="Adding" || calcText=="Mutipling" || calcText=="Convolution"){
		
		int selwith=with->itemData(with->currentIndex()).toInt();
		calcTarget->clear();
		
		for (int i=0; i<mPlot->getPlots().size(); i++){
			if (i!=selSource && i!=selwith){
				QVariant index(i);
				calcTarget->addItem("Plot "+QString::number(i+1),index);
			}
		}
	}
	else if (calcText=="Fourier Transform"){
		int selreal=realTarget->itemData(realTarget->currentIndex()).toInt();
		imagTarget->clear();
		
		for (int i=0; i<mPlot->getPlots().size(); i++){
			if (i!=selSource && i!=selreal){
				QVariant index(i);
				imagTarget->addItem("Plot "+QString::number(i+1),index);
			}
		}
		
		int selimag=imagTarget->itemData(imagTarget->currentIndex()).toInt();
		powerTarget->clear();
		
		for (int i=0; i<mPlot->getPlots().size(); i++){
			if (i!=selSource && i!=selreal && i!=selimag){
				QVariant index(i);
				powerTarget->addItem("Plot "+QString::number(i+1),index);
			}
		}
	}
}

/*
 * Fix All Combo Boxes of CURRENT Widget ONLY...
 */
void CalcDlg::refreshCombos(){
	// Hold selected source plot index (QVariant data)
	int selSource=sourcePlot->itemData(sourcePlot->currentIndex()).toInt();


	//Check Calculation
	QString calcText=calculation->currentText();
	
	if (calcText=="Sampling/Quantization") {
		// For sampling/quant Widget
		samplingTarget->clear();
	
		
		for (int i=0; i<mPlot->getPlots().size(); i++){
			if (i!=selSource){
				QVariant index(i);
				samplingTarget->addItem("Plot "+QString::number(i+1),index);
			}
		}
	
		
		int selSampTarget=samplingTarget->itemData(samplingTarget->currentIndex()).toInt();
		quantTarget->clear();
	
		
		for (int i=0; i<mPlot->getPlots().size(); i++){
			if (i!=selSource && i!=selSampTarget){
				QVariant index(i);
				quantTarget->addItem("Plot "+QString::number(i+1),index);
			}
		}
	}else if (calcText=="Adding" || calcText=="Multipling" || calcText=="Convolution"){
		// For Add
		with->clear();
		
		for (int i=0; i<mPlot->getPlots().size(); i++){
			if (i!=selSource && !mPlot->getPlots().at(i)->isEmpty()){
				QVariant index(i);
				with->addItem("Signal "+QString::number(i+1),index);
			}
		}
		
		int selwith=with->itemData(with->currentIndex()).toInt();
		calcTarget->clear();
		
		for (int i=0; i<mPlot->getPlots().size(); i++){
			if (i!=selSource && i!=selwith){
				QVariant index(i);
				calcTarget->addItem("Plot "+QString::number(i+1),index);
			}
		}
	}else if (calcText=="Fourier Transform"){
		realTarget->clear();
		
		for (int i=0; i<mPlot->getPlots().size(); i++){
			if (i!=selSource){
				QVariant index(i);
				realTarget->addItem("Plot "+QString::number(i+1),index);
			}
		}
		
		int selreal=realTarget->itemData(realTarget->currentIndex()).toInt();
		imagTarget->clear();
		
		for (int i=0; i<mPlot->getPlots().size(); i++){
			if (i!=selSource && i!=selreal){
				QVariant index(i);
				imagTarget->addItem("Plot "+QString::number(i+1),index);
			}
		}
		
		int selimag=imagTarget->itemData(imagTarget->currentIndex()).toInt();
		powerTarget->clear();
		
		for (int i=0; i<mPlot->getPlots().size(); i++){
			if (i!=selSource && i!=selreal && i!=selimag){
				QVariant index(i);
				powerTarget->addItem("Plot "+QString::number(i+1),index);
			}
		}
	}
}

// Change Widget in reqLayout
void CalcDlg::calcChanged(){
	
	if (current==0) return;
	
	QString calcText=calculation->currentText();
	
	
	// Remove old widget
	reqLayout->removeWidget(current);
	current->hide();
	
	// Insert new
	if (calcText=="Adding" || calcText=="Multipling" || calcText=="Convolution") {
		if (loadedSignals()<2) {
			reqLayout->addWidget(errorPane);
			current=errorPane;
			current->show();
			buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
			return;
		}
		
		// Fix Label
		if (calcText=="Adding") withLab->setText("Add With");
		else if (calcText=="Multipling") withLab->setText("Multiply With");
		else if (calcText=="Convolution") withLab->setText("With");
		
		reqLayout->addWidget(AddMulti);
		current=AddMulti;
		current->show();
	}
	else if (calcText=="Sampling/Quantization"){
		reqLayout->addWidget(SamplingQuant);
		current=SamplingQuant;
		current->show();
	}
	else if (calcText=="Fourier Transform"){
		if (mPlot->getPlots().size() < 4){
			reqLayout->addWidget(errorPane);
			current=errorPane;
			current->show();
			buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
			return;
		} 
		reqLayout->addWidget(Fft);
		current=Fft;
		current->show();	
	}
	
	
	// Everything OK refresh and enable ok button
	refreshCombos();
	buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
}

int CalcDlg::loadedSignals(){
	int c=0;
	for (int i=0; i<mPlot->getPlots().size(); i++){
		if (!mPlot->getPlots().at(i)->isEmpty())
			c++;
	}
	return c;
}



