$(function() {
    
    var startYear = -10000,
        endYear = 2012,
        zoomLevel = 8,
        zoomStep = Math.SQRT2,
        minZoomLevel = 1,
        maxZoomLevel = 256,
        sliderWidth = 3000,
        baseSpan = (endYear - startYear),
        $slider = $(".timeline-mill-slider"),
        $tlcontainer = $(".timeline-container"),
        canvas = $tlcontainer.find('canvas')[0],
        lineDistances = [ 1000, 500, 250, 100, 50, 25, 10, 5, 2 ],
        miniLineDist = 1000,
        cWidth, cHeight,
        wSpan, wStart, wEnd, cScale, wLineDist, sScale, mScale,
        wCenter = endYear - baseSpan / 16,
        itemCount = 12,
        tlCache = [], tlIdCache = [], currentTerm = null,
        startSlide = startYear, endSlide = endYear, userStartSlide = startSlide, userEndSlide = endSlide;
    
    function boundValue(val) {
        return Math.max(Math.floor(wStart), Math.min(Math.floor(wEnd), val));
    }
    
    function updateCoords() {
        cWidth = $tlcontainer.width();
        cHeight = $tlcontainer.height();
        wSpan = baseSpan / zoomLevel;
        wStart = wCenter - wSpan / 2;
        wEnd = wCenter + wSpan / 2;
        cScale = cWidth / wSpan;
        sScale = sliderWidth / wSpan;
        mScale = cWidth / baseSpan;
        wLineDist = null;
        for (var i = 0; i < lineDistances.length; i++) {
            if (lineDistances[i] * cScale < 50) {
                break;
            }
            wLineDist = lineDistances[i];
        }
        startSlide = boundValue(userStartSlide);
        endSlide = boundValue(userEndSlide);
        $slider.slider("values",[yrToSliderPos(startSlide),yrToSliderPos(endSlide)]);
        updateSpans();
    }
    
    function yrToSliderPos(yr) {
        return sScale * (yr - wStart);
    }
    function sliderPosToYr(x) {
        return wStart + x / sScale;
    }
    function yrToX(yr) {
        return cScale * (yr - wStart);
    }
    function xToYr(x) {
        return wStart + x / cScale;
    }
    function yrToMiniX(yr) {
        return (yr - startYear)*mScale;
    }
    
    var itemTpl = _.template(
        '<li class="timeline-item"><div class="timeline-item-box<%- current ? " timeline-current" : "" %>"'
        + ' data-dbpedia-uri="<%- item.dbpedia_uri %>" style="left: <%- left %>px; width: <%- width %>px;">'
        + '<div class="timeline-item-label"><%- item.label %></div></div></li>'
    );
    
    function redrawView() {
        canvas.width = cWidth;
        canvas.height = cHeight;
        
        var ctx = canvas.getContext("2d");
        
        var xstart = yrToMiniX(wStart),
            xend = yrToMiniX(wEnd);
        ctx.fillStyle = "#f0f2ff";
        ctx.strokeStyle = "#3090ff";
        ctx.beginPath();
        ctx.moveTo(xstart, 0);
        ctx.lineTo(xend, 0);
        ctx.lineTo(xend, 35);
        ctx.lineTo(cWidth, 70);
        ctx.lineTo(cWidth, cHeight);
        ctx.lineTo(0, cHeight);
        ctx.lineTo(0, 70);
        ctx.lineTo(xstart, 35);
        ctx.closePath();
        ctx.stroke();
        ctx.fill();
        ctx.fillStyle = "#666666";
        ctx.strokeStyle = "#666666";
        ctx.fillStyle = "rgba(220, 220, 220, .5)";
        ctx.fillRect( 0, 0, cWidth, 30 );
        ctx.font = 'bold 12px Arial,Helvetica';
        ctx.fillStyle = "#333333";
        for (var y = miniLineDist * Math.ceil(startYear/miniLineDist); y <= endYear; y += miniLineDist ) {
            var x = yrToMiniX(y);
            ctx.beginPath();
            ctx.moveTo(x,0);
            ctx.lineTo(x,6);
            ctx.moveTo(x,24);
            ctx.lineTo(x,30);
            ctx.stroke();
            ctx.textAlign = ((y - startYear) < miniLineDist ? "left" : ((endYear - y) < miniLineDist ? "right" : "center") );
            ctx.fillText(y || 1, x,20);
        }
        ctx.textAlign = 'center';
        ctx.font = 'bold 14px Arial,Helvetica';
        ctx.fillStyle = "#000000";
        for (var y = wLineDist * Math.ceil(wStart/wLineDist); y <= wEnd; y += wLineDist ) {
            var x = yrToX(y+1/2),
                isPrimary = !((y/wLineDist) % 2);
            ctx.strokeStyle = (isPrimary ? "#000000": "#999999");
            ctx.beginPath();
            ctx.moveTo(x, 60);
            ctx.lineTo(x, cHeight - 20);
            ctx.stroke();
            if (isPrimary) {
                ctx.fillText(y || 1, x, cHeight - 4);
            }
        }
        var html = _(tlCache).chain()
            .filter(function(item) {
                return (item.end_year >= wStart && item.start_year <= wEnd);
            }).first(itemCount)
            .sortBy(function(item) {
                return (item.start_year + item.end_year)
            }).map(function(item) {
                var l = Math.max(0, yrToX(item.start_year)),
                    r = Math.min(cWidth, yrToX(item.end_year + 1));
                return itemTpl({
                    current: (item.dbpedia_uri == currentTerm),
                    item: item,
                    left: l,
                    width: (r-l)
                });
            }).value().join("");
        $(".timeline-list").html(html);
        dbpediaBox.bind(".timeline-item-box");
        $(".timeline-item-box").click(function() {
            var $this = $(this);
            currentTerm = $this.attr("data-dbpedia-uri")
            $(".timeline-item-box").removeClass("timeline-current");
            $this.addClass("timeline-current");
            loadSearchResults({ dbpedia_uri: currentTerm });
        });
    }
    
    function getData() {
        $.getJSON(
            urls.ajax_years,
            {
                from_year: Math.floor(wStart),
                to_year: Math.floor(wEnd)
            },
            function(data) {
                _(data).each(function(term) {
                    if (tlIdCache.indexOf(term.dbpedia_uri) === -1) {
                        tlIdCache.push(term.dbpedia_uri);
                        tlCache.push(term);
                    }
                });
                tlCache = _(tlCache).sortBy(function(item) {
                    return -item.nb_notice;
                });
                throttledRedraw();
            }
        );
    }
    
    var throttledRedraw = _.throttle(function() {
        updateCoords();
        redrawView();
    }, 100);
    
    var debouncedGetData = _.debounce(getData, 1000);
        
    var mousedown = false, dragging = false, xstart = null, wcStart, dragmini;
    
    $tlcontainer.mousedown(function(e) {
        dragging = false;
        mousedown = true;
        dragmini = (e.clientY - $tlcontainer.offset().top < 40);
        xstart = e.clientX;
        wcStart = wCenter;
        return false;
    }).mousemove(function(e) {
        if (mousedown) {
            dragging = true;
            wCenter = Math.max(
                startYear + wSpan / 2,
                Math.min(
                    endYear - wSpan / 2,
                    dragmini ?
                        (wcStart + (e.clientX - xstart) / mScale) :
                        (wcStart + (xstart - e.clientX) / cScale)
                    )
                );
            throttledRedraw();
            debouncedGetData();
            return false;
        }
    }).mousewheel(function(e, d) {
        var yrMouse = xToYr(e.clientX - $(this).offset().left),
            scaleRatio = (d > 0 ? zoomStep : 1/zoomStep);
        if (d < 0 && zoomLevel <= minZoomLevel) {
            return;
        }
        if (d >= 0 && zoomLevel >= maxZoomLevel) {
            return;
        }
        zoomLevel *= scaleRatio;
        var newSpan = baseSpan / ( 2 * zoomLevel );
        wCenter = Math.max(startYear + newSpan, Math.min(endYear - newSpan, yrMouse * (1 - 1 / scaleRatio) + wCenter / scaleRatio ));
        throttledRedraw();
        debouncedGetData();
    });
    
    $("body").mouseup(function() {
        mousedown = false;
        dragging = false;
    });
    
    var $startSpan = $(".timeline-mill-from-year"),
        $endSpan = $(".timeline-mill-to-year");
    
    function updateSpans() {
        $startSpan.text(startSlide);
        $endSpan.text(endSlide);
    }
    
    //updateSpans();
    
    $slider.slider({
        range: true,
        min: 0,
        max: sliderWidth,
        values: [0, sliderWidth],
        slide: function(e, ui) {
            userStartSlide = startSlide = Math.floor(sliderPosToYr(ui.values[0]));
            userEndSlide = endSlide = Math.floor(sliderPosToYr(ui.values[1]));
            updateSpans();
        }
    });
    
    $(".timeline-mill-submit").click(function() {
        loadSearchResults({ from_year: startSlide, to_year: endSlide, show_years: 1 });
    });
    
    throttledRedraw();
    
    getData();
    
    $(window).resize(throttledRedraw);
    
});
