// vim: et:ts=4:sw=4:sts=4:ft=javascript

'use strict';

Ox.VideoPreview = function(options, self) {

    self = self || {};
    var that = Ox.Element({}, self)
        .defaults({
            duration: 0,
            getFrame: null,
            fps: 25,
            frameRatio: 16/9,
            height: 256,
            position: void 0,
            scaleToFill: false,
            timeline: '',
            width: 256
        })
        .options(options || {})
        .addClass('OxVideoPreview')
        .css({
            width: self.options.width + 'px',
            height: self.options.height + 'px'
        });

    self.loaded = [];
    self.queue = [];

    self.$frameElement = $('<div>')
        .addClass('OxFrame')
        .appendTo(that.$element)

    self.$frame = $('<img>')
        .attr({src: self.options.getFrame(self.options.position)})
        .css(getFrameCSS())
        .appendTo(self.$frameElement);

    self.$timeline = $('<img>')
        .addClass('OxTimeline')
        .attr({src: self.options.timeline})
        .css({width: self.options.width + 'px'})
        .appendTo(that.$element);

    self.$interface = Ox.Element({
            tooltip: function(event) {
                //event.offsetX does not work in Firefox
                // fixme: use layerX then
                var position = getPosition(event.clientX - that.offset().left);
                self.$frame.attr({src: self.options.getFrame(position)});
                return Ox.formatDuration(position, 2);
            }        
        })
        .addClass('OxInterface')
        .bind({
            click: click,
            mouseenter: startLoading,
            mouseleave: function() {
                self.$frame.attr({src: self.options.getFrame(self.options.position)});
                stopLoading();
            }
        })
        .appendTo(that.$element);

    function click(e) {
        that.triggerEvent('click', {
            // e.offsetX does not work in Firefox
            position: getPosition(e.clientX - that.offset().left)
        });
    }

    function getFrameCSS() {
        var css = {},
            elementWidth = self.options.width,
            elementHeight = self.options.height - 16,
            elementRatio = elementWidth / elementHeight,
            frameRatio = self.options.frameRatio,
            frameIsWider = frameRatio > elementRatio;
        if (self.options.scaleToFill) {
            css.width = frameIsWider ? elementHeight * frameRatio : elementWidth;
            css.height = frameIsWider ? elementHeight : elementWidth / frameRatio;
            css.marginLeft = frameIsWider ? (elementWidth - css.width) / 2 : 0;
            css.marginTop = frameIsWider ? 0 : (elementHeight - css.height) / 2;
        } else {
            css.width = frameIsWider ? elementWidth : elementHeight * frameRatio;
            css.height = frameIsWider ? elementWidth / frameRatio : elementHeight;
            css.marginLeft = frameIsWider ? 0 : (css.width - elementWidth) / 2;
            css.marginTop = frameIsWider ? (css.height - elementHeight) / 2 : 0;
        }
        return Ox.map(css, function(value) {
            return Math.round(value) + 'px';
        });
    }

    function getPosition(x) {
        return Math.round(
            self.options.duration * x / self.options.width * self.options.fps
        ) / self.options.fps;
    }

    function startLoading() {
        var last,
            steps = [Math.round(self.options.width / 2)];
        while ((last = steps[steps.length - 1]) > 1) {
            steps.push(Math.round(last / 2));
        }
        steps.forEach(function(step) {
            Ox.loop(0, self.options.width, step, function(x) {
                var frame = self.options.getFrame(getPosition(x));
                if (
                    self.loaded.indexOf(frame) == -1
                    && self.queue.indexOf(frame) == -1
                ) {
                    self.queue.push(frame);
                }
            });
        });
        loadFrame();
        function loadFrame() {
            $('<img>')
                .load(function() {
                    self.loaded.push(self.queue.shift());
                    self.queue.length && loadFrame();
                })
                .attr({src: self.queue[0]});
        }
    }

    function stopLoading() {
        self.queue = [];
    }

    self.setOption = function(key, value) {
        if (key == 'height') {
            that.css({height: value + 'px'});
            self.$frame.css(getFrameCSS());
        } else if (key == 'position') {
            self.$frame.attr({src: self.options.getFrame(value)});
        } else if (key == 'width') {
            that.css({width: value + 'px'});
            self.$frame.attr({src: self.options.getFrame()})
                .css(getFrameCSS());
            self.$timeline.css({width: value + 'px'});
            stopLoading();
        }
    }

    return that;

};
