/***************************************************************************
                          adjustmirrordlg.cpp  -  description
                             -------------------
    begin                : Sat Nov 23 08:23:53 UTC 2002
    copyright            : (C) 2002 by Martin Merck
    email                : merck@astro.uni-wuerzburg.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is part of the MAGIC control software for the AMC.       *
 *   The software is only intended for use in the MAGIC telescope project  *
 *   All rights remain with the author.					   *
 ***************************************************************************/

#include <qlayout.h>
#include <qmessagebox.h>
#include <qlineedit.h>
#include <qpushbutton.h>
#include <qcheckbox.h>
#include <qpopupmenu.h>
#include <qlabel.h>
#include <qvalidator.h>
#include <kapp.h>
#include "amcerror.h"
#include "amcserialport.h"
#include "amcmirrorpanel.h"
#include "amcmotor.h"
#include "amcprogdlg.h"
#include "adjustmirrordlg.h"
#include "threadcontroller.h"
#include "magicmirror.h"
#include "videodisplay.h"

#define MAX(a,b) ((a>b) ? a : b )

extern KApplication*	g_theApp;
extern AMCSerialPort* g_pPort[];
extern MagicMirror*		g_theMirror;

AdjustMirrorDlg::AdjustMirrorDlg(QWidget *parent, const char *name, bool modal = FALSE)
	: AdjustMirrorDlgBase(parent, name, modal)
{
	m_pMotor = 0;
	m_pCurrentPanel = 0;
	
	// now we add the mirror selector to the dialog panel
	m_mirrorWidget = new MirrorSelector( this, "Mirror Selector");
	((QGridLayout*) this->layout())->addWidget( m_mirrorWidget,0,0 );
	
	QObject::connect( m_mirrorWidget, SIGNAL( panelSelectedSignal( AMCMirrorPanel* ) ),
					  this, SLOT( mirrorSelectedSlot( AMCMirrorPanel* ) ) );
	
	// create the context menu.
	m_contextMenu = new QPopupMenu();
	m_contextMenu->insertItem( "Save positions", this, SLOT( savePositionsSlot() ) );

  Frequency_Value->setValidator( new QIntValidator( 0, 2000, Frequency_Value ) );
  Working_I_Value->setValidator( new QIntValidator( 0, 2000, Working_I_Value ) );
  Holding_I_Value->setValidator( new QIntValidator( 0, 2000, Holding_I_Value ) );

  X_Goto_Value->setValidator( new QIntValidator( -3000, 3000, X_Goto_Value ) );
  Y_Goto_Value->setValidator( new QIntValidator( -3000, 3000, Y_Goto_Value ) );
}

AdjustMirrorDlg::~AdjustMirrorDlg()
{
//	delete m_mirrorWidget;
}

