/* -LICENSE-START-
 ** Copyright (c) 2015 Blackmagic Design
 **  
 ** Permission is hereby granted, free of charge, to any person or organization 
 ** obtaining a copy of the software and accompanying documentation (the 
 ** "Software") to use, reproduce, display, distribute, sub-license, 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, in 
 ** accordance with:
 ** 
 ** (1) if the Software is obtained from Blackmagic Design, the End User License 
 ** Agreement for the Software Development Kit (“EULA”) available at 
 ** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
 ** 
 ** (2) if the Software is obtained from any third party, such licensing terms 
 ** as notified by that third party,
 ** 
 ** and all subject to the following:
 ** 
 ** (3) 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.
 ** 
 ** (4) 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.
 ** 
 ** A copy of the Software is available free of charge at 
 ** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
 ** 
 ** -LICENSE-END-
 */

#include "DeckLinkDevice.h"
#include "ControllerImp.h"

#include <QMessageBox>
#include <QObject>

#include <DeckLinkAPI.h>

static const int kMegabit = 1000000;

ControllerImp::ControllerImp()
{
	m_currentBitrate = 20 * kMegabit;
	m_selectedDevice = -1;
	m_selectedMode   = 0;
}

ControllerImp::~ControllerImp()
{

}

void ControllerImp::init(QObject* delegate)
{
	m_uiDelegate = delegate;

	m_deckLinkDiscovery = new DeckLinkDeviceDiscovery(this);
	m_deckLinkDiscovery->Enable();

	bool connected = QObject::connect(this, SIGNAL(recordingStarted(QString, uint32_t)), m_uiDelegate, SLOT(recordingStarted(QString, uint32_t)));
	Q_ASSERT(connected);
	connected = QObject::connect(this, SIGNAL(recordingFinished()), m_uiDelegate, SLOT(recordingFinished()));
	Q_ASSERT(connected);
	connected = QObject::connect(this, SIGNAL(displayErrorMessage(QString,QString)), this, SLOT(onDisplayErrorMessage(QString, QString)));
	Q_ASSERT(connected);
	connected = QObject::connect(this, SIGNAL(restartCapture(uint32_t)), this, SLOT(restartCaptureRequested(uint32_t)));
	Q_ASSERT(connected);
}

int ControllerImp::changeTargetRate(int rate)
{
	m_currentBitrate = rate;
	return kNoError;
}

int ControllerImp::startStopCapture()
{
	return startStopCapture(m_selectedMode);
}

int ControllerImp::startStopCapture(uint32_t selectedMode)
{
	if (m_selectedDevice < 0)
		return kInvalidOpError;

	DeckLinkDevice* device = m_deviceList[m_selectedDevice];
	if (device->isCapturing())
		stopCapture();
	else
		startCapture(selectedMode);

	return kNoError;
}

int ControllerImp::startCapture(uint32_t mode)
{
	m_selectedMode = mode;
	DeckLinkDevice* device = m_deviceList[m_selectedDevice];
	if (device->isCapturing())
		return kInvalidOpError;

	if (!device->startCapture(m_selectedMode, m_currentBitrate))
	{
		m_selectedMode = device->defaultMode();
		return kUnknownError;
	}

	emit recordingStarted(device->getDisplayModeName(m_selectedMode), device->getDisplayModeFrameRate(m_selectedMode));

	return kNoError;
}

int ControllerImp::stopCapture(bool deleteFile)
{
	if (m_selectedDevice < 0)
		return kInvalidOpError;

	DeckLinkDevice* device = m_deviceList[m_selectedDevice];
	if (device->isCapturing())
	{
		device->stopCapture(deleteFile);
		emit recordingFinished();
	}
	return kNoError;
}

void ControllerImp::restartCaptureRequested(uint32_t mode)
{
	DeckLinkDevice* device = m_deviceList[m_selectedDevice];
	if (device->isCapturing())
		stopCapture(true);
	startCapture(mode);
}

void ControllerImp::newDeviceSelected()
{
	m_selectedDevice = 0;
	m_selectedMode = m_deviceList[m_selectedDevice]->defaultMode();
}

void ControllerImp::addDevice(IDeckLink* deckLink)
{
	DeckLinkDevice* device = new DeckLinkDevice(this, deckLink);

	if (!device->init())
	{
		showErrorMessage(QString("Error initialising your %1 for encoding").arg(device->getDeviceName()), "This application is unable to initialise your device");
		device->Release();
		return;
	}

	m_deviceList.push_back(device);
	if (m_deviceList.size() == 1)
	{
		newDeviceSelected();
	}
}

void ControllerImp::removeDevice(IDeckLink* deckLink)
{
	DeviceList::iterator deviceToRemove;
	for (deviceToRemove = m_deviceList.begin(); deviceToRemove != m_deviceList.end(); ++deviceToRemove)
	{
		if ((*deviceToRemove)->m_deckLink == deckLink)
			break;
	}
	if (deviceToRemove == m_deviceList.end())
		return;

	int deviceIndex = std::distance(m_deviceList.begin(), deviceToRemove);
	if (m_selectedDevice == deviceIndex)
		stopCapture();

	DeckLinkDevice* deviceRemoved = *deviceToRemove;
	m_deviceList.erase(deviceToRemove);

	if (m_deviceList.size() == 0)
		m_selectedDevice = -1;
	else if (m_selectedDevice == deviceIndex)
		newDeviceSelected();

	deviceRemoved->Release();
}

void ControllerImp::showErrorMessage(const QString& title, const QString& message)
{
	emit displayErrorMessage(title, message);
}

bool ControllerImp::shouldRestartCaptureWithNewVideoMode()
{
	return false;
}

void ControllerImp::selectDetectedVideoModeWithIndex(uint32_t index)
{
	emit restartCapture(index);
}

void ControllerImp::onDisplayErrorMessage(const QString& title, const QString& message)
{
	QMessageBox msgBox;
	msgBox.setIcon(QMessageBox::Warning);
	msgBox.setWindowTitle(title);
	msgBox.setText(message);
	msgBox.exec();
}
