$(function() {
    
    var lang = $("html").attr("lang"),
        sparqlTpl = _.template(
            'select distinct * where { '
            + 'OPTIONAL { <<%= uri %>> rdfs:label ?l FILTER( langMatches( lang(?l), "<%- lang %>" ) ) }. '
            + 'OPTIONAL { <<%= uri %>> dbpedia-owl:thumbnail ?t }. '
            + 'OPTIONAL { <<%= uri %>> dbpedia-owl:abstract ?a FILTER( langMatches( lang(?a), "<%- lang %>" ) ) }. '
            + 'OPTIONAL { <<%= uri %>> dbpedia-owl:wikiPageRedirects ?r }. '
            + 'OPTIONAL { ?r rdfs:label ?lr FILTER( langMatches( lang(?lr), "<%- lang %>" ) ) }. '
            + 'OPTIONAL { ?r dbpedia-owl:thumbnail ?tr }. '
            + 'OPTIONAL { ?r dbpedia-owl:abstract ?ar FILTER( langMatches( lang(?ar), "<%- lang %>" ) ) }. '
            + '}'
        ),
        $overlay = $(".dbpedia-overlay"),
        hovering = null,
        $refdiv = null,
        $win = $(window),
        dbpediaCache = {},
        $img = $overlay.find("img"),
        $h2 = $overlay.find("h2"),
        $abstract = $overlay.find(".dbpedia-abstract"),
        $source = $overlay.find(".dbpedia-source a");
    
    function moveDbpediaPopin() {
        if (hovering && $refdiv) {
            var refoff = $refdiv.offset(),
                refw = $refdiv.outerWidth(),
                refh = $refdiv.outerHeight(),
                refx = refoff.left,
                refy = refoff.top,
                ovw = $overlay.outerWidth(),
                ovh = $overlay.outerHeight(),
                showAbove = (refy + refh + ovh) > ($win.height() + $win.scrollTop());
            $overlay.css({
                top: showAbove ? (refy - ovh) : (refy + refh),
                left: Math.max(5, Math.min($win.width() - ovw - 5, refx + (refw / 2) - (ovw / 2)))
            });
        }
    }
    
    function showUriData(dbpediaUri) {
        var uriData = dbpediaCache[dbpediaUri];
        if (!uriData) {
            return false;
        }
        if (hovering) {
            $overlay.show().attr("data-dbpedia-uri", dbpediaUri);
            if (uriData.t || uriData.tr) {
                $img.load(moveDbpediaPopin).attr("src",uriData.t || uriData.tr).show();
            } else {
                $img.hide();
            }
            var label = uriData.l || uriData.lr || "",
                wkUrl = "http://" + lang + ".wikipedia.org/";
            if (label) {
                wkUrl += "wiki/" + encodeURI(label.replace(/ /g,'_'));
            } 
            $h2.text(uriData.l || uriData.lr || "");
            $abstract.text((uriData.a || uriData.ar || "").replace(/^(.{240,260})\s.+$/,'$1…'));
            $source.attr("href", wkUrl);
            moveDbpediaPopin();
        }
        return true;
    }
    
    function getUriData(dbpediaUri) {
        if (typeof dbpediaCache[dbpediaUri] !== "undefined") {
            return;
        }
        var sparqlEndpoint = dbpediaUri.replace(/\/resource\/.*$/,'/sparql'),
            query = sparqlTpl({uri: decodeURI(dbpediaUri), lang: lang});
        dbpediaCache[dbpediaUri] = false;
        $.getJSON(sparqlEndpoint, {
            query: query,
            format: "application/sparql-results+json"
        }, function(data) {
            if (!data.results || !data.results.bindings || !data.results.bindings.length) {
                return;
            }
            var res = data.results.bindings[0], cacheData = {};
            for (var k in res) {
                if (res.hasOwnProperty(k)) {
                    cacheData[k] = res[k].value;
                }
            }
            dbpediaCache[dbpediaUri] = cacheData;
            if (hovering === dbpediaUri) {
                showUriData(dbpediaUri);
            }
        });
    }
    
    function onDbpediaLeave() {
        hovering = null;
        setTimeout(function() {
            if (!hovering) {
                $overlay.hide();
            }
        }, 0);
    }
    
    $("body").on({
        mouseenter: function(e) {
            $refdiv = $(this);
            var dbpediaUri = $refdiv.attr("data-dbpedia-uri");
            hovering = dbpediaUri;
            showUriData(dbpediaUri) || getUriData(dbpediaUri);
        },
        mouseleave: onDbpediaLeave
    }, "a[data-dbpedia-uri]");
    
    $overlay.hover(function() {
        var $this = $(this),
            dbpediaUri = $this.attr("data-dbpedia-uri");
        if (dbpediaUri) {
            hovering = dbpediaUri;
        }
    }, onDbpediaLeave);
    
    $(window).resize(moveDbpediaPopin).scroll(moveDbpediaPopin);
    
})