/** No descriptions */
void AdjustMirrorDlg::mirrorSelectedSlot( AMCMirrorPanel* pPanel )
{
	if( !pPanel->isPowerOn() )
	{
		Motor_Power_Check->setChecked( false );
		
		QString str;
   		int iRes = QMessageBox::warning( this,
   										 "AMC Warning",
										 "The motor power for this panel has previously been\n"
										 "switched off. By selecting this driver the power will\n"
										 "be switched on automatically!\n"
										 "Do you want to proceed?",
										 "Yes",
										 "No" );
		if( iRes == 1)
		{
			if(m_pMotor != 0 )
			{
				try
				{
					m_pMotor->unselectBox();
				}
				catch( AMCError& e )
				{
				}
				delete m_pMotor;
				m_pMotor = 0;
			}
			enableButtons( false );
			Panel_Info->setTitle( "Panel" );
			Device_Label->setText( "Device: -" );
			Box_Label->setText( "Box: --" );
			Driver_Label->setText( "Driver: -" );
			return;
		}
		
		pPanel->setPowerOn( true );
		
	}
	m_pCurrentPanel = pPanel;
	int iPort   = pPanel->port();
	AMCSerialPort* pPort = g_pPort[ iPort-1 ];
	
	QString info;
	Panel_Info->setTitle( info.sprintf( "Panel: %d,%d", pPanel->i(), pPanel->j() ) );
	Device_Label->setText( info.sprintf( "Device: /dev/ttyS%d", pPanel->port()+3 ) );
	Box_Label->setText( info.sprintf( "Box: %02d", pPanel->box() ) );
	Driver_Label->setText( info.sprintf( "Driver: %d", pPanel->driver() ) );
	
	if(m_pMotor != 0 )
	{
		delete m_pMotor;
	}
		
	m_pMotor = new AMCMotor( pPort );
	try
	{
		m_pMotor->unselectBox();
	}
	catch( AMCError& e )
	{
	}
	
//	QString str;
//   	QMessageBox::information( this,
//   							  "AMC Info",
//							  str.sprintf( "%d %d %d",
//							  			   pPanel->port(),
//							  			   pPanel->box(),
//							  			   pPanel->driver() ),
//							  QMessageBox::Ok | QMessageBox:: Default );
	
	try
	{
		enableButtons( true );
		
		int iBox = pPanel->box();
		m_pMotor->selectBox( iBox );
		
		int iTemp, iHum, iPowerI, iPowerV, iSecondV, iLogicV;
		m_pMotor->getInfo( &iTemp, &iHum, &iPowerI, &iPowerV, &iSecondV, &iLogicV);

		// Convert ADC vaues to primary voltages or currents
		double dTemp, dHum, dPowerI, dPowerV, dSecondV, dLogicV;
		dTemp   =  ( ((double) iTemp) );
		dPowerI =  ( ((double) iPowerI) );
		dPowerV =  ( ((double) iPowerV) / 1024.0) * 2.56 * 103.0 / 3.0;
		dSecondV = ( ((double) iSecondV) / 1024.0) * 2.56 * 103.0 / 3.0;
		dLogicV =  ( ((double) iLogicV) / 1024.0) * 2.56 * 6.9 / 2.2;
		
		Temperature_Value->setText( QString::number( dTemp, 'f', 1 ) );
		Humidity_Value->setText( QString::number( iHum ) );
		Power_I_Value->setText( QString::number( dPowerI, 'f', 1 ) );
		Power_V_Value->setText( QString::number( dPowerV, 'f', 1 ) );
		Secondary_V_Value->setText( QString::number( dSecondV, 'f', 1 ) );
		Logical_V_Value->setText( QString::number( dLogicV, 'f', 1 ) );
		
		int iDriver = pPanel->driver();
		m_pMotor->selectDriver( iDriver );
		
		int iFrequency      = m_pMotor->getFrequency();
		int iWorkingCurrent = m_pMotor->getWorkingCurrent();
		int iHoldingCurrent = m_pMotor->getHoldingCurrent();
		
		Frequency_Value->setText( QString::number( iFrequency ) );
		Working_I_Value->setText( QString::number( iWorkingCurrent ) );
		Holding_I_Value->setText( QString::number( iHoldingCurrent ) );
		
		Laser_Check->setChecked( pPanel->isLaserOn() );
		Motor_Power_Check->setChecked( pPanel->isPowerOn() );
	}
	catch( AMCError& e )
	{
		QString str;
		QMessageBox::information( this,
								  "AMCError",
  							  	  e.getErrorText(),
  							  	  QMessageBox::Ok | QMessageBox:: Default );
		enableButtons( false );
		delete m_pMotor;
		m_pMotor = 0;
		m_pCurrentPanel = 0;
		qDebug(e.formatError(0));
	}
	
	
}

/** No descriptions */
void AdjustMirrorDlg::enableButtons( bool p_zEnable ) const
{
	Temperature_Value->setEnabled( p_zEnable );
	Humidity_Value->setEnabled( p_zEnable );
	Power_I_Value->setEnabled( p_zEnable );
	Power_V_Value->setEnabled( p_zEnable );
	Secondary_V_Value->setEnabled( p_zEnable );
	Logical_V_Value->setEnabled( p_zEnable );
	
	Frequency_Value->setEnabled( p_zEnable );
	Working_I_Value->setEnabled( p_zEnable );
	Holding_I_Value->setEnabled( p_zEnable );
	Set_Button->setEnabled( p_zEnable );
	Laser_Check->setEnabled( p_zEnable );
	Motor_Power_Check->setEnabled( p_zEnable );
	
	X_Inc_100_Button->setEnabled( p_zEnable );
	X_Inc_10_Button->setEnabled( p_zEnable );
	X_Goto_Value->setEnabled( p_zEnable );
	X_Go_Button->setEnabled( p_zEnable );
	X_Dec_10_Button->setEnabled( p_zEnable );
	X_Dec_100_Button->setEnabled( p_zEnable );
	
	Y_Inc_100_Button->setEnabled( p_zEnable );
	Y_Inc_10_Button->setEnabled( p_zEnable );
	Y_Goto_Value->setEnabled( p_zEnable );
	Y_Go_Button->setEnabled( p_zEnable );
	Y_Dec_10_Button->setEnabled( p_zEnable );
	Y_Dec_100_Button->setEnabled( p_zEnable );
		
	if( p_zEnable )
	{
		int x = m_pCurrentPanel->getX();
		int y = m_pCurrentPanel->getY();
		
		QString str;
		X_Mot_Box->setTitle( str.sprintf("X=%d",x ) );
		Y_Mot_Box->setTitle( str.sprintf("Y=%d",y ) );
		X_Inc_100_Button->setEnabled( (x > 2400) ? false : true );
		X_Inc_10_Button->setEnabled( (x > 2490) ? false : true );
		X_Dec_10_Button->setEnabled( (x < -2490) ? false : true );
		X_Dec_100_Button->setEnabled( (x < -2400) ? false : true );
		
		Y_Inc_100_Button->setEnabled( (y > 2400) ? false : true );
		Y_Inc_10_Button->setEnabled( (y > 2490) ? false : true );
		Y_Dec_10_Button->setEnabled( (y < -2490) ? false : true );
		Y_Dec_100_Button->setEnabled( (y < -2400) ? false : true );

	}
	
	Center_Button->setEnabled( p_zEnable );
	VideoButton->setEnabled( p_zEnable );
}

