/*******************************************************************************
Copyright (c) 2010 Tecella LLC
Licensed under the MIT License
*******************************************************************************/

#include "amplifier_settings.h"
#include "ui_amplifier_settings.h"

#include <QThread>
#include <QProgressDialog>
#include <QMessageBox>
#include <sstream>

#include "tecella_helper_widgets.h"
#include "system_monitor.h"
#include "acquisition_interrupter.h"
#include "tc_utility_shared.h"
#include "auto_calibration_threads.h"

AmplifierSettings::AmplifierSettings(QWidget *parent, TECELLA_HNDL amp_handle_new )
: QWidget(parent), ui(new Ui::AmplifierSettings), acquisition_interrupter(0)
{
	ui->setupUi(this);
	setAmpHandle(amp_handle_new);
}

AmplifierSettings::~AmplifierSettings()
{
    delete ui;
}

void AmplifierSettings::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void AmplifierSettings::setAmpHandle( TECELLA_HNDL amp_handle_new )
{
	amp_handle = amp_handle_new;

	updatingUI = true;

	TECELLA_HW_PROPS hwprops;
	TECELLA_HW_PROPS_EX_01 hwprops_ex_01;
	tecella_get_hw_props(amp_handle, &hwprops);
	tecella_get_hw_props_ex_01(amp_handle, &hwprops_ex_01);

	//Enumerate available configurations
	ui->comboBox_Configuration->clear();
	for(int config=0; config<hwprops.user_config_count; ++config)
	{
		TECELLA_HW_PROPS user_config_props;
		tecella_user_config_get(amp_handle, config, &user_config_props);
		ui->comboBox_Configuration->addItem(
			QString::fromWCharArray(user_config_props.user_config_name) );
	}

	//Select current configuration
	int user_config;
	tecella_user_config_get_current(amp_handle, &user_config);
	ui->comboBox_Configuration->setCurrentIndex(user_config);

	//System Monitor
	int system_monitor_count = hwprops_ex_01.dynamic_system_monitor_count;
	ui->comboBox_SystemMonitorIndex->clear();
	for(int i=0; i<system_monitor_count; i++) {
		ui->comboBox_SystemMonitorIndex->addItem( QString::number(i) );
	}
	ui->comboBox_SystemMonitorIndex->setCurrentIndex(0);

	//Update configuration info.
	std::stringstream info;
	info << "Model: " << QString::fromWCharArray( hwprops.device_name ).toStdString() << "\n";

	info << "Channels: " << hwprops.nchans << "\n";
	double freq = 1 / hwprops.sample_period_min;

	tcu::MetricBase freq_best_base = tcu::MetricBase::bestBase( freq );
	info << "Sampling frequency: " << freq/freq_best_base.base
			 << " " << freq_best_base.prefix << "Hz\n";

	tcu::MetricBase stimulus_best_base = tcu::MetricBase::bestBase( hwprops.stimulus_value_max );
	info << "Stimulus range: " << hwprops.stimulus_value_min/stimulus_best_base.base
			<< "" << stimulus_best_base.prefix << tcu::wstr2str(hwprops_ex_01.stimulus_units)
			<< " to " << hwprops.stimulus_value_max/stimulus_best_base.base
			<< "" << stimulus_best_base.prefix << tcu::wstr2str(hwprops_ex_01.stimulus_units) << "\n";

	ui->label_ConfigurationInfo->setText( info.str().c_str() );

	//Calibration info
	bool bvalue;

	tecella_auto_calibrate_enable_get( amp_handle, &bvalue );
	ui->checkBox_EnableOffsetCalibration->setChecked(bvalue);

	tecella_auto_scale_enable_get( amp_handle, &bvalue );
	ui->checkBox_EnableScaleCalibration->setChecked(bvalue);


	//DACs
	ui->doubleSpinBox_UDac1->setRange(
			hwprops.utility_dac_min, hwprops.utility_dac_max );
	ui->doubleSpinBox_UDac1->setSingleStep( hwprops.utility_dac_lsb );

	ui->doubleSpinBox_UDac2->setRange(
			hwprops.utility_dac_min, hwprops.utility_dac_max );
	ui->doubleSpinBox_UDac2->setSingleStep( hwprops.utility_dac_lsb );

	ui->doubleSpinBox_UDac3->setRange(
			hwprops.utility_dac_min, hwprops.utility_dac_max );
	ui->doubleSpinBox_UDac3->setSingleStep( hwprops.utility_dac_lsb );

	ui->doubleSpinBox_UDac4->setRange(
			hwprops.utility_dac_min, hwprops.utility_dac_max );
	ui->doubleSpinBox_UDac4->setSingleStep( hwprops.utility_dac_lsb );

	updatingUI = false;
}

