<template>
    <div class="splits-root" v-bind:class="['state-' + state]">
        <div class="splits">
            <div v-for="(segment, index) in segments" :key="index" v-bind:class="[
                                            'split',
                                            {['previous-' + (currentSegment - index)]: index < currentSegment},

                                            {'visible':
                                                (currentSegment + visibleSegments) >= segments.length &&
                                                index >= segments.length - visibleSegments - 1 && index < currentSegment
                                                ||
                                                index > currentSegment &&
                                                index <= currentSegment + visibleSegments
                                            },
                                            {'current': index === currentSegment},

                                            {['next-' + (currentSegment - index)]: (currentSegment - index) > 0 && index > currentSegment},

                                            {'skipped': segment.skipped},
                                            {'first': index === 0},
                                            {'final': index === segments.length - 1},
                                            {'new-best-time': index < currentSegment && segment.previousBestTime > segment.personalBest},
                                            {'new-best-segment': index < currentSegment && segment.previousBestSegment > segment.overallBest}
                                        ]">
                <span class="name">{{ segment.name }}</span>
                <span class="seperator"></span>
                <span class="time">{{ typeof segment.timeString === 'undefined' ? '' : segment.timeString }}</span>
                <span class="best-time">{{ typeof segment.personalBestString === 'undefined' ? '' : 'PB: ' + segment.personalBestString }}</span>
                <span class="best-segment">{{ typeof segment.overallBestString === 'undefined' ? '' : 'OB: ' + segment.overallBestString }}</span>
            </div>
        </div>
        <p class="time total-time">
            <span class="text">Total Time:</span>
            <span>{{ totalTimeString }}</span>
        </p>
        <button v-on:click="split()">{{ state !== 'stoped' ? 'Split' : 'Start' }}</button>
        <button v-on:click="reset()">Reset</button>
        <button v-on:click="pause()">{{ state === 'paused' ? 'Unpause' : 'Pause' }}</button>
        <button v-on:click="skipSplit()">Skip Split</button>
        <button v-on:click="revertSplit()">Revert Button</button>
    </div>
</template>

<script>
import Vue from 'vue';
import { dialog } from 'electron';
import * as now from 'performance-now';
import * as moment from 'moment';

// Possible states of the Splits
const STOPED = 'stoped';
const RUNNING = 'running';
const PAUSED = 'paused';
const FINISHED = 'finished';

/*
  SEGMENT
  ---------------------------

  - name: Name of the Split which is being displayed
  - startTime: Internal starting time of the segment
  - time: Time in milliseconds for this segment
  - timeString: String that represents the time and which is being displayed

  - personalBest: Personal Best time in milliseconds
  - personalBestString: String that represents the time and which is being displayed
  - hasNewPersonalBest: If the segment has a new personal-best. The Object must have a previosPersonalBest property
  - previousPersonalBest: Time of the previous personal-best

  - overallBest: Overall Best time in milliseconds
  - overallBestString: String that represents the time and which is being displayed
  - hasNewOverallBest: If the segment has a new overall-best. The Object must have a previousOverallBest property
  - previousOverallBest: Time of the previous overall-best

  - done: If the segment has been passed (Used to know if it should be resetted)
  - skipped: If the segment has been skipped
*/