/** Switch the laser on. */
void AdjustMirrorDlg::switchLaserSlot( bool p_zOn )
{
  if( p_zOn )
		qDebug("Switching LASER on for Panel %p", m_pMotor);
	else
		qDebug("Switching LASER off for Panel %p", m_pMotor);
	try
	{
		m_pMotor->switchLaser( p_zOn );
		m_pCurrentPanel->setLaserOn( p_zOn );
	}
	catch( AMCError& e )
	{
		QMessageBox::information( this,
								  "AMCError",
  							  	  e.getErrorText(),
  							  	  QMessageBox::Ok | QMessageBox:: Default );
		enableButtons( false );
		delete m_pMotor;
		m_pMotor = 0;
		m_pCurrentPanel = 0;
	}
		
}

/** Power motors on or off. */
void AdjustMirrorDlg::powerMotorsSlot()
{

	if ( m_pCurrentPanel->isPowerOn( ) )
	{
  		int iRes = QMessageBox::warning( this,
  										 "AMC Warning",
  										 "Turning the motor power of will also stop the holding\n"
  										 "current. You should only do this in case of problems\n"
  										 "with this driver!\n"
  										 "Selecting a movement command or the driver will automatically\n"
  										 "switch the power back on. Do you wish to proceed?",
  										 "Yes",
  										 "No" );
		if( iRes == 1)
		{
			m_pCurrentPanel->setPowerOn( true );	
			return;
		}
	}
	
	bool zOn = !m_pCurrentPanel->isPowerOn( );
	try
	{
		m_pMotor->powerMotors( zOn );
		m_pCurrentPanel->setPowerOn( zOn );
	}
	catch( AMCError& e )
	{
		QMessageBox::information( this,
								  "AMCError",
  							  	  e.getErrorText(),
  							  	  QMessageBox::Ok | QMessageBox:: Default );
		enableButtons( false );
		delete m_pMotor;
		m_pMotor = 0;
		m_pCurrentPanel = 0;
	}
}

/** Power motors on or off. */
void AdjustMirrorDlg::setParamsSlot()
{
  bool zOk;
	int iFrequency = Frequency_Value->text().toInt( &zOk );
	int iWorkingI = Working_I_Value->text().toInt( &zOk );
	int iHoldingI = Holding_I_Value->text().toInt( &zOk );
	try
	{
		m_pMotor->setFrequency( iFrequency );
		m_pMotor->setWorkingCurrent( iWorkingI );
		m_pMotor->setHoldingCurrent( iHoldingI );
	}
	catch( AMCError& e )
	{
		QMessageBox::information( this,
								  "AMCError",
  							  	  e.getErrorText(),
  							  	  QMessageBox::Ok | QMessageBox:: Default );
		enableButtons( false );
		delete m_pMotor;
		m_pMotor = 0;
		m_pCurrentPanel = 0;
	}
}

/** Center the motors. */
void AdjustMirrorDlg::centerSlot()
{
//	Motor_Power_Check->setChecked( false );
	enableButtons( false );
//	g_theApp->processEvents();
	try
	{
		m_pMotor->centerMotors();
		m_pMotor->waitForMotors( m_pMotor->calcTimeout( 17000 )+2 );
	}
	catch( AMCError& e )
	{
		QMessageBox::information( this,
								  "AMCError",
  							  	  e.getErrorText(),
  							  	  QMessageBox::Ok | QMessageBox:: Default );
		enableButtons( false );
		delete m_pMotor;
		m_pMotor = 0;
		m_pCurrentPanel = 0;
		return;
	}
	m_pCurrentPanel->setX( 0 );
	m_pCurrentPanel->setY( 0 );
	enableButtons( true );
}

/** Goto the position given by X. */
void AdjustMirrorDlg::goXSlot()
{
  bool zOk;
	int iX = X_Goto_Value->text().toInt( &zOk );
	moveMotors( iX - m_pCurrentPanel->getX(), 0 );
}

