<!DOCTYPE html>
<html lang="fr">
<head>
    <title>Obscreen</title>
    <meta name="robots" content="noindex, nofollow">
    <meta name="google" content="notranslate">
    <link rel="shortcut icon" href="{{ STATIC_PREFIX }}/favicon.ico">
    {% if slide_animation_enabled.eval() %}
        <link rel="stylesheet" href="{{ STATIC_PREFIX }}css/lib/animate.min.css" />
    {% endif %}
    <style>
        html, body { margin: 0; padding: 0; height: 100%; overflow: hidden; background-color: white; display: flex; flex-direction: row; justify-content: center; align-items: center; }
        .slide { display: flex; flex-direction: row; justify-content: center; align-items: center; background: black; }
        .slide, iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none; padding-top: 0; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; }
        .slide iframe { background: white; }
        .slide img, .slide video { height: 100%; }
    </style>
    <script type="application/javascript" src="{{ STATIC_PREFIX }}js/lib/is-cron-now.js"></script>
</head>
<body>
<div id="IntroSlide" class="slide" style="z-index: 10000;">
    {% if default_slide_duration.eval() > 0 %}
        <iframe src="/player/default"></iframe>
    {% endif %}
</div>
<div id="CronSlide" class="slide" style="z-index: 0;">

</div>
<div id="FirstSlide" class="slide slide-loop" style="z-index: 500;">

</div>
<div id="SecondSlide" class="slide slide-loop" style="z-index: 1000;">

</div>

