/*
 * Remote Laboratory Oscilloscope Part
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * (c) 2012 - 2019 Timothy Pearson
 * Raptor Engineering, LLC
 * http://www.raptorengineering.com
 */

#ifndef REMOTELAB_SCOPEPART_H
#define REMOTELAB_SCOPEPART_H

#include <tdeparts/browserextension.h>
#include <tdeparts/statusbarextension.h>
#include <tdeparts/part.h>
#include <kurl.h>

#include <tqtrla.h>

#include "floatspinbox.h"

#define MAXTRACES	255
#define MAXMATHTRACES	255

class TDEAboutData;
using KParts::StatusBarExtension;
class TraceWidget;
class TQSocket;
class TQTimer;
class TQMutex;
class TQRectF;
class TQLabel;
class TQGridLayout;
class TQCheckBox;
class TQGroupBox;
class TQPushButton;
class ScopeBase;

typedef TQPair<TQString, TQ_INT16> MathOperator;
typedef TQValueList<MathOperator> MathOperatorList;

namespace RemoteLab
{
	class TraceControlWidget : public TQWidget
	{
		Q_OBJECT

		public:
			TraceControlWidget(TQWidget *parent=0, const char *name=0);
			~TraceControlWidget();

		public:
			void setVoltsPerDivList(TQDoubleList list);
			void setSelectedVoltsPerDiv(double vdiv);
			void setTraceEnabled(bool enabled);
			void setTraceName(TQString name);
			void setTriggerChannel(bool isTrigger);

		signals:
			void enableChanged(bool enabled);
			void voltsPerDivChanged(double vdiv);
			void triggerChannelChangeRequested();

		private slots:
			void enableClicked();
			void vdivChanged(int index);
			void triggerRequested();

		private:
			TQGroupBox* m_groupBox;
			TQGridLayout* m_primaryLayout;
			TQComboBox* m_voltsDivComboBox;
			TQCheckBox* m_channelEnabledCheckBox;
			TQPushButton* m_setTriggerChannelButton;

			TQDoubleList m_voltsDivList;
	};

	class TracePostProcessControlWidget : public TQWidget
	{
		Q_OBJECT

		public:
			TracePostProcessControlWidget(TQWidget *parent=0, const char *name=0);
			~TracePostProcessControlWidget();

		public:
			void setSelectedVoltsMultiplier(double vmult);
			void setPostProcessEnabled(bool enabled);
			void setTraceName(TQString name);

		signals:
			void enableChanged(bool enabled);
			void voltsMultiplierChanged(double vmult);

		private slots:
			void enableClicked();
			void vMultChanged(double vmult);

		private:
			TQGroupBox* m_groupBox;
			TQGridLayout* m_primaryLayout;
			FloatSpinBox* m_voltsMultiplierSpinBox;
			TQCheckBox* m_postProcessEnabledCheckBox;
	};

	class MathTraceControlWidget : public TQWidget
	{
		Q_OBJECT

		public:
			MathTraceControlWidget(TQWidget *parent=0, const char *name=0);
			~MathTraceControlWidget();

		public:
			void setVoltsPerDivList(TQDoubleList list);
			void setFirstMathOperandList(TQInt16List list);
			void setSecondMathOperandList(TQInt16List list);
			void setMathOperatorList(MathOperatorList list);
			void setSelectedVoltsPerDiv(double vdiv);
			void setSelectedFirstMathOperand(int channel);
			void setSelectedSecondMathOperand(int channel);
			void setSelectedMathOperator(TQString op);
			void setTraceEnabled(bool enabled);
			void setTraceName(TQString name);
			void setVerticalUnits(TQString units);

		signals:
			void enableChanged(bool enabled);
			void voltsPerDivChanged(double vdiv);
			void firstMathOperandChanged(int channel);
			void secondMathOperandChanged(int channel);
			void mathOperatorChanged(TQString op);

		private slots:
			void enableClicked();
			void vdivChanged(int index);
			void operandFirstChanged(int index);
			void operandSecondChanged(int index);
			void operatorChanged(int index);

		private:
			void updateMathOperatorOperandVisibility();

		private:
			TQGroupBox* m_groupBox;
			TQGridLayout* m_primaryLayout;
			TQComboBox* m_voltsDivComboBox;
			TQCheckBox* m_channelEnabledCheckBox;
			TQComboBox* m_operandFirstComboBox;
			TQComboBox* m_operandSecondComboBox;
			TQComboBox* m_operatorComboBox;
			TQLabel* m_verticalUnitsLabel;

			TQDoubleList m_voltsDivList;
			TQInt16List m_firstMathOperandList;
			TQInt16List m_secondMathOperandList;
			MathOperatorList m_mathOperatorList;
	};

	class TimebaseControlWidget : public TQWidget
	{
		Q_OBJECT

		public:
			TimebaseControlWidget(TQWidget *parent=0, const char *name=0);
			~TimebaseControlWidget();

		public:
			void setSecondsPerDivList(TQDoubleList list);
			void setSelectedSecondsPerDiv(double sdiv);

		signals:
			void secondsPerDivChanged(double sdiv);

		private slots:
			void sdivChanged(int index);

