void DialogVideoPlayer::updatePlaybackStateTime(double newTimeMS) {

    currentTimeMS = newTimeMS;

    //Search for current index

    int last_index = (*p_roughM).n_rows - 1;

    int previousIndex = qMax(currentIndex, 0);

    if (p_roughM->at(previousIndex, 0) > currentTimeMS ) {
        previousIndex = 0;
    }

    int current_index = -1;

    for(int search_index = previousIndex; search_index <= last_index; search_index++) {
        double searched_time = (*p_roughM).at(search_index, 0);
        if (searched_time >= currentTimeMS) {
            //found latest frame - paint
            current_index = search_index;

            break;
        }
    }

    updatePlaybackState(current_index, false);

}
void DialogVideoPlayer::spinBoxSegmentChanged(int value) {

    int target_index = qBound(0, value, (int)segmentsM.n_rows);

    if (target_index != value) {
        ui->spinBoxSegment->setValue(target_index);
    }

    if (target_index == 0) {
        updatePlaybackState(0, true);
    } else if (target_index - 1 < (int)segmentsM.n_rows) {
        updatePlaybackState(segmentsM(FIXCOL_START,target_index - 1), true);
    }


}
void DialogVideoPlayer::spinBoxIndexChanged(int value) {
    int target_index = qBound(0, value, (int)p_roughM->n_rows - 1);

    if (target_index != value) {
        ui->spinBoxIndex->setValue(target_index);
    }

    updatePlaybackState(target_index, true);
}
void DialogVideoPlayer::mousePressEvent(QMouseEvent *mouseEvent) {
    bool leftButton = mouseEvent->buttons() & Qt::LeftButton;

    QRect timeLineRect = ui->timeLineView->geometry();
    bool onTimeLine = timeLineRect.contains(mouseEvent->pos());

    if (leftButton && onTimeLine) {
        // Set position
        double samples_over_time_line = (double)samplesPerFragment * (double)(mouseEvent->pos().x() - timeLineRect.x()) / (double)timeLineRect.width();
        int current_position = (currentFragment * samplesPerFragment) + (int)floor(samples_over_time_line);

        if (current_position > 0 && current_position < (int)p_roughM->n_rows) {
            updatePlaybackState(current_position, true);
        }

        return;
    }

    QRect fixationsRect = ui->fixationsView->geometry();
    bool onFixations = fixationsRect.contains(mouseEvent->pos());

    if (leftButton && onFixations) {
        // Set position to beginning of fixation (if on one)
        double samples_over_fixations = (double)samplesPerFragment * (double)(mouseEvent->pos().x() - fixationsRect.x()) / (double)fixationsRect.width();
        int selected_position = (currentFragment * samplesPerFragment) + (int)floor(samples_over_fixations);
        for (uword i = 0; i < p_fixAllM->n_rows  ; i++) {
            bool fixation_starts_before_selected = p_fixAllM->at(i, FIXCOL_START) <= selected_position;
            bool fixation_ends_after_selected = p_fixAllM->at(i, FIXCOL_END) >= selected_position;

            //go to start of fixation
            if (fixation_starts_before_selected && fixation_ends_after_selected) {
                updatePlaybackState(p_fixAllM->at(i, FIXCOL_START), true);
            }
        }
    }
}
void MediaController::reportControllerState()
{
    updateReadyState();
    updatePlaybackState();
}
void DialogVideoPlayer::updatePlaybackState(int index, bool resetTimeSource) {

    bool trigger_fragment_mode = settingPlayMode == PlayModeFragment &&
                                 (index >= ((currentFragment + 1) * samplesPerFragment) || index == -1);

    if (trigger_fragment_mode) {
        if (settingLoop) {
            updatePlaybackState(currentFragment * samplesPerFragment, true);
        } else {
            stopPlaying();
        }
        return;
    }

    bool trigger_whole_file_mode = settingPlayMode == PlayModeWholeFile &&
                                   (index >= (int)p_roughM->n_rows || index == -1);

    if (trigger_whole_file_mode) {
        if (settingLoop) {
            updatePlaybackState(0, true);
        } else {
            stopPlaying();
        }
        return;
    }

    bool segment_in_bounds = currentSegment > 0 && currentSegment - 1 < (int)segmentsM.n_rows;
    bool trigger_segment_mode = segment_in_bounds && settingPlayMode == PlayModeSegment &&
            (index >= segmentsM(currentSegment - 1, SEGCOL_END) || index == -1);
    if (trigger_segment_mode) {

        if (settingLoop) {
            updatePlaybackState(segmentsM(currentSegment - 1, SEGCOL_START), true);
        } else {
            stopPlaying();
        }
        return;
    }

    // Display index
    currentIndex = index;
    currentTimeMS = p_roughM->at(qMax(0, currentIndex), 0 );

    // Display time since start
    int milliseconds = currentTimeMS - firstSampleMS;
    int minutes = floor(milliseconds / 60000);
    milliseconds -= minutes * 60000;
    int seconds = floor(milliseconds / 1000);
    milliseconds -= seconds * 1000;

    ui->labelTime->setText(QString("Time (m:s:ms): %1:%2:%3").arg(minutes).arg(seconds).arg(milliseconds));
    ui->spinBoxIndex->blockSignals(true);
    ui->spinBoxIndex->setValue(currentIndex);
    ui->spinBoxIndex->blockSignals(false);

    // Calculate current fragment
    int current_fragment = currentIndex > -1 ? (int)floor((double)currentIndex / samplesPerFragment) : -1;

    if (current_fragment != currentFragment) {
        currentFragment = current_fragment;
        paintTimeLine();
        paintFixations();
    }

    ui->spinBoxFragment->blockSignals(true);
    ui->spinBoxFragment->setValue(currentFragment);
    ui->spinBoxFragment->blockSignals(false);

    // Calculate current segment
    int current_segment = 0; // 0 means at start of file
    for (uword i = 0; i < segmentsM.n_rows -1; ++i) {
        if (currentIndex >= segmentsM(i, SEGCOL_START)) {
            current_segment = i;
        }
    }

    if (currentSegment != current_segment + 1) {
        currentSegment = current_segment + 1;


        if (!ui->checkBoxMovie->isChecked()) {
            paintBackgroundImage();
        }
    }

    ui->spinBoxSegment->blockSignals(true);
    ui->spinBoxSegment->setValue(currentSegment);
    ui->spinBoxSegment->blockSignals(false);

    paintCurrentVisualizationFrame();
    paintCurrentTimeLineLineFrame();

    if (resetTimeSource) {
        if (ui->checkBoxMovie->isChecked()) {
            mediaPlayer->setPosition(currentTimeMS + movieOffsetMS - firstSampleMS);
        } else {
            clockStartTime = getMilliCount();
            playStartSampleMS = p_roughM->at(qMax(0, currentIndex), 0 );
        }
    }
}
void DialogVideoPlayer::spinBoxFragmentChanged(int value) {
    int target_index = qBound(0, value * samplesPerFragment, (int)p_roughM->n_rows - 1);
    updatePlaybackState(target_index, true);
}
void DialogVideoPlayer::loadData(GrafixParticipant* participant, mat &p_roughM_in, mat &p_smoothM_in, mat &p_fixAllM_in, mat &p_segmentsM_in) {

    _participant = participant;

    p_roughM = &p_roughM_in;
    p_smoothM = &p_smoothM_in;
    p_fixAllM = &p_fixAllM_in;

    segmentsM = p_segmentsM_in;
    if (segmentsM.n_rows == 0) {
        segmentsM.zeros(1,3);
        segmentsM(0,0) = 0;
        segmentsM(0,1) = 0;
        segmentsM(0,2) = p_roughM->n_rows - 1;
    }
    // order the segments
    uvec indices = sort_index(segmentsM.cols(1,1));
    this->segmentsM = segmentsM.rows(indices);



    secsFragment = this->_participant->GetProject()->GetProjectSetting(Consts::SETTING_SECS_FRAGMENT, Consts::ACTIVE_CONFIGURATION()).toInt();
    hz = this->_participant->GetProject()->GetProjectSetting(Consts::SETTING_HZ, Consts::ACTIVE_CONFIGURATION()).toInt();
    samplesPerFragment = secsFragment * hz;
    expWidth = this->_participant->GetProject()->GetProjectSetting(Consts::SETTING_EXP_WIDTH, Consts::ACTIVE_CONFIGURATION()).toInt();
    expHeight = this->_participant->GetProject()->GetProjectSetting(Consts::SETTING_EXP_HEIGHT, Consts::ACTIVE_CONFIGURATION()).toInt();

    if (p_smoothM->is_empty()) {
        settingPlaySmooth = false;
        ui->checkBoxSmooth->setChecked(false);
        ui->checkBoxSmooth->setEnabled(false);
    } else {
        ui->checkBoxSmooth->setChecked(true);
    }

    firstSampleMS = (*p_roughM).at(0, 0); //this is the ms of when the player first started
    currentIndex = 0;
    currentFragment = -1;
    currentSegment = 0;

    settingChanged();

    stopPlaying();

    // Load media from settings
    QString moviePath = _participant->GetProjectSetting(Consts::SETTING_MOVIE_PATH).toString();
    loadMovie(moviePath);
    QByteArray imagesPaths = _participant->GetProjectSetting(Consts::SETTING_IMAGE_PATHS).toByteArray();
    pathsImages = QJsonDocument::fromJson(imagesPaths).object().toVariantMap();
    qDebug() << pathsImages;

    updatePlaybackState(0, true);
    qDebug() << " finish loading ";

    dotSizePercentage = 5;
    ui->sliderDotSize->blockSignals(true);
    ui->sliderDotSize->setValue(dotSizePercentage * 10);
    ui->sliderDotSize->blockSignals(false);

    resizeDisplay();
}