/***************************************************************************
 *   Copyright (C) 2005 by David Saxton                                    *
 *   david@bluehaze.org                                                    *
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#ifndef OSCILLOSCOPE_H
#define OSCILLOSCOPE_H

#ifndef PROBE_H
#ifndef KTECHLAB_H
#ifndef OSCILLOSCOPEDATA_H
#include <ui_oscilloscopewidget.h>
#endif
#endif
#endif

#include "simulator.h"

#include <QMap>
#include <QWidget>

#include <stdint.h>

class FloatingProbeData;
class LogicProbe;
class LogicProbeData;
class KTechlab;
class Oscilloscope;
class Probe;
class ProbeData;
class VoltageProbe;
class QTimer;
namespace KateMDI { class ToolView; }

typedef QMap< int, ProbeData * > ProbeDataMap;
typedef QMap< int, LogicProbeData * > LogicProbeDataMap;
typedef QMap< int, FloatingProbeData * > FloatingProbeDataMap;

#if 0
const double MAX_BITS_PER_S = 100000;

// NOTE: The 10 has to agree with the 2^10 = 1024.0
const int MIN_MAX_LOG_2_DIFF = 10;
const double MIN_BITS_PER_S = MAX_BITS_PER_S / 1024.0;
#else
const double MAX_BITS_PER_S = LOGIC_UPDATE_RATE * 4;

// NOTE: The 18 has to agree with the 2^18 = 262144.0
const int MIN_MAX_LOG_2_DIFF = 18;
const double MIN_BITS_PER_S = MAX_BITS_PER_S / 262144.0;
#endif


/*
Due to strangeness with generation of .[cpp/h] files from .ui files (that is,
my inability to sort it out neatly), files other than those in /src/gui can't
see header files such as "oscilloscopewidget.h", so we have to provide some
interface functions for accessing the functionality in this class
*/
ProbeData * registerProbe( Probe * probe);
void unregisterProbe( int id);
void addOscilloscopeAsToolView( KTechlab *ktechlab);


#ifndef PROBE_H
#ifndef KTECHLAB_H
#ifndef OSCILLOSCOPEDATA_H
/**
@author David Saxton
*/
class Oscilloscope : public QWidget, public Ui::OscilloscopeWidget
{
	Q_OBJECT
	public:
		static Oscilloscope * self( KateMDI::ToolView * parent = nullptr);
		static QString toolViewIdentifier() { return "Oscilloscope"; }
		~Oscilloscope() override;
		
        static bool isInstantiated() ;

		/**
	 	* Register a probe (that outputs boolean data) with the oscilloscope.
	 	* Returns a unique id that the probe can use to add data points
		 */
		ProbeData * registerProbe( Probe * probe);
		void unregisterProbe( int id);
		/**
		 * Returns the Simulator time since recording started.
		 */
		uint64_t time() const;
		/**
		 * Returns how much of an increment in value of the oscilloscope slider
		 * is equivalent to one second.
		 */
		int sliderTicksPerSecond() const;
		/**
		 * Returns the number of pixels per second the user has requested to be
		 * displayed.
		 */
		double pixelsPerSecond() const;
		/**
		 * Zoom level; a value between 0 and 1. 0 is maximum zoom out, and 1 is
		 * maximum zoom in.
		 */
		double zoomLevel() const { return m_zoomLevel; }
		/**
		 * Sets the zoom level (and in the process, checks that it is within the
		 * bounds allowed).
		 */
		void setZoomLevel( double zoomLevel);
		/**
		 * Returns the Simulator time as given by the current scrollbar
		 * position.
		 */
		int64_t scrollTime() const;
		/**
		 * @returns pointer to probe with given id, or nullptr if no such probe exists
		 */
		ProbeData * probeData( int id) const;
		/**
		 * @returns the total number of probes
		 */
		int numberOfProbes() const;
		/**
		 * @returns number of the probe with the given id, starting from 0, or -1 if no such probe
		 */
		int probeNumber( int id) const;
		
	signals:
		/**
		 * Emitted when a probe is registered
		 */
		void probeRegistered( int id, ProbeData * probe);
		/**
		 * Emitted when a probe is unregistered
		 */
		void probeUnregistered( int id);
		
	public slots:
		/**
		 * Resets all recorded data
		 */
		void reset();
		/**
		 * Called when the zoom slider value was changed.
		 */
		void slotZoomSliderChanged( int value);
		/**
		 * Called when the horizontal scrollbar was scrolled by the user
		 */
		void slotSliderValueChanged( int value);
		/**
		 * Pause the data capture (e.g. user clicked on pause button)
		 */
		void slotTogglePause();
	
	protected:
		void getOldestProbe();
		
		int m_nextId;
		ProbeData * m_oldestProbe;
		int m_oldestId;
		int m_nextColor; // For giving the probes colours
		
		ProbeDataMap m_probeDataMap;
		LogicProbeDataMap m_logicProbeDataMap;
		FloatingProbeDataMap m_floatingProbeDataMap;
		
		Simulator * m_pSimulator;
		
	protected slots:
		void updateScrollbars();
		
	private:
		Oscilloscope( KateMDI::ToolView * parent);
		
		static Oscilloscope * m_pSelf;
		double m_zoomLevel;
		
		friend class OscilloscopeView;
		friend class ProbePositioner;
};

#endif // OSCILLOSCOPEDATA_H
#endif // KTECHLAB_H
#endif // PROBE_H

#endif // OSCILLOSCOPE_H
