#include "cvvideoplayer.h"
#include "ui_cvvideoplayer.h"

CvVideoPlayer::CvVideoPlayer(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::CvVideoPlayer)
{
    ui->setupUi(this);
    capture = NULL;
}

CvVideoPlayer::~CvVideoPlayer()
{
    delete ui;
}

void CvVideoPlayer::open(QString filename, PlaySchema schema)
{
    try
    {
        try
        {
            capture = new cv::VideoCapture(filename.toStdString());

            if(!capture->isOpened())
            {
                //CV_Error(CV_StsObjectNotFound, "Cannot open video capture.");
            }

            setSchema(schema);
            setPosition(0);
        }
        catch(...)
        {
            capture = NULL;
            throw;
        }

        //setPosition(0);
        currentSegmentIdx = 0;
    }
    catch(...)
    {
        close();
        throw;
    }
}

void CvVideoPlayer::close()
{
    if(capture != NULL)
    {
        //delete capture;
        capture->release(); // TODO
        capture = NULL;
    }

    schema.clear();
    frame = QImage();

    ui->frame->setAlignment(Qt::AlignCenter);
    ui->frame->setPixmap(QPixmap::fromImage(frame).scaled(ui->frame->size(), Qt::KeepAspectRatio, Qt::FastTransformation));
}

void CvVideoPlayer::setSchema(PlaySchema schema)
{
    if(schema.empty())
    {
        assert(capture != NULL);
        this->schema.clear();
        this->schema.push_back(cv::Vec2i(1, (int)capture->get(CV_CAP_PROP_FRAME_COUNT)));
    }
    else
    {
        this->schema = schema;
    }

    currentSegmentIdx = findNextSegmentIdx(getPosition());
}

int CvVideoPlayer::getPosition() const
{
    if(capture != NULL)
    {
        return (int)capture->get(CV_CAP_PROP_POS_FRAMES);
    }
    else
    {
        return -1;
    }
}

bool CvVideoPlayer::setPosition(int frame)
{
    if(capture != NULL)
    {
        frame = std::min<int>(frame, (int)capture->get(CV_CAP_PROP_FRAME_COUNT)-1);

        capture->set(CV_CAP_PROP_POS_FRAMES, frame);
        while((int)capture->get(CV_CAP_PROP_POS_FRAMES) < frame)
        {
            capture->grab();
        }

        currentSegmentIdx = findNextSegmentIdx(frame);

        readImage();

        emit positionChanged(getPosition());
        return true;
    }

    return false;
}

bool CvVideoPlayer::next()
{
    if(capture != NULL)
    {
        int currentPosition = getPosition();
        bool inCurrentSegment = currentPosition >= schema[currentSegmentIdx][0] && currentPosition <= schema[currentSegmentIdx][1];

        if(inCurrentSegment && currentPosition < schema[currentSegmentIdx][1])
        {
          bool ok = capture->grab();
          readImage();

          if(ok)
          {
              emit positionChanged(getPosition());
          }

          return ok;
        }
        else
        {
            currentSegmentIdx = findNextSegmentIdx(currentPosition+1);

            if(currentSegmentIdx == -1)
            {
                return false;
            }

            return setPosition(schema[currentSegmentIdx][0]);
        }
    }
    else
    {
        return false;
    }
}

void CvVideoPlayer::readImage()
{
    if(capture != NULL)
    {
        cv::Mat frameCv;
        if(capture->read(frameCv))
        {
            frame = matToQimage(frameCv);
            ui->frame->setAlignment(Qt::AlignCenter);
            ui->frame->setPixmap(QPixmap::fromImage(frame).scaled(ui->frame->size(), Qt::KeepAspectRatio, Qt::FastTransformation));
            //repaint();
            return;
        }
    }

    frame = QImage();
    repaint();
}

QImage CvVideoPlayer::matToQimage(cv::Mat & src)
{
    if(src.channels() == 3)
    {
        cv::cvtColor(src, src, CV_BGR2RGB);
    }
    else
    {
        cv::cvtColor(src, src, CV_GRAY2RGB);
    }

    QImage imgQt((uchar *)src.data, src.cols, src.rows, (int)src.step, QImage::Format_RGB888);
    return imgQt.copy();
}

int CvVideoPlayer::findNextSegmentIdx(int currentPos)
{
    for(int i = 0; i < (signed)schema.size(); i++)
    {
        if((schema[i][0] <= currentPos && schema[i][1] >= currentPos) || schema[i][0] > currentPos)
        {
            return i;
        }
    }

    return -1;
}

void CvVideoPlayer::resizeEvent(QResizeEvent *e)
{
    Q_UNUSED(e);

    ui->frame->setAlignment(Qt::AlignCenter);
    ui->frame->setPixmap(QPixmap::fromImage(frame).scaled(ui->frame->size(), Qt::KeepAspectRatio, Qt::FastTransformation));
}

void CvVideoPlayer::previousSegment()
{
    if(currentSegmentIdx > 0)
    {
        currentSegmentIdx--;
        setPosition(schema[currentSegmentIdx][0]-1);
    }
    else
    {
        setPosition(0);
    }
}

void CvVideoPlayer::nextSegment()
{
    if(schema.size() > 1)
    {
        if(currentSegmentIdx < (signed)schema.size()-1)
        {
            if(getPosition() >= schema[currentSegmentIdx][0])
            {
                currentSegmentIdx++;
            }

            setPosition(schema[currentSegmentIdx][0]-1);
        }
    }
    else
    {
        setPosition((int)capture->get(CV_CAP_PROP_FRAME_COUNT)-2);
    }
}