/** Goto the position given by Y. */
void AdjustMirrorDlg::goYSlot()
{
  bool zOk;
	int iY = Y_Goto_Value->text().toInt( &zOk );
	moveMotors( 0, iY - m_pCurrentPanel->getY() );
}

/** Move motors relative by the given amount of steps. */
void AdjustMirrorDlg::moveMotors( int p_iX, int p_iY )
{
	if( (p_iX == 0) && (p_iY == 0) )
		return;
	Motor_Power_Check->setChecked( true );
	
	enableButtons( false );
//	g_theApp->processEvents();
	try
	{
		m_pMotor->moveMotors( p_iX, p_iY );
		m_pMotor->waitForMotors( m_pMotor->calcTimeout( MAX( abs(p_iX), abs(p_iY) ) ) );			
	
		int x = m_pCurrentPanel->getX() + p_iX;
		int y = m_pCurrentPanel->getY() + p_iY;
		m_pCurrentPanel->setX( x );
		m_pCurrentPanel->setY( y );
	}
	catch( AMCError& e )
	{
		QMessageBox::information( this,
								  "AMCError",
  							  	  e.formatError(),
  							  	  QMessageBox::Ok | QMessageBox:: Default );
		enableButtons( false );
		m_pMotor->resetBox();
		delete m_pMotor;
		m_pMotor = 0;
		m_pCurrentPanel = 0;
		return;
	}
	
	enableButtons( true );
}

/** No descriptions */
void AdjustMirrorDlg::closeEvent( QCloseEvent* e )
{
	qDebug("AdjustMirrorDlg::closeEvent");
	int iRes = QMessageBox::warning( this,
							  "AMC Exiting",
  							  "Save current mirror positions as defaults?",
  							  "Save",
  							  "Discard" );
  if( iRes == 0)
		g_theMirror->saveMirrorPanels();
		
	e->accept();
}

/** Save the positions to the file. */
void AdjustMirrorDlg::savePositionsSlot()
{
	qDebug("AdjustMirrorDlg::savePositionsSlot");
	g_theMirror->saveMirrorPanels();
}

/** Check to see if the right mouse button was pressed and
	show the context menu in this case.
  */
void AdjustMirrorDlg::mousePressEvent( QMouseEvent* p_pEvent )
{
	if( p_pEvent->button() == RightButton )
		m_contextMenu->exec( QCursor::pos() );
}

/** show / hide video.
  */
void AdjustMirrorDlg::videoSlot()
{
	enableButtons( false );
	qDebug("Creating new Videodisplay() ");
	VideoDisplay* pDlg = new VideoDisplay( this, "Video", true);
	pDlg->setMotor( m_pMotor );
	pDlg->setPanel( m_pCurrentPanel );
	int iRet = pDlg->exec();
	delete pDlg;
	Laser_Check->setChecked( m_pCurrentPanel->isLaserOn() );
	enableButtons( true );
	qDebug("Returning from videoSlot() ");
}

/** No descriptions */
void AdjustMirrorDlg::allLasersOnSlot()
{
	allLasersOnOff( QString("Switching all lasers on"), true);
}

/** No descriptions */
void AdjustMirrorDlg::allLasersOffSlot()
{
	allLasersOnOff( QString("Switching all lasers off"), false);
}

/** No descriptions */
void AdjustMirrorDlg::allLasersOnOff( QString p_qsMsg, bool p_zOn)
{
	AMCProgDlg* pDialog = new AMCProgDlg( LASER_THREAD_CTRL, this, p_qsMsg, true );
	pDialog->setText( p_qsMsg );
	pDialog->setBool( p_zOn );
	pDialog->start();
	pDialog->exec();
	delete pDialog;

	if( m_pCurrentPanel != 0 )
	{
		try
		{
			// reselect the currently selected panel
			m_pMotor->unselectBox();
			int iBox = m_pCurrentPanel->box();
			m_pMotor->selectBox( iBox );
			int iDriver = m_pCurrentPanel->driver();
			m_pMotor->selectDriver( iDriver );
		}
		catch( AMCError& e )
		{
			QMessageBox::information( this,
									  "AMCError",
  						  	  e.formatError(),
  						  	  QMessageBox::Ok | QMessageBox:: Default );
			enableButtons( false );
			delete m_pMotor;
			m_pMotor = 0;
			m_pCurrentPanel = 0;
			return;
		}
		// We may need to togle the switch on the display of the laser status.
		// Befor we do this we have to check if the laser is realy on or of.
		Laser_Check->setChecked( m_pCurrentPanel->isLaserOn() );
	}

}
