/*
 * Copyright (c) 2011 Nokia Corporation.
 */

#include "mirrorhouse.h"
#include <QDebug>

const int FRAME_DELAY = 0;

/* ***************************************************************************
* MyVideoSurface
*/
MyVideoSurface::MyVideoSurface(QWidget* widget, VideoIF* target, QObject* parent)
    : QAbstractVideoSurface(parent)
{
    m_targetWidget = widget;
    m_target = target;
    m_imageFormat = QImage::Format_Invalid;
    m_mirrorHouseEffect = new CMirrorHouse();
}

MyVideoSurface::~MyVideoSurface()
{
    delete m_mirrorHouseEffect;
}

bool MyVideoSurface::start(const QVideoSurfaceFormat &format)
{
    m_frameDelayCount = FRAME_DELAY;
    m_videoFormat = format;
    const QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat());
    const QSize size = format.frameSize();

    if (imageFormat != QImage::Format_Invalid && !size.isEmpty()) {
        m_imageFormat = imageFormat;
        QAbstractVideoSurface::start(format);
        return true;
    } else {
        return false;
    }
}

bool MyVideoSurface::present(const QVideoFrame &frame)
{
    m_frame = frame;
    if (surfaceFormat().pixelFormat() != m_frame.pixelFormat() ||
            surfaceFormat().frameSize() != m_frame.size()) {
        stop();
        return false;
    } else {

        // Small delay for showing/mirroring process frames
        // TODO: is this needed Tuomo?
        m_frameDelayCount--;
        if (m_frameDelayCount<0) {
            if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) {
                // Source
                //m_sourceImage = QImage(m_frame.bits(),m_frame.width(),m_frame.height(),
                //        m_frame.bytesPerLine(),
                //        m_imageFormat);
                //m_mirrorHouseEffect->setSource( (unsigned int*)m_sourceImage.bits(),
                //                               m_sourceImage.width(),m_sourceImage.height(),
                //                               m_sourceImage.bytesPerLine()/4);
                m_mirrorHouseEffect->setSource( (unsigned int*)m_frame.bits(),
                                               m_frame.width(),m_frame.height(),
                                               m_frame.bytesPerLine()/4);

                // Target
                if (m_targetImage.width()==0) {
                    m_targetImage = QImage( m_frame.width(), m_frame.height(), m_imageFormat);
                    m_mirrorHouseEffect->setTarget( (unsigned int*)m_targetImage.bits(),
                                                   m_targetImage.width(),m_targetImage.height(),
                                                   m_targetImage.bytesPerLine()/4);
                }
                m_mirrorHouseEffect->setMirrorTransform(eBUBBLES);

                // Do mirroring
                m_mirrorHouseEffect->setHighQuality(false);
                m_mirrorHouseEffect->process();

                // Update widget
                m_target->updateVideo();
                m_frameDelayCount = FRAME_DELAY;

                m_frame.unmap();
            }
        }
        return true;
    }
}

void MyVideoSurface::paint(QPainter *painter)
 {
     QRect r = m_targetWidget->rect();
     if (!m_targetImage.isNull()) {
         QPoint centerPic((qAbs(r.size().width() - m_targetImage.size().width())) / 2, (qAbs(
             r.size().height() - m_targetImage.size().height())) / 2);

        // For testing unprocessed camera picture
        //painter->drawImage(centerPic,m_sourceImage);

        // Paint mirrored image
        painter->drawImage(centerPic,m_targetImage);
     }
 }

QList<QVideoFrame::PixelFormat> MyVideoSurface::supportedPixelFormats(
            QAbstractVideoBuffer::HandleType handleType) const
{
    if (handleType == QAbstractVideoBuffer::NoHandle) {
        return QList<QVideoFrame::PixelFormat>()
                << QVideoFrame::Format_RGB32;
//                << QVideoFrame::Format_ARGB32
//                << QVideoFrame::Format_ARGB32_Premultiplied
//                << QVideoFrame::Format_RGB565
//                << QVideoFrame::Format_RGB555;
    } else {
        return QList<QVideoFrame::PixelFormat>();
    }
}