const Splits = {
    data() {
        return {
            // Status the splits are currently in
            // stoped - Completely reseted
            // running - Time is currently running
            // finished - Last segement just got finished, but still running since potential of wrong splitting
            // paused - It's paused, time from the pause time on is being ignored
            state: STOPED,

            // Time when the split started
            segmentStartTime: 0,

            // Time when the Timer started
            // Only used for internal calculations
            totalStartTime: 0,
            // Strings which are getting displayed
            totalTimeString: undefined,

            // When the pause was initiated
            pauseStartTime: 0,
            // Amount of pause for this segment
            pauseSegmentTime: 0,
            // Total amount of paused time
            pauseTotalTime: 0,

            // Index of the current Segment
            currentSegment: 0,
            // Amount of previous Splits should be visible
            visibleSegments: 3,

            // If the User had a new best-time
            hasBestTime: false,
            // If the User had a new best-segment
            hasBestSegment: false,

            // List of segments
            segments: [
                {
                    // Name of the Segment
                    name: '1st Split',
                    // Personal Best time in ms
                    personalBest: 1000,
                    // Best Segment/Overall time in ms
                    overallBest: 750,
                },
                {
                    name: '2nd Split',
                },
                {
                    name: '3rd Split',
                },
                {
                    name: '4th Split',
                },
                {
                    name: '5th Split',
                },
                {
                    name: '6th Split',
                },
                {
                    name: '7h Split',
                },
                {
                    name: 'final Split',
                }
            ],
        }
    },
    created: function() {
        // Setup Global-Hotkeys
        if (typeof this.$electron !== 'undefined') {
            this.$electron.ipcRenderer.on('splits-split', () => {
                this.split()
            })
            this.$electron.ipcRenderer.on('splits-pause', () => {
                this.pause()
            })
            this.$electron.ipcRenderer.on('splits-reset', () => {
                this.reset()
            })
        }
    },
    methods: {
        start() {
            this.currentSegment = this.pauseTotalTime = this.pauseSegmentTime = 0;
            this.totalStartTime = this.segmentStartTime = now();
            this.state = RUNNING;
            this.startTimer();
        },
        split() {
            switch (this.state) {
                case STOPED:
                    this.start();
                    return;
                case FINISHED:
                    this.reset();
                    return;
                case RUNNING:
                    break;
                case PAUSED:
                    this.unpause();
                    break;
                default:
                    return;
            }

            const time = now() - this.segmentStartTime - this.pauseSegmentTime;
            const segment = this.segments[this.currentSegment];

            segment.startTime = this.segmentStartTime;
            segment.done = true;
            segment.time = time;
            segment.timeString = this.formatTime(time);

            if (typeof segment.personalBest === 'undefined' || segment.personalBest > time) {
                // Backup of the previous time to be able to revert it
                segment.previousPersonalBest = segment.personalBest;
                segment.personalBest = time;
                segment.personalBestString = this.formatTime(time);
                segment.hasNewPersonalBest = true;
                this.hasPersonalBest = true;
            } else {
                segment.hasNewPersonalBest = false;
            }

            if (typeof segment.overallBest === 'undefined' || segment.overallBest > time) {
                // Backup of the previous time to be able to revert it
                segment.previousOverallBest = segment.overallBest;
                segment.overallBest = time;
                segment.overallBestString = this.formatTime(time);
                segment.hasNewOverallBest = true;
                this.hasOverallBest = true;
            } else {
                segment.hasNewOverallBest = false;
            }

            // Check if it is the last split
            if ((this.currentSegment + 1) >= this.segments.length) {
                this.finish();
                return;
            }

            this.pauseSegmentTime = 0;
            this.currentSegment++;
            this.segmentStartTime = now();
        },
        pause() {
            if (this.state === PAUSED) {
                this.unpause();
                return;
            }
            this.state = PAUSED;
            this.pauseStartTime = now();
        },
        unpause() {
            const pause = (now() - this.pauseStartTime);
            this.pauseSegmentTime += pause;
            this.pauseTotalTime += pause;
            this.pauseStartTime = 0;
            this.state = RUNNING;
            this.startTimer();
        },
        revertSplit() {
            if (this.state === RUNNING) {
                if (this.currentSegment >= 1) {
                    const segment = this.segments[this.currentSegment];
                    segment.time = 0;
                    segment.timeString = undefined;

                    // Revert PB
                    if (segment.hasNewPersonalBest) {
                        segment.personalBest = segment.previousPersonalBest;
                        segment.personalBestString = this.formatTime(segment.personalBest);
                        segment.previousPersonalBest = undefined;
                        segment.hasNewPersonalBest = false;
                    }

                    // Revert OB
                    if (segment.hasNewOverallBest) {
                        segment.overallBest = segment.previousOverallBest;
                        segment.overallBestString = this.formatTime(segment.overallBest);
                        segment.previousOverallBest = undefined;
                        segment.hasNewOverallBest = false;
                    }

                    this.currentSegment--;
                    const n = this.segments[this.currentSegment];
                    this.segmentStartTime = n.startTime;
                }
            }
        },
        skipSplit() {
            if (this.state === RUNNING) {
                if (this.currentSegment + 1 < this.segments.length) {
                    const segment = this.segments[this.currentSegment];
                    segment.time = 0;
                    segment.timeString = undefined;
                    segment.skipped = true;
                    segment.done = true;
                    segment.startTime = this.segmentStartTime;
                    this.currentSegment++;
                }
            }
        },
        finish() {
            this.state = FINISHED;
            this.segments.forEach(segment => {
                segment.previousPersonalBest = segment.personalBest;
                segment.previousOverallBest = segment.overallBest;
            });
        },
        reset() {
            if (this.state === STOPED) {
                return;
            }
            if ((!this.hasOverallBest && !this.hasPersonalBest) || this.state === FINISHED) {
                this.performReset();
                return;
            }

            this.pause();
            this.$electron.ipcRenderer.send('open-message', {
                type: 'question',
                buttons: ['Save', 'Discard', 'Abort'],
                title: 'Reset?',
                message: `You got a new best-time or best-segment!\n` +
                    `Do you want to save the new times, discard it or abort the reset?`
            });
            this.$electron.ipcRenderer.once('open-message-response', (event, response) => {
                this.unpause();
                switch (response) {
                    case 0:
                        this.applyingReset();
                        break;
                    case 1:
                        this.discardingReset();
                        break;
                    case 2:
                        break;
                }
            });
        },
        applyingReset() {
            this.currentSegment = 0;
            this.state = STOPED;
            this.totalStartTime = undefined;
            this.totalTimeString = undefined;
            this.pauseSegmentTime = this.pauseTotalTime = 0;

            this.segments.forEach(segment => {
                segment.skipped = false;
                segment.done = false;

                segment.startTime = undefined;
                segment.time = undefined;
                segment.timeString = undefined;

                segment.hasNewPersonalBest = false;
                segment.previosPersonalBest = undefined;
                segment.hasNewOverallBest = false;
                segment.previousOverallBest = undefined;
            })
        },
        discardingReset() {
            this.currentSegment = 0;
            this.state = STOPED;
            this.totalStartTime = undefined;
            this.totalTimeString = undefined;
            this.pauseSegmentTime = this.pauseTotalTime = 0;

            this.segments.forEach(segment => {
                segment.skipped = false;
                segment.startTime = undefined;
                segment.time = undefined;
                segment.timeString = undefined;

                if (segment.done) {
                    segment.done = false;

                    if (segment.hasNewPersonalBest) {
                        segment.personalBest = segment.previousPersonalBest;
                        segment.personalBestString = this.formatTime(segment.personalBest);
                        segment.previousPersonalBest = undefined;
                        segment.hasNewPersonalBest = false;
                    }

                    if (segment.hasNewOverallBest) {
                        segment.overallBest = segment.previousOverallBest;
                        segment.overallBestString = this.formatTime(segment.overallBest);
                        segment.previousOverallBest = undefined;
                        segment.hasNewOverallBest = false;
                    }
                }
            })
        },
        getTimeObject(time) {
            return {
                hours: Math.trunc(time / 3600000),
                minutes: Math.trunc(time / 60000),
                seconds: Math.trunc(time / 1000),
                milliseconds: time % 1000
            };
        },
        formatTime(time, format) {
            if (time === null || typeof time === 'undefined') {
                return '';
            }
            if (typeof format === 'undefined') {
                format = 'H:mm:ss.SSS';
            }
            const obj = this.getTimeObject(time);
            if (time < 1000 && obj.seconds > 0) {
                console.log(obj)
            }
            return moment(obj).format(format)
        },
        startTimer() {
            const func = () => {
                if (this.state !== RUNNING) {
                    return;
                }

                const total = now() - this.totalStartTime - this.pauseTotalTime;
                this.totalTimeString = this.formatTime(total);

                const segment = this.segments[this.currentSegment];
                const s = now() - this.segmentStartTime - this.pauseSegmentTime;
                segment.time = s;
                segment.timeString = this.formatTime(s);

                setTimeout(func, 1);
            }
            func()
        },
    }
}

export default Splits;
</script>

<style lang="scss">
@import '../styles/config.scss';

.splits-root {
    &.state-stoped {
        .splits {
            .split {
                .best-time,
                .best-segment {
                    display: none;
                }
            }
        }
    }

    .splits {
        display: flex;
        flex-direction: column;

        .split {
            flex: 1 1 100%;
            float: left;
            padding: 10px 25px;
            display: none;

            &.current {
                display: block;
                background: $color-primary;
            }

            &.visible {
                display: block;
            }

            &.final {
                background: $color-secondary;
            }

            .best-time,
            .best-segment {
                display: none;
            }
        }
    }
}
</style>
