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

'use strict';

/*@
Ox.LargeTimeline <f:Ox.Element> LargeTimeline Object
    () ->              <f> LargeTimeline Object
    (options) ->       <f> LargeTimeline Object
    (options, self) -> <f> LargeTimeline Object
    options <o> Options object
    self    <o> shared private variable
@*/

Ox.LargeTimeline = function(options, self) {

    self = self || {};
    var that = Ox.Element({}, self)
            .defaults({
                cuts: [],
                duration: 0,
                find: '',
                matches: [],
                points: [0, 0],
                position: 0,
                style: 'default',
                subtitles: [],
                videoId: '',
                width: 0
            })
            .options(options || {})
            .addClass('OxTimelineLarge')
            .mouseleave(mouseleave)
            .mousemove(mousemove)
            .bindEvent({
                anyclick: click,
                dragstart: dragstart,
                drag: drag
            });

    Ox.extend(self, {
        $cuts: [],
        $markerPoint: [],
        $subtitles: [],
        $tiles: {},
        $tooltip: Ox.Tooltip({
            animate: false
        }),
        center: parseInt(self.options.width / 2),
        element: that.$element[0],
        fps: 25,
        height: 64,
        tileWidth: 1500
    });
    self.tiles = self.options.duration * self.fps / self.tileWidth;

    self.$timeline = $('<div>')
        .css({
            left: self.center + 'px'
        })
        .appendTo(that.$element);

    self.options.subtitles.forEach(function(v, i) {
        self.$subtitles[i] = $('<div>')
            .addClass('OxSubtitle' + (self.options.matches.indexOf(i) > -1 ? ' OxHighlight' : ''))
            .css({
                left: (v['in'] * self.fps) + 'px',
                width: (((v['out'] - v['in']) * self.fps) - 2) + 'px'
            })
            .html(Ox.highlight(v.value, self.options.find, 'OxHighlight'))
            .appendTo(self.$timeline);
    });

    self.options.cuts.forEach(function(v, i) {
        self.$cuts[i] = $('<img>')
            .addClass('OxCut')
            .attr({
                src: Ox.UI.PATH + 'png/videoMarkerCut.png'
            })
            .css({
                left: (v * self.fps) + 'px'
            })
            .appendTo(self.$timeline);
    });

    self.$markerPosition = $('<img>')
        .addClass('OxMarkerPosition')
        .attr({
            src: Ox.UI.PATH + 'png/videoMarkerPlay.png'
        })
        .appendTo(that.$element);
    setMarker();

    ['In', 'Out'].forEach(function(v, i) {
        self.$markerPoint[i] = $('<img>')
            .addClass('OxMarkerPoint' + v)
            .attr({
                src: Ox.UI.PATH + 'png/videoMarker' + v + '.png'
            })
            .appendTo(self.$timeline);
        setMarkerPoint(i);
    });

    setWidth();
    setPosition();

    function click(data) {
        self.options.position = Ox.limit(
            getPosition(data), 0, self.options.duration
        );
        setPosition();
        triggerChangeEvent();
    }

    function dragstart(data) {
        self.drag = {x: data.clientX};
    }

    function drag(data) {
        self.options.position = Ox.limit(
            self.options.position + (self.drag.x - data.clientX) / self.fps,
            0, self.options.duration
        );
        self.drag.x = data.clientX;
        setPosition();
        triggerChangeEvent();
    }

    function getPosition(e) {
        return self.options.position + (e.clientX - that.offset().left - self.center - 1) / self.fps;
    }

    function mouseleave(e) {
        self.clientX = 0;
        self.clientY = 0;
        self.$tooltip.hide();
    }

    function mousemove(e) {
        self.clientX = e.clientX;
        self.clientY = e.clientY;
        updateTooltip();
    }

    function setMarkerPoint(i) {
        self.$markerPoint[i].css({
            left: (self.options.points[i] * self.fps) + 'px'
        });
    }

    function setMarker() {
        self.$markerPosition.css({
            left: (self.center - 4) + 'px',
        });
    }

    function setPosition() {
        self.tile = parseInt(self.options.position * self.fps / self.tileWidth);
        self.$timeline.css({
            marginLeft: (-self.options.position * self.fps) + 'px'
        });
        Ox.range(
            Math.max(self.tile - 1, 0), Math.min(self.tile + 2, self.tiles)
        ).forEach(function(v) {
            if (!self.$tiles[v]) {
                self.$tiles[v] = $('<img>')
                    .attr({
                        src: '/' + self.options.videoId + '/' + (
                            self.options.style == 'default' ? 'timeline' : self.options.style
                        ) + '64p' + v + '.png'
                    })
                    .css({
                        left: (v * self.tileWidth) + 'px'
                    })
                    .appendTo(self.$timeline);
            }
        });
        if (self.clientX && self.clientY) {
            updateTooltip();
        }
    }

    function setWidth() {
        self.center = parseInt(self.options.width / 2);
        that.css({
            width: self.options.width + 'px'
        });
        self.$timeline.css({
            left: self.center + 'px'
        });
        setMarker();
    }

    function triggerChangeEvent() {
        that.triggerEvent('change', {
            position: self.options.position
        });
    }

    function updateTooltip() {
        var position = getPosition(self);
        if (position >= 0 && position <= self.options.duration) {
            self.$tooltip
                .options({
                    title: Ox.formatDuration(position, 3)
                })
                .show(self.clientX, self.clientY);
        } else {
            self.$tooltip.hide();
        }
    }

    self.setOption = function(key, value) {
        if (key == 'points') {
            setMarkerPoint(0);
            setMarkerPoint(1);
        } else if (key == 'position') {
            setPosition();
        } else if (key == 'width') {
            setWidth();
        }
    };

    return that;

};