/* ***************************************************************************
* MirrorHouse
*/
MirrorHouse::MirrorHouse(QWidget *parent) :
    QMainWindow(parent)
{
    m_myVideoSurface = 0;
    m_showViewFinder = false;

    m_camera = 0;
    m_devices = QCamera::availableDevices();
    m_deviceId = 0;

    m_systemScreenSaver = new QSystemScreenSaver(this);
    m_systemScreenSaver->screenSaverInhibited();

    // Opitimizations for screen update and drawing qwidget
    setAutoFillBackground(false);
    //setAttribute(Qt::WA_NoSystemBackground, true);
    //setAttribute(Qt::WA_PaintOnScreen, true);

    QPalette palette = this->palette();
    palette.setColor(QPalette::Background, Qt::black);
    setPalette(palette);
    
    // Enable camera after 1s, so that the application is started
    // and widnget is created to landscape orientation
    QTimer::singleShot(1000,this,SLOT(enableCamera()));
}

MirrorHouse::~MirrorHouse()
{
#ifndef __WINS__
    if (m_myVideoSurface) {
        m_myVideoSurface->stop();
    }
    if (m_camera) {
        m_camera->stop();
    }
    delete m_camera;
#endif
}

void MirrorHouse::mousePressEvent(QMouseEvent *e)
{
    QMainWindow::mousePressEvent(e);

    restartCamera();
}


void MirrorHouse::enableCamera()
{
#ifndef __WINS__
    if (m_deviceId > m_devices.count()-1) {
        m_deviceId = 0;
    }
    m_camera = new QCamera(m_devices[m_deviceId]);
    m_deviceId++;
    connect(m_camera, SIGNAL(error(QCamera::Error)), this, SLOT(error(QCamera::Error)));

    // Own video output drawing
    QMediaService* ms = m_camera->service();
    QVideoRendererControl* vrc = ms->requestControl<QVideoRendererControl*>();
    m_myVideoSurface = new MyVideoSurface(this,this,this);
    vrc->setSurface(m_myVideoSurface);

    // Start camera
    if (m_camera->state() == QCamera::ActiveState) {
        m_camera->stop();
    }
    m_camera->start();
    m_showViewFinder = true;
#endif
}

void MirrorHouse::restartCamera()
{
    if (m_camera) {
        m_camera->stop();
    }
    delete m_camera;

    QTimer::singleShot(3000,this,SLOT(enableCamera()));
}

void MirrorHouse::error(QCamera::Error e)
{
    switch (e) {
    case QCamera::NoError:
    {
        break;
    }
    case QCamera::CameraError:
    {
        QMessageBox::warning(this, "QMirrorHouse", "General Camera error");
        break;
    }
    case QCamera::InvalidRequestError:
    {
        QMessageBox::warning(this, "QMirrorHouse", "Camera invalid request error");
        break;
    }
    case QCamera::ServiceMissingError:
    {
        QMessageBox::warning(this, "QMirrorHouse", "Camera service missing error");
        break;
    }
    case QCamera::NotSupportedFeatureError :
    {
        QMessageBox::warning(this, "QMirrorHouse", "Camera not supported error");
        break;
    }
    };
}

void MirrorHouse::updateVideo()
{
    if (m_showViewFinder) {
        repaint();
    }
}

void MirrorHouse::paintEvent(QPaintEvent *event)
{
    //QMainWindow::paintEvent(event);
    QPainter painter(this);
    if (m_showViewFinder && m_myVideoSurface && m_myVideoSurface->isActive()) {
        // Show view finder
        m_myVideoSurface->paint(&painter);
    } else {
        // Draw black
        painter.fillRect(event->rect(), palette().background());
    }
}

