/*
 * Copyright (c) 2011 TWIMPACT UG (haftungsbeschraenkt). All rights reserved.
 */


(function($) {
  $.ajaxSetup({dataType: 'json', type: 'POST'});

  var doAnimation = true;

  $(window).blur(function() { doAnimation = false; });
  $(window).focus(function() { doAnimation = true; });

  var APIBASE = location.host.match(/localhost/) ? "http://localhost:8998" : "http://api.twimpact.com";
  var language = kototoy_locale[0];

  var i18nCache = {};
  var templates = {};
  var timescales = [3600,60];

  var selectedLanguage = kototoy_data.l == "" ? language : kototoy_data.l;
  var selectedTimescale = kototoy_data.t == "" ? -1 : kototoy_data.t;

  function i18n(id, args) {
    if (!i18nCache[id]) {
      $.ajax(kototoy_base + "/i18n/" + language, { async: false, type: 'GET' })
          .success(function(result) {i18nCache = result;});
    }
    var value = i18nCache[id];
    if (args) {
      return  value.replace(/\{([0-9]+)\}/, function(m, i) {
        return args[i];
      });
    } else {
      return value;
    }
  }


  function loadTemplate(name) {
    $.ajax(kototoy_base + "/templates/" + name + ".mustache", {type: 'GET', dataType: 'text'}).success(
        function(template, status, xhr) {
          templates[name] = xhr.responseText;
        }).error(function(e) {
          console.log(e);
        });
  }

  function status(text) { $("#status").text(text).css("color", "#00cc00"); }

  function statusError(text) { $("#status").text(text).css("color", "#ee0000").css("font-weight", "bold"); }

  function streaming() {
    var twid;
    var retryCounter = 0;
    var mediaParams = { "offset": 0, "count": kototoy_viewable != "retweets" ? 200 : 20};

    function request(type, params) {
      return $.ajax(APIBASE + "/1/stream/" + twid + "/" + type, {
        data: $.extend({
          "offset": 0,
          "count": 20,
          "lang": selectedLanguage,
          "ts": selectedTimescale,
          "q": $("#query").val()
        }, params)
      });
    }

    function requestFeatures() {
      if (kototoy_features.match(/languages/)) {
        request("languages").success(function() { status(i18n("status.requested.languages")); });
      }
      if (kototoy_viewable == "retweets") {
        request("retweets").success(function() { status(i18n("status.requested.retweets")); });
        request("twimpact").success(function() { status(i18n("status.requested.ranking")); });
        request("media", mediaParams).success(function() { status(i18n("status.requested.media")); });
      } else if (kototoy_viewable == "images") {
        request("media", mediaParams).success(function() { status(i18n("status.requested.media")); });
      } else if (kototoy_viewable == "links") {
        request("links", mediaParams).success(function() { status(i18n("status.requested.links")); });
      }
    }


    $("#lang-chart .language").live('click', function() {
      selectedLanguage = $(this).text().trim();
      requestFeatures(mediaParams);
    });


    var formatter = new Twimpact.Formatter();
    var stream = new Twimpact.Streaming();
    var reconnectCb;
    stream.connect(APIBASE.replace(/^[a-z]+:\/\//, window.WebSocket ? "ws://" : "http://") + "/1/stream");
    stream.open(function() {
      status(i18n("status.stream.open"));
      console.log("open(" + (twid ? twid : "") + ")");
      clearTimeout(reconnectCb);
      reconnectCb = 0;
      retryCounter = 0;
    });

    stream.close(function(event) {
      console.log("close(" + twid + ") {clean:" + event.wasClean + ",reason:'" + event.reason + "'}");
      if (retryCounter < 100) {
        retryCounter++;
        statusError(i18n("status.stream.reconnect", [retryCounter]));
        reconnectCb = setTimeout(stream.connect, 2000);
      } else {
        statusError(i18n("status.stream.reconnect.max"));
      }
    });

    stream.error(function() {
      statusError(i18n("status.stream.error"));
      if (!reconnectCb) {
        reconnectCb = setTimeout(stream.connect, 5000);
        retryCounter++;
      }
    });

    var lastReceivedBytes = 0;
    var reconnectThreshold = 20 * 1024 * 1024;

    function pretty(ms) {
      return ms < 5000 && (ms + "ms") ||
          ms < 60000 && (Math.floor(ms / 1000) + "s " + Math.floor(ms % 1000) + "ms") ||
          ms < 3600000 && (Math.floor(ms / 60000) + "m " + Math.floor((ms % 60000) / 1000) + "s") ||
        /*ms < 86400000 &&*/ (Math.floor(ms / 3600000) + "h " + Math.floor((ms % 3600000) / 60000) + "m "
          + Math.floor(((ms % 3600000) % 60000) / 1000) + "s");
    }

    jQuery.fx.off = true;
    // update an elements text value with an effect, then execute callback
    function update(el, value, then) {
      if ($(el).text() != value) {
        $(el).stop().fadeOut('fast').html(value).fadeIn('fast');
        if (typeof then === 'function') then(el);
      }
      return el;
    }

    function toggleFx(rate) {
      if (rate < 2.5 && jQuery.fx.off) {
        jQuery.fx.off = false;
      } else if (rate > 2.5 && !jQuery.fx.off) {
        jQuery.fx.off = true;
      }
    }

    // stream event handler
    function streamEvent(event) {
      var rate = stream.eventRate();
      toggleFx(rate);
      status(i18n("status.online", [Twimpact.Util.byteSize(stream.receivedBytes()) + ", " + rate.toFixed(2)]));
      if (stream.isStreaming() && (stream.receivedBytes() - lastReceivedBytes) > reconnectThreshold) {
        status(i18n("status.stream.reconnect.mem"));
        console.log("reconnect(" + twid + "), received " + (stream.receivedBytes() - lastReceivedBytes) + " bytes");
        lastReceivedBytes = stream.receivedBytes();
        stream.disconnect();
      }

      switch (event.data.type) {
        case "ready":
          twid = event.data.p;
          stream.configure(twid ? {openData: {"id": twid}} : {});
          console.log("connected(" + twid + ")");

          $.ajax(APIBASE + "/1/timescales", {type: 'GET', dataType: 'json'}).success(function(ts) {
            if (selectedTimescale == -1) {
              selectedTimescale = ts["default"] ? ts["default"] : Math.max(0, ts.length - 2);
            }
            timescales = ts["timescales"];
            var data = $.map(timescales, function(t, idx) {
              return {
                "i": idx,
                "name": i18n("template.timescale." + t + "s")
              }
            });
            $("#timescale form").empty();
            $("#timescale form").append($.mustache(templates["timescales"], {
              "key": i18n("template.timescale"),
              "timescales": data
            }));
            $("#timescale form").find("input:eq(" + selectedTimescale + ")").attr("checked", "checked");
            $("#timescale form").find("input").click(function() {
              selectedTimescale = $(this).val();
              requestFeatures();
            });
          });
          request("statistics").success(function() { status(i18n("status.requested.statistics")); });
          requestFeatures();
          break;
        case "stats":
          $("#rtlag .lag").text(pretty(event.data.p.lag[0]));
          $("#anlag .lag").text((event.data.p.lag[0] - event.data.p.lag[1]) + "ms");
          $("#mem .used").text(Twimpact.Util.byteSize(event.data.p.mem.used));
          $("#mem .max").text(Twimpact.Util.byteSize(event.data.p.mem.total));
          break;
        case "languages":
          if (doAnimation) {
            var chart = d3.select("#lang-chart").selectAll("div").data(event.data.p);
            chart.enter().append("div")
                .attr("class", "language")
                .attr("title", function(d) { return d.self; })
                .text(function(d) { return d.language; })
                .transition().duration(500)
                .style("width", Math.floor(($("#lang-chart").width() - 2 * event.data.p.length) / event.data.p
                .length) + "px")
                .style("height", function(d) { return d.score * 100 / event.data.p[0].score + "%"; })
                .style("background-color", function(d) { return d.language == selectedLanguage ? "red" : "steelblue"; })
                .style("font-weight", function(d) { return d.language == selectedLanguage ? "bold" : "normal"; });
            chart.selectAll("div")
                .attr("title", function(d) { return d.self; })
                .text(function(d) { return d.language; });
            chart
                .style("width", Math.floor(($("#lang-chart").width() - 2 * event.data.p.length) / event.data.p
                .length) + "px")
                .style("height", function(d) { return d.score * 100 / event.data.p[0].score + "%"; })
                .style("background-color", function(d) { return d.language == selectedLanguage ? "red" : "steelblue"; })
                .style("font-weight", function(d) { return d.language == selectedLanguage ? "bold" : "normal"; });
            chart.exit().remove();
          }
          break;
        case "retweets":
          if (templates['retweet']) {
            var ul = $("#retweet-trend ul");
            var li = ul.find("li");
            $.each(event.data.p, function(idx, item) {
              if (!item.user.profile_image_url) item.user.profile_image_url = 'images/missing-profile-image.png';
              var view = $.extend(item, {
                score: item.score.toFixed(),
                text: formatter.format(item.text),
                retweet: "RT @" + item.user.screen_name + ": " + item.text,
                since: $.prettyDate.format(item.updated),
                updown: {
                  trend: item.trend > 0 ? "up" : "down",
                  icon: item.trend > 0 ? i18n("trend.up") : i18n("trend.down")
                },
                retweet_this: i18n("template.retweet.this"),
                retweet_last: i18n("template.retweet.last")
              });


              var el = li[idx];
              var rendered;
              if (el) {
                if (el.id == "rtid-" + item.id) {
                  update($(el).find(".user-twimpact"), view.user.twimpact, function(e) {
                    $(e).removeClass(
                        function(i, c) {
                          return (c.match(/\btw-[0-9]+/g) || []).join(' ');
                        }).addClass("tw-" + view.user.twimpact);
                  });
                  var updown = $(el).find(".updown");
                  if (!updown.hasClass("trend-" + view.updown.trend)) {
                    update(updown, view.updown.icon, function(e) {
                      $(e).removeClass(
                          function(i, c) {
                            return (c.match(/\btrend-(up|down)/g) || []).join(' ');
                          }).addClass("trend-" + view.updown.trend);
                    });
                  }
                  update($(el).find(".score"), view.score);
                  update($(el).find(".rt-age .since"), view.since);
                  $(el).find(".rt-age").attr("title", view.updated);
                  rendered = $(el);
                } else {
                  rendered = $($.mustache(templates['retweet'], view));
                  $(el).replaceWith(rendered);
                }
              } else {
                rendered = $($.mustache(templates['retweet'], view));
                rendered.hide().appendTo(ul).stop().fadeIn('slow');
              }

              rendered.promise().done(function() {
                $(this).find(".history").sparkline(item.history, {
                  type: 'bar', barWidth: 2, barColor: '#00a', height: '18px'
                });
              });
            });
            $("#retweet-trend ul li").slice(event.data.p.length).remove();
            if ($("#retweet-trend ul li").length == 0) {
              $("#retweet-trend ul").append("<li class=\"empty\">" + i18n("trend.nodata", [$("#query").val()]));
            }
            $.sparkline_display_visible();
          }
          break;
        case "twimpact":
          if (templates['twimpact']) {
            var ul = $("#twimpact-trend ul");
            var li = ul.find("li");
            $.each(event.data.p, function(idx, item) {
              if (!item.profile_image_url) item.profile_image_url = 'images/missing-profile-image.png';
              var el = li[idx];
              if (el) {
                if (el.id == "tw-" + item.screen_name) {
                  update($(el).find('.user-twimpact'), item.twimpact);
                } else {
                  $(el).replaceWith($($.mustache(templates['twimpact'], item)));
                }
              } else {
                $($.mustache(templates['twimpact'], item)).hide().appendTo(ul).stop().fadeIn('slow');
              }
            });
            $("#twimpact-trend ul li").slice(event.data.p.length).remove();
            if ($("#twimpact-trend ul li").length == 0) {
              $("#twimpact-trend ul").append("<li class=\"empty\">" + i18n("ranking.nodata") + "</li>");
            }
          }
          break;
        case "media":
          if (templates['media']) {
            var mId = kototoy_viewable == "images" ? "#media-trend-wall" : "#media-trend";
            var ul = $(mId + " ul");
            var li = ul.find("li");
            var now = Date.now().getTime();
            $.each(event.data.p, function(idx, item) {
              var rendered = $($.mustache(templates['media'], $.extend(item, { score: item.score.toFixed() })));
              var el = li[idx];
              if (el) {
                if ($(el).find("img").attr("src") == item.thumbnail) {
                  update($(el).find("score"), item.score);
                } else {
                  $(el).replaceWith(rendered);
                }
              } else {
                rendered.appendTo(ul);
              }

              rendered.promise().done(function() {
                $(this).find(".history").sparkline(item.history, {
                  type: 'bar', barSpacing: 1, barWidth: 1, barColor: '#00a', height: '16px'
                });
              });
            });

            $(mId + " ul li").slice(event.data.p.length).remove();
            if ($(mId + " ul li").length == 0) {
              $(mId + " ul").append("<li class=\"empty\">" + i18n("media.nodata", [$("#query").val()]));
            }
          }
          break;
        case "links":
          if (templates['links']) {
            var mId = "#link-trend-wall";
            var ul = $(mId + " ul");
            var li = ul.find("li");
            var now = Date.now().getTime();
            $.each(event.data.p, function(idx, item) {
              var rendered = $($.mustache(templates['links'], $.extend(item, { score: item.score.toFixed() })));
              var el = li[idx];
              if (el) {
                if ($(el).find("img").attr("src") == item.link) {
                  update($(el).find("score"), item.score);
                } else {
                  $(el).replaceWith(rendered);
                }
              } else {
                rendered.appendTo(ul);
              }

//              rendered.promise().done(function() {
//                $(this).find(".history").sparkline(item.history, {
//                  type: 'bar', barSpacing: 1, barWidth: 1, barColor: '#00a', height: '16px'
//                });
//              });
            });

            $(mId + " ul li").slice(event.data.p.length).remove();
            if ($(mId + " ul li").length == 0) {
              $(mId + " ul").append("<li class=\"empty\">" + i18n("links.nodata", [$("#query").val()]));
            }
          }
          break;
        default:
          console.log("unknown event received: " + event.data.type);
          break;
      }
    }

    stream.message(streamEvent);

    $("#query").typeWatch({
      callback: function() {
        if (kototoy_viewable == "retweets") {
          request("retweets");
        }
        if (kototoy_viewable == "retweets" || kototoy_viewable == "images") {
          request("media", mediaParams);
        }
        if (kototoy_viewable == "links") {
          request("links", mediaParams);
        }
        return true;
      },
      wait:750,
      highlight:true,
      captureLength: -1
    });
    $("#filter-query form").submit(function(e) { e.preventDefault(); });

  }

  function changeLink(e) {
    var href = $(this).attr("href");
    var q = $("#query").val();
    var params = {};
    if (q && q != "") params.q = q;
    params.t = selectedTimescale;
    if (selectedLanguage != language) params.l = selectedLanguage;
    if (params.q || params.l || params.t) {
      var url = href + "?" + $.param(params);
      $(this).attr("href", url);
    }
  }

  $(function() {
    $.prettyDate.messages = {
      now: i18n("time.now"),
      minute: i18n("time.minute"),
      minutes: $.prettyDate.template(i18n("time.minutes")),
      hour: i18n("time.hour"),
      hours: $.prettyDate.template(i18n("time.hours")),
      yesterday: i18n("time.yesterday"),
      days: $.prettyDate.template(i18n("time.days")),
      weeks: $.prettyDate.template(i18n("time.weeks"))
    };

    status(i18n("status.initializing"));
    loadTemplate("timescales");
    loadTemplate("retweet");
    loadTemplate("twimpact");
    loadTemplate("media");
    loadTemplate("links");

    streaming();

    $("#menu-retweets a").click(changeLink);
    $("#menu-images a").click(changeLink);
    $("#menu-links a").click(changeLink);
  });

})(jQuery);