void AmplifierSettings::setAcquisitionInterrupter( AcquisitionInterrupter *acquisition_interrupter_new )
{
	acquisition_interrupter = acquisition_interrupter_new;
}

//returns true if caller should assume acquisition has been paused.
//acquisition may not be paused if acquisition_interrupter is not set.
bool AmplifierSettings::pauseAcquisition()
{
	if( acquisition_interrupter ) {
		if( !acquisition_interrupter->pause_acquisition(true) ) {
			QMessageBox::information(this, "Warning", "Unable to interrupt acquisition to perform automatic compensation.", "Ok");
			return false;
		}
	}
	return true;
}

//returns true if caller should assume acquisition has been resumed.
//acquisition may not be resumed if acquisition_interrupter is not set.
bool AmplifierSettings::resumeAcquisition()
{
	if( acquisition_interrupter ) {
		if( !acquisition_interrupter->resume_acquisition(true) ) {
			QMessageBox::information(this, "Warning", "Could not resume normal acquisition after automatic compensation.", "Ok");
			return false;
		}
	}
	return true;
}

void AmplifierSettings::doAutoCalibrate(bool enable)
{
	if(updatingUI) { return; }

	if(!pauseAcquisition()) { return; }

	AutoCalibrateThread auto_calibrate_thread(amp_handle, enable);
	auto_calibrate_thread.start();
    display_qthread_progress_estimate(this, "Calibrating all amplifer configurations.\nThis may take a few minutes...",
        &auto_calibrate_thread, 45);     //YT: Reduce to 45 to make it appear to progress faster

	resumeAcquisition();
	return;
}

void AmplifierSettings::doAutoCalibrateCurrent(bool enable)
{
	if(updatingUI) { return; }

	if(!pauseAcquisition()) { return; }

	AutoCalibrateCurrentThread auto_calibrate_current_thread(amp_handle, enable);
	auto_calibrate_current_thread.start();
	display_qthread_progress_estimate(this, "Calibrating current configuration...", &auto_calibrate_current_thread, 20);

	resumeAcquisition();
	return;
}

void AmplifierSettings::on_comboBox_Configuration_currentIndexChanged(int index)
{
	if(updatingUI) { return; }

	TECELLA_ERRNUM err = tecella_user_config_set(amp_handle, index);
	if(err!=TECELLA_ERR_OK) {
		QMessageBox::information(0, "Error", "While changing user config.", "Ok");
	}

	//refresh this UI and notify others
	setAmpHandle(amp_handle);
	emit ampOrConfigChanged();
}

void AmplifierSettings::on_pushButton_SystemMonitor_clicked()
{
	SystemMonitor system_monitor(amp_handle, this);
	system_monitor.exec();
}

void AmplifierSettings::on_comboBox_SystemMonitorIndex_currentIndexChanged(int index)
{
	tecella_system_monitor_dynamic_set(amp_handle, index);
}

void AmplifierSettings::on_doubleSpinBox_UDac1_valueChanged(double value )
{
	tecella_utility_dac_set( amp_handle, value, 0);
}

void AmplifierSettings::on_doubleSpinBox_UDac2_valueChanged(double value)
{
	tecella_utility_dac_set( amp_handle, value, 1);
}

void AmplifierSettings::on_doubleSpinBox_UDac3_valueChanged(double value)
{
	tecella_utility_dac_set( amp_handle, value, 2);
}

void AmplifierSettings::on_doubleSpinBox_UDac4_valueChanged(double value)
{
	tecella_utility_dac_set( amp_handle, value, 3);
}

void AmplifierSettings::showCalibrateScale(bool enable)
{
    ui->comboBox_SystemMonitorIndex->setShown(enable);
    ui->pushButton_CalibrateAll->setShown(enable);
    ui->pushButton_SystemMonitor->setShown(enable);
    ui->label_3->setShown(enable);
}

void AmplifierSettings::acquisitionHint(bool acquiring)
{
	ui->comboBox_Configuration->setEnabled(!acquiring || acquisition_interrupter);
	ui->pushButton_CalibrateAll->setEnabled(!acquiring || acquisition_interrupter);
	ui->pushButton_SystemMonitor->setEnabled(!acquiring || acquisition_interrupter);
}

void AmplifierSettings::on_checkBox_EnableOffsetCalibration_toggled(bool checked)
{
	if(updatingUI) { return; }
	tecella_auto_calibrate_enable( amp_handle, checked );
}

void AmplifierSettings::on_checkBox_EnableScaleCalibration_toggled(bool checked)
{
	if(updatingUI) { return; }
	tecella_auto_scale_enable( amp_handle, checked );
}

void AmplifierSettings::on_pushButton_CalibrateAll_clicked()
{
	doAutoCalibrate(true);
}

void AmplifierSettings::on_pushButton_CalibrateCurrentConfig_clicked()
{
	doAutoCalibrateCurrent(true);
}
