/* -LICENSE-START-
** Copyright (c) 2009 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation covered by
** this license (the "Software") to use, reproduce, display, distribute,
** execute, and transmit the Software, and to prepare derivative works of the
** Software, and to permit third-parties to whom the Software is furnished to
** do so, all subject to the following:
** 
** The copyright notices in the Software and this entire statement, including
** the above license grant, this restriction and the following disclaimer,
** must be included in all copies of the Software, in whole or in part, and
** all derivative works of the Software, unless such copies or derivative
** works are solely in the form of machine-executable object code generated by
** a source language processor.
** 
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
** -LICENSE-END-
*/
//
//  SyncController.h
//  Signal Generator
//

#ifndef __SignalGenerator_H__
#define __SignalGenerator_H__

#include "DeckLinkAPI.h"

#include <QMessageBox>
#include <QWidget>
#include <QGLWidget>
#include <QMutex>
#include <QEvent>

#include "ui_SignalGenerator.h"

// Define custom event type 
const QEvent::Type ADD_DEVICE_EVENT 	= static_cast<QEvent::Type>(QEvent::User + 1);
const QEvent::Type REMOVE_DEVICE_EVENT	= static_cast<QEvent::Type>(QEvent::User + 2);

class SignalGeneratorEvent : public QEvent
{
private:
	IDeckLink* 		m_deckLink;
	
public:
	SignalGeneratorEvent( QEvent::Type type, IDeckLink* deckLinkDevice ) 
		: QEvent( type ), m_deckLink( deckLinkDevice ) { m_deckLink->AddRef(); };
	~SignalGeneratorEvent() { m_deckLink->Release(); };

	IDeckLink* deckLink() const { return m_deckLink; };
};


class Timecode
{
public:
	Timecode(int f)
		: fps(f),frames_(0),seconds_(0),minutes_(0),hours_(0)
	{
	}
	void update()
	{
		if (frames_ >= (unsigned)fps - 1)
		{
			frames_ = 0;
			seconds_++;
		}
		else
			frames_++;

		if (seconds_ >= 60)
		{
			seconds_ = 0;
			minutes_++;
		}

		if (minutes_ >= 60)
		{
			minutes_ = 0;
			hours_++;
		}
		if (hours_ >= 24)
		{
			frames_ = 0;
			seconds_ = 0;
			minutes_ = 0;
			hours_ = 0;
		}
	}
	int hours() const { return hours_; }
	int minutes() const { return minutes_; }
	int seconds() const { return seconds_; }
	int frames() const { return frames_; }
private:
	int fps;
	unsigned long frames_;
	int seconds_;
	int minutes_;
	int hours_;
};

enum OutputSignal
{
	kOutputSignalPip		= 0,
	kOutputSignalDrop		= 1
};

// Forward declarations
class CDeckLinkGLWidget;
class DeckLinkOutputDevice;
class DeckLinkDeviceDiscovery;

class SignalGenerator : public QDialog
{
	Q_OBJECT
public:
	SignalGenerator();
	~SignalGenerator();
	Ui::SignalGeneratorDialog *ui;
	CDeckLinkGLWidget *previewView;
	
	bool						running;
	DeckLinkOutputDevice* 		selectedDevice;
	DeckLinkDeviceDiscovery*	deckLinkDiscovery;
	BMDPixelFormat				pixelFormat;
	
	uint32_t					frameWidth;
	uint32_t					frameHeight;
	BMDTimeValue				frameDuration;
	BMDTimeScale				frameTimescale;
	uint32_t					framesPerSecond;
	IDeckLinkMutableVideoFrame*	videoFrameBlack;
	IDeckLinkMutableVideoFrame*	videoFrameBars;
	uint32_t					totalFramesScheduled;
	//
	OutputSignal				outputSignal;
	void*						audioBuffer;
	uint32_t					audioBufferSampleLength;
	uint32_t					audioSamplesPerFrame;
	uint32_t					audioChannelCount;
	BMDAudioSampleRate			audioSampleRate;
	uint32_t					audioSampleDepth;
	uint32_t					totalAudioSecondsScheduled;
	
	BMDTimecodeFormat			timeCodeFormat;

	void customEvent(QEvent* event);
	void closeEvent(QCloseEvent *event);

	void setup();

	void scheduleNextFrame(bool prerolling);
	void writeNextAudioSamples();
	void enableInterface(bool);

	void startRunning();
	void stopRunning();
	
	void refreshDisplayModeMenu(void);
	void refreshAudioChannelMenu(void);
	void addDevice(IDeckLink* deckLink);
	void removeDevice(IDeckLink* deckLink);
	
public slots:
	void outputDeviceChanged(int selectedDeviceIndex);
	void pixelFormatChanged(int selectedDeviceIndex);
	void toggleStart();
	
private:
	QGridLayout *layout;
	Timecode *timeCode;
};

void	FillSine (void* audioBuffer, uint32_t samplesToWrite, uint32_t channels, uint32_t sampleDepth);
void	FillColourBars (IDeckLinkVideoFrame* theFrame);
void	FillBlack (IDeckLinkVideoFrame* theFrame);
void	ScheduleNextVideoFrame (void);

#endif