		private:
			TQGroupBox* m_groupBox;
			TQGridLayout* m_primaryLayout;
			TQComboBox* m_secondsDivComboBox;

			TQDoubleList m_secondsDivList;
	};

	class ScopePart : public KParts::RemoteInstrumentPart
	{
		Q_OBJECT

		public:
			ScopePart( QWidget *, const char *, TQObject *, const char *, const TQStringList&);
			~ScopePart();

			virtual bool openFile() { return false; }	// pure virtual in the base class
			virtual bool closeURL();
			static TDEAboutData *createAboutData();

		public slots:
			virtual bool openURL(const KURL &url);
			void updateZoomWidgetLimits(const TQRectF& zoomRect);

		private slots:
			void postInit();
			void processLockouts();
			void updateGraticule();
			void controlWidgetViewSetWidth();
			void connectionFinishedCallback();
			void disconnectFromServerCallback();
			void connectionStatusChangedCallback();
			void setTickerMessage(TQString message);
			void mainEventLoop();
			void dumpSamples();
			void startDAQ();
			void stopDAQ();
			void updateTraceControlWidgets();
			void traceControlEnableChanged(bool enabled);
			void traceControlVDivChanged(double vdiv);
			void traceControlSDivChanged(double sdiv);
			void tracePostProcessControlEnableChanged(bool enabled);
			void tracePostProcessControlVMultChanged(double vmult);
			void mathTraceControlEnableChanged(bool enabled);
			void mathTraceControlVDivChanged(double vdiv);
			void mathTraceControlFirstOperandChanged(int operand);
			void mathTraceControlSecondOperandChanged(int operand);
			void mathTraceControlOperatorChanged(TQString op);
			void cursorLevelChanged(uint cursor, double level);
			void processTriggerButtons();
			void startScope();
			void stopScope();
			void saveWaveforms();
			void recallWaveforms();
			virtual void processMathTraces();
			virtual void postProcessTrace();

		private:
			void updateMathTraceAllowedVoltsPerDivList(int traceno);

		private:
			TraceWidget* m_traceWidget;
			TQGridLayout* m_traceControlWidgetGrid;
			TQGridLayout* m_mathTraceControlWidgetGrid;
			TQGridLayout* m_postProcessTraceControlWidgetGrid;
			TQGridLayout* m_timebaseControlWidgetGrid;
			int m_commHandlerState;
			int m_commHandlerMode;
			int m_commHandlerCommandState;
			TQTimer* m_forcedUpdateTimer;
			TQTimer* m_updateTimeoutTimer;
			TQTimer* m_controlWidgetViewFixupTimer;
			bool m_connectionActiveAndValid;
			unsigned char m_tickerState;
			TQ_INT16 m_maxNumberOfTraces;
			TQ_INT16 m_maxNumberOfMathTraces;
			TQ_INT32 m_currentOpChannel;
			TQ_INT32 m_nextOpChannel;
			TQ_INT16 m_nextOpParameter16;
			TQ_INT16 m_hdivs;
			TQ_INT16 m_vdivs;
			TQ_INT16 m_triggerChannel;
			bool m_running;
			double m_triggerLevel;
			double m_horizontalTimebase;
			TQ_INT32 m_samplesInTrace[MAXTRACES+1];
			TQ_INT32 m_samplesInMathTrace[MAXMATHTRACES+1];
			bool m_channelActive[MAXTRACES+1];
			bool m_mathChannelActive[MAXMATHTRACES+1];
			TQDoubleList m_traceAllowedVoltsDiv[MAXTRACES+1];
			TQDoubleList m_mathTraceAllowedVoltsDiv[MAXTRACES+1];
			double m_voltsDiv[MAXTRACES+1];
			double m_mathVoltsDiv[MAXMATHTRACES+1];
			double m_secsDiv[MAXTRACES+1];
			double m_mathSecsDiv[MAXMATHTRACES+1];
			TQ_INT16 m_mathFirstOperand[MAXMATHTRACES+1];
			TQ_INT16 m_mathSecondOperand[MAXMATHTRACES+1];
			TQString m_mathOperator[MAXMATHTRACES+1];
			TQString m_mathHorizontalUnits[MAXMATHTRACES+1];
			TQString m_mathVerticalUnits[MAXMATHTRACES+1];
			TraceControlWidget* m_traceControlWidgetList[MAXTRACES+1];
			TracePostProcessControlWidget* m_tracePostProcessControlWidgetList[MAXTRACES+1];
			MathTraceControlWidget* m_mathTraceControlWidgetList[MAXMATHTRACES+1];
			TimebaseControlWidget* m_timebaseControlWidget;
			bool m_triggerLevelSet;
			bool m_triggerChannelSet;
			bool m_horizontalTimebaseSet;
			bool m_runningSet;
			bool m_voltsDivSet[MAXTRACES+1];
			bool m_channelActiveSet[MAXTRACES+1];
			bool m_channelPostProcessActive[MAXTRACES+1];
			double m_channelPostProcessVoltsMult[MAXTRACES+1];
			bool m_settingsChanged;
			MathOperatorList m_availableMathOperators;
			ScopeBase* m_base;
			TQMutex* m_instrumentMutex;
			bool m_stopTraceUpdate;
	};
}

#endif