<script type="text/javascript">
    // Backend config
    var items = {{items | safe}};
    var introDuration = {{ default_slide_duration.eval() * 1000 }};
    var playlistCheckResolutionMs = {{ polling_interval.eval() * 1000 }};

    // Backend flag updates
    var needHardRefresh = null;

    // Frontend config
    var syncWithTime = items['time_sync'];
    var tickRefreshResolutionMs = 100;

    // Frontend flag updates
    var hasMoveOnce = false;
    var forcePreload = false;

    // Player states infos
    var PLAY_STATE_PLAYING = 0, PLAY_STATE_PAUSE = 1;
    var playState = PLAY_STATE_PLAYING;
    var isPlaying = function() {return playState === PLAY_STATE_PLAYING;};
    var isPaused = function() {return playState === PLAY_STATE_PAUSE;};
    var pauseClockValue = null;

    // Animations
    var animate = {{ 'true' if slide_animation_enabled.eval() else 'false' }};
    var animate_speed = "animate__{{ slide_animation_speed.eval()|default("normal") }}";
    var animation_speed_duration = {{ animation_speed_duration[slide_animation_speed.eval()] if slide_animation_enabled.eval() else 0 }};
    var animate_transitions = [
        "animate__{{ slide_animation_entrance_effect.eval()|default("fadeIn") }}",
        "animate__{{ slide_animation_exit_effect.eval()|default("none") }}"
    ];

    // Slide flow management
    var SLIDE_TOP_Z = '1000';
    var SLIDE_BOTTOM_Z = '500';
    var clockValue = 0;
    var curItemIndex = -1;
    var secondsBeforeNext = 0;
    var nextReady = true;
    var introSlide = document.getElementById('IntroSlide');
    var cronSlide = document.getElementById('CronSlide');
    var firstSlide = document.getElementById('FirstSlide');
    var secondSlide = document.getElementById('SecondSlide');
    var curSlide = secondSlide;
    var nextSlide = firstSlide;
    var cronItemIndex = null;

    // Functions
    var itemCheck = setInterval(function () {
        fetch('/player/playlist' + (items['playlist_id'] ? '/use/'+items['playlist_id'] : '')).then(function(response) {
            if (response.ok) {
                return response.json();
            }
        }).then(function(data) {
            items = data;

            if (needHardRefresh === null) {
                needHardRefresh = items.hard_refresh_request;
            } else if (needHardRefresh != items.hard_refresh_request) {
                document.location.reload();
            }
        }).catch(function(err) {
            console.error(err);
        });
    }, playlistCheckResolutionMs);

    var getLoopDuration = function() {
        let totalDuration = 0;
        for (var i = 0; i < items.loop.length; i++) {
            var item = items.loop[i];
            totalDuration += safe_duration(item);
        }
        return totalDuration;
    };

    var resume = function() {
        playState = PLAY_STATE_PLAYING;
    };

    var play = function() {
        resume();
    };

    var pause = function() {
        pauseClockValue = clockValue;
        playState = PLAY_STATE_PAUSE;
    };

    var stop = function() {
        pause();
    };

    var seek = function(timeInSeconds) {
        if (forcePreload) {
            return;
        }

        if (syncWithTime) {
            return console.warn('You can\'t seek with synced playlists');
        }

        var maxDuration = getLoopDuration();

        if (timeInSeconds > maxDuration) {
            timeInSeconds = maxDuration - 1;
            console.warn('Max duration is ' + timeInSeconds + ' seconds');
        }

        if (timeInSeconds < 0) {
            timeInSeconds = 0;
        }

        clockValue = timeInSeconds * 1000;
        forcePreload = true;
        pause();
    };

    var lookupPreviousItem = function() {
        return (curItemIndex - 1 < 0) ? items.loop[items.loop.length - 1] : items.loop[curItemIndex - 1];
    };

    var lookupNextItem = function() {
        return (curItemIndex + 1 >= items.loop.length) ? items.loop[0] : items.loop[curItemIndex + 1];
    };

    var lookupCurrentItem = function() {
        return items.loop[curItemIndex];
    }

    var getEmptySlide = function() {
        return Array.from(document.getElementsByClassName('slide-loop')).filter(slide => slide.innerHTML.replaceAll(/\s/g,'') === '')[0];
    };

    var refreshSlidesOrder = function() {
        curSlide = Array.from(document.getElementsByClassName('slide')).filter(function(slide) {
            return getComputedStyle(slide).zIndex === SLIDE_TOP_Z;
        })[0];
        nextSlide = Array.from(document.getElementsByClassName('slide')).filter(function(slide) {
            return getComputedStyle(slide).zIndex === SLIDE_BOTTOM_Z;
        })[0];
        //console.log("top is", SLIDE_TOP_Z, curSlide, "bottom is", SLIDE_BOTTOM_Z, nextSlide)
    };

    var safe_duration = function(item) {
        if (!item) {
            return tickRefreshResolutionMs/1000;
        }
        return item.duration + Math.ceil(animation_speed_duration/1000);
    };

    var main = function() {
        setTimeout(function() {
            introSlide.remove();
            setInterval(checkAndMoveSlide, tickRefreshResolutionMs);
            setInterval(checkAndMoveCron, 1000);
        }, introDuration);
    };

    var preloadSlide = function(slide, item) {
        //console.log('Preload', slide, item.name)
        var element = document.getElementById(slide);
        var callbackReady = function() {};
        loadContent(element, callbackReady, item);
    };

    var tickClockValue = function() {
        if (isPaused()) {
            return pauseClockValue;
        }
        if (syncWithTime) {
            clockValue = Date.now();
        } else {
            clockValue += tickRefreshResolutionMs;
        }
    };

    function checkAndMoveSlide() {
        tickClockValue();
        var timeInCurrentLoop = (clockValue/1000) % getLoopDuration();
        var accumulatedTime = 0;

        for (var i = 0; i < items.loop.length; i++) {
            var item = items.loop[i];

            if (i === curItemIndex) {
                secondsBeforeNext = accumulatedTime + safe_duration(item) - timeInCurrentLoop;
                //console.log("remaining:", secondsBeforeNext, "clock:",clockValue, curItemIndex);
            }

            if (timeInCurrentLoop < accumulatedTime + safe_duration(item)) {

                if (curItemIndex !== i) {
                    //console.log('change to ', i , item.name)
                    curItemIndex = i;

                    var emptySlide = getEmptySlide();
                    if ((emptySlide && !hasMoveOnce) || forcePreload) {
                        //console.log('init preload');
                        var slide = emptySlide ? emptySlide : nextSlide;
                        preloadSlide(slide.attributes['id'].value, item);

                        if (!hasMoveOnce && syncWithTime) {
                            if (accumulatedTime + safe_duration(item) - timeInCurrentLoop < 1) {
                                // Prevent glitch when syncWithTime for first init
                                continue;
                            }
                        }

                        hasMoveOnce = true;
                    }
                    moveToNextSlide();
                }
                break;
            }
            accumulatedTime += safe_duration(item);
        }
    }

    function moveToNextSlide() {
        refreshSlidesOrder();
        nextSlide.style.zIndex = SLIDE_TOP_Z; // first
        curSlide.style.zIndex = SLIDE_BOTTOM_Z; // second

        //console.log("curSlide", curSlide.attributes['id'].value, curSlide.style.zIndex, "to", "next", nextSlide.attributes['id'].value, nextSlide.style.zIndex);
        //console.log("###");

         var loadingNextSlide = function () {
            if (forcePreload) {
                forcePreload = false;
                play();
            }

            if (isPaused() && !syncWithTime) {
                return setTimeout(loadingNextSlide, 500);
            }

            refreshSlidesOrder();
            preloadSlide(nextSlide.attributes['id'].value, lookupNextItem());
        };

        if (animate) {
            nextSlide.classList.add('animate__animated', animate_transitions[0], animate_speed);
            nextSlide.onanimationend = function() {
                nextSlide.classList.remove(animate_transitions[0], animate_speed);
                loadingNextSlide();
            };

            curSlide.classList.add('animate__animated', animate_transitions[1], animate_speed);
            curSlide.onanimationend = function() {
                curSlide.classList.remove(animate_transitions[1], animate_speed);
            };
        } else {
            loadingNextSlide();
        }
    }

    function loadContent(element, callbackReady, item) {
        switch (item.type) {
            case 'url':
                loadUrl(element, callbackReady, item);
                break;
            case 'picture':
                loadPicture(element, callbackReady, item);
                break;
            case 'video':
                loadVideo(element, callbackReady, item);
                break;
            case 'youtube':
                loadYoutube(element, callbackReady, item);
                break;
            default:
                loadUrl(element, callbackReady, item);
                break;
        }
    }

    function loadUrl(element, callbackReady, item, delay) {
        element.innerHTML = `<iframe src="${item.location}"></iframe>`;
        callbackReady(function () {});
    }

    function loadPicture(element, callbackReady, item) {
        element.innerHTML = `<img src="/${item.location}" alt="" />`;
        callbackReady(function () {});
    }

    function loadYoutube(element, callbackReady, item) {
        element.innerHTML = `youtube`;
        callbackReady(function () {});

        var loadingDelayMs = 1000;
        var delayNoisyContentJIT = Math.max(100, (lookupCurrentItem().duration * 1000) - loadingDelayMs);
        delayNoisyContentJIT = lookupCurrentItem().id !== item.id ? delayNoisyContentJIT : 0;

        var autoplayLoader = function() {
            if (secondsBeforeNext * 1000 > loadingDelayMs) {
                return setTimeout(autoplayLoader, 500);
            }

            if (element.innerHTML === 'youtube') {
                element.innerHTML = `<iframe src="https://www.youtube.com/embed/${item.location}?version=3&autoplay=1&showinfo=0&controls=0&modestbranding=1&fs=1&rel=0" frameborder="0" allow="autoplay" allowfullscreen></iframe>`;
            }
        }
        setTimeout(autoplayLoader, delayNoisyContentJIT);
    }

    function loadVideo(element, callbackReady, item) {
        element.innerHTML = `<video><source src=/${item.location} type="video/mp4" /></video>`;
        var video = element.querySelector('video');
        callbackReady(function () {});

        var loadingDelayMs = 1000;
        var delayNoisyContentJIT = Math.max(100, (lookupCurrentItem().duration * 1000) - loadingDelayMs);
        delayNoisyContentJIT = lookupCurrentItem().id !== item.id ? delayNoisyContentJIT : 0;

        video.addEventListener('loadedmetadata', function () {
            if (item.duration !== video.duration) {
                console.warn('Given duration ' + item.duration + 's is different from video file ' + Math.ceil(video.duration) + 's');
            }
        });

        var autoplayLoader = function() {
            if (secondsBeforeNext * 1000 > loadingDelayMs) {
                return setTimeout(autoplayLoader, 500);
            }

            if (element.innerHTML.match('<video>')) {
                video.play();
            }
        }
        setTimeout(autoplayLoader, delayNoisyContentJIT);
    }

    var checkAndMoveCron = function() {
        if ((new Date()).getSeconds() != 0) {
            return;
        }

        for (var i = 0; i < items.cron.length; i++) {
            var item = items.cron[i];

            if (cron.isActive(item.cron_schedule) && cronItemIndex !== i) {
                moveToCronSlide(i);
            }

            if (cron.isActive(item.cron_schedule_end) && cronItemIndex === i) {
                stopCronSlide();
            }
        }
    };

    function moveToCronSlide(cronSlideIndex) {
        var item = items.cron[cronSlideIndex];
        cronItemIndex = cronSlideIndex;
        pause();
        var callbackReady = function() {
            cronSlide.style.zIndex = '2000';
            if (!item.cron_schedule_end) {
                setTimeout(function () {
                    stopCronSlide();
                }, safe_duration(item) * 1000);
            }
        };
        loadContent(cronSlide, callbackReady, item);
    }

    function stopCronSlide() {
        cronItemIndex = null;
        cronSlide.style.zIndex = '0';
        play();
    }

    main();
</script>
</body>
</html>
