function isExternal(url) {
  return url.indexOf("http") == 0 && url.indexOf(window.location.host) == -1;
}

/* This is so you can set the text of elements without worrying about XSS or
 * text with embedded html. $("whatever").strippedHtml("<i>Hello</i> World!") 
 * sets the html to "Hello World!" You can also specify a maxLength, in which 
 * case we'll show some dots if the text is too long and let the user click to
 * see the rest. Notice that we do .html, which lets through &nbsp; and the 
 * like, which will make maxLength work a little wonky. */
jQuery.fn.strippedHtml = function(text, maxLength) {
  var tags = /<[^>]*>/gi;
  // Nobody uses this, I'm just doing it to be consistent with jQuery.
  if (typeof text == "undefined") {
    return this.html().replace(tags, '');
  }
  text = text.replace(tags, '');
  var dotsText = "...";
  if (maxLength && text.length > maxLength) {
    if (maxLength <= dotsText.length) {
      return this.text(text.substring(0, maxLength));
    }
    var toggled = false;
    var visible = $("<span/>");
    visible.html(text.substring(0, maxLength - dotsText.length));
    var dots = $("<span/>").html(dotsText);
    var remaining = $("<span/>").css({display: "none"});
    remaining.html(text.substring(maxLength - dotsText.length, text.length));
    var setup = function(e) {
      e.css({cursor: "pointer"}).click(function() {
        if (toggled) {
          dots.css({display: "inline"});
          remaining.css({display: "none"});
        } else {
          remaining.css({display: "inline"});
          dots.css({display: "none"});
        }
        toggled = !toggled;
      });
    };
    setup(visible);
    setup(dots);
    setup(remaining);
    return this.empty().append(visible).append(dots).append(remaining);
  } else {
    return this.html(text);
  }
};

jQuery.fn.truncateToHeight = function(text, maxHeight) {
  var element = $(this);
  var tags = /<[^>]*>/gi;
  text = text.replace(tags, '');
  var newText = "";
  var i = -1;
  element.html("");
  while (++i < text.length && element.outerHeight() <= maxHeight) {
    newText += text.charAt(i);
    element.html(newText);
  }
  while (element.outerHeight() > maxHeight && newText.length >= 1) {
    newText = newText.substring(0, newText.length - 1);
    element.html(newText + "...");
  }
};

/* dumps turns dates into yyyy-mm-ddThh:mm:ss which is great for sorting
 * dates while they're still strings. If you need to manipulate dates and
 * times, use this function. */
function dateFromString(str, addHours) {
  addHours = addHours ? addHours : 0;
  var d = new Date();
  var match = str.match(/^(\d{4})-(\d\d)-(\d\d)T(\d\d:\d\d:\d\d)$/);
  if (match) {
    str = [match[2], match[3], match[1]].join("/") + " " + match[4];
  } else {
    match = str.match(/^(\d{4})-(\d\d)-(\d\d)$/);
    if (match) {
      str = [match[2], match[3], match[1]].join("/") + " 00:00:00";
    }
  }
  d.setTime(Date.parse(str) + addHours * 1000 * 60 * 60);
  return d;
}

$(document).ready(function() {
  $("a").each(function(i) {
    var a = $(this);
    if (a.attr("href") && isExternal(a.attr("href")) && !a.attr("target")) {
      a.attr("target", "_blank");
    }
  });
  if ((typeof item_pk != "undefined" && item_pk) && 
      (typeof item_content_type != "undefined" && item_content_type)) {
    $.get("/api/most/view/" + item_content_type + "/" + item_pk + "/");
  }
  jQuery("a#logout").click(function(e) {
    e.preventDefault();
    $.ajax({url: "/accounts/logout/", cache: false, success: function(data){
      $(".login").html("<span>you have been logged out</span>");
      document.location.reload();
    }});
  });
});

/* from  http://getfirebug.com/firebug/firebugx.js */
if (!window.console || !console.firebug) {
  var _names = ["log", "debug", "info", "warn", "error", "assert", "dir",
      "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", 
      "profile", "profileEnd"];

  window.console = {};
  for (var i = 0; i < _names.length; ++i) {
    window.console[_names[i]] = function() {};
  }
}

function IE6() {
  return jQuery.browser.msie && jQuery.browser.version.match(/6/);
}

function embed_video(video, id, width, height) {
  // IE6 is sensitive to modifying the dom before it's done loading. Here, we 
  // add a div to a parent element before we hit the closing tag of the parent.
  // Hence, $(document).ready
  $(document).ready(function() {
    var url_jpg = video.replace(/\.[a-z]+$/, ".png");
    var flashvars = false;
    var params = {
        wmode: "transparent",
        allowscriptaccess: "always",
        showfsbutton: "true",
        allowfullscreen: "true", 
        flashvars: "file=" + video + 
            "&showfsbutton=true&stretching=exactfit&image=" + url_jpg};
    var attributes = {
        id: "videoplayer_"+id,
        name: "videoplayer_"+id};
    var new_id = "videoplayer_" + id;
    var buttons = buttons_div(new_id + "_buttons", width, $("#" + new_id));
    buttons.addClass("video");
    embed_code_helper(width, height, params, 
        videoPlayerPath(), buttons, "Video");
    swfobject.embedSWF(videoPlayerPath(), new_id, width, height, 
        "9.0.0","", flashvars, params, attributes);
  });
};

function buttons_div(buttons_id, width, insertAfter) {
  var div = $("<div/>").attr("id", buttons_id);
  return div.insertAfter(insertAfter).addClass("media_buttons clearfix");
}

function embed_code_helper(width, height, params, 
    player_path, wrapper, videoOrAudio) {
  var embed_code = $("<embed/>").attr("src", player_path);
  embed_code.attr("width", width).attr("height", height);
  for (param in params) {
    embed_code.attr(param, params[param]);
  }
  var fieldSet = $("<fieldset/>").addClass("embedthis").hide();
  var fieldSetHidden = true;
  var opener = $("<a/>").addClass("Embed").addClass("button");
  opener.attr("href", "#").click(function(event) {
    event.preventDefault();
    fieldSetHidden = !fieldSetHidden;
    if (fieldSetHidden) {
      fieldSet.hide();
    } else {
      fieldSet.show();
    }
  });
  opener.text("Embed");
  opener.appendTo(wrapper);
  fieldSet.appendTo(wrapper);
  fieldSet.append($("<legend/>").text("Embed This " + videoOrAudio));
  fieldSet.append($("<p/>").html("Copy and paste the HTML below to embed this " 
      + videoOrAudio.toLowerCase() + " onto your web page. Find out more "
      + "<a href=\"/audio/help/\">here</a>."));
  var embed_id = wrapper.attr("id") + "_code";
  var labelText = "WNYC " + videoOrAudio.toLowerCase() + " player code:";
  $("<label/>").text(labelText).attr("for", embed_id).appendTo(fieldSet);
  fieldSet.append($("<br/>"));
  wrapper.append($("<div/>").addClass("clear"));
  var textArea = $("<textarea/>").attr("id", embed_id).attr("readonly", "true");
  textArea.attr("rows", 6).attr("cols", 44);
  var innerHtml = $("<p/>").append(embed_code).html();
  var replaceWith = "$1http://" + window.location.host + "/";
  innerHtml = innerHtml.replace(/(=|")\//g, replaceWith);
 
  /* http://www.longtailvideo.com/support/forum/Bug-Reports/9709/Javascript-error-with-embed
   * IE all versions throws all these javascript errors when you unload the page
   * with the JW Player embed. Wrapping the embed tag in an object tag with 
   * appropriate params and attributes didn't do the trick. This little bit of 
   * script here essentially changes the offending
   * function __flash__removeCallback(instance, name) {
   *   instance[name] = null;
   * }
   * into
   * function __flash__removeCallback(instance, name) {
   *   if (instance) instance[name] = null;
   * }*/
  innerHtml += '<script type="text/javascript">(function(){var s=function()' +
      '{__flash__removeCallback=function(i,n){if(i)i[n]=null;};' +
      'window.setTimeout(s,10);};s();})();</script>';
  innerHtml = innerHtml.replace(/</g, "&lt;").replace(/>/g, "&gt;");
  textArea.html(innerHtml).appendTo(fieldSet).click(function() {
    this.select();
  });
	fieldSet.append('<a href="#" class="embed-close-button">Close</a>');
	$('.embed-close-button').click(function(event) {
      fieldSet.hide();
      event.preventDefault();
	});
}

function create_bookmark(user, pk, content_type, bookmark_url, can_bookmark) {
  if (user != "" && content_type != "" && pk != "" && can_bookmark == true) {
    var data = {user:user, content_type: content_type, pk: pk};
    var args = {type:"POST",
        url: bookmark_url,
        data: data,
        success: function(msg) {
          $('li.bookmark').html("Favorited");
        }};
    $.ajax(args);
  } else if (user != "" && can_bookmark == false) {
  } else if (user == "") {
  }
  return false;
}

function delete_bookmark(bookmark_id, delete_bookmark_url) {
  if (bookmark_id) {
    var data = {bookmark_id: bookmark_id};
    var args = {type: "POST",
        url: delete_bookmark_url,
        data: data,
        success: function() {
          $('li#bookmark_' + bookmark_id).remove();
        }};
    $.ajax(args);
  } else {
    return false;
  }
}

/* This code was originally in article_tools.js. As far as I can tell,
 * addthis_(sendto|close|open) aren't actually defined anywhere. In
 * case they're pulled in from an external javascript file however,
 * I'll leave this in for now. */
$(document).ready(function() {
  if ("undefined" != typeof addthis_close) {
    $('#emailthislink').click(function() {
      return loadEmailForm(item_ctype, item_pk);
    });
    $('li.share > a.addthis_share').hover(function() { 
      return addthis_open(this, '', '[URL]', '[TITLE]');
    }, addthis_close).click(addthis_sendto);
    $('li.print > a').click(function() {
      window.print();
    });
    $('li.bookmark > a').click(function() { return false; });

    if (typeof item_pk == "undefined" || item_pk == null) {
       $('li.bookmark').html(" ");
    } else {
       if (can_bookmark) {
          $('li.bookmark > a.bookmark_item').bind('click', add_bookmark);
       } else if (!can_bookmark && is_auth) {
           $('li.bookmark').html("Already Liked");
       } else {
          $('li.bookmark > a.bookmark_item').bind('click', suggest_login);
       }
    }
  }
});

function loadEmailForm(ctype, pk) {
  console.log('in loadEmailForm');
  var place = $('#emailthiswrapper');
  if (place.length) {
    console.log("we've found emailthiswrapper");
    place.load('/emailthis/' +  ctype + '/' + pk + '/');
    var pos = $('#emailthislink').position();
    place.css({'top': pos.top+20, 'left': pos.left}).fadeIn('slow');
  }
  return false;
}

function cancelEmail() {
  $('#emailthiswrapper').fadeOut(1000, function() {
     $(this).html('');
  });
}

function encodeURI(unencoded) {
  if (typeof(encodeURIComponent) != "undefined") {
    return encodeURIComponent(unencoded).replace(/\'/g, '%27');
  } else {
    var returnValue = escape(unencoded).replace(/\+/g, '%2B');
    return returnValue.replace(/\"/g,'%22').rval.replace(/\'/g, '%27');
  }
}

$(document).ready(function($) {
  $("input.clearonfocus").bind("focus", function() {
    if (this.defaultValue == this.value) this.value = '';
  });
  jQuery('input.resetonblur').bind('blur', function() {
    if (this.value == '') this.value = this.defaultValue;
  });
})

function localize_npr_links() {
  $('a').each(function(idx) {
    var href=this.href;
    if (href && href.match(/^http\:\/\/(www\.) ?npr\.org/) 
        && (!href.match(/force_localization |\/dmg\//))) {
      var newhref = 'http://www.npr.org/stations/force/force_localization.php?'
          + 'station=WNYC_FM&url=' + href;
      this.setAttribute('href', newhref);
    }
  });
}
$(localize_npr_links);

function embed_audio_height() {
  return 29;
}

function player_list_image_size() {
  return "popup_player";
}

function enlargeImage(img_id, url, credits, credits_url) {
  var img = $("#" + img_id);
  var background = $("#enlarge_bg").show();
  var enlarge = $("#enlarge");
  var imgElement = $("#enlarge img");
  var imgCaption = $("#enlarge .caption");
  var imgCredits = $("#enlarge .credits").empty();
  var loading = $("#enlarge .loading");
  if (!background.length) {
    background = $("<div/>").appendTo($("body")).attr("id", "enlarge_bg");
    background.css("opacity", 0.2).click(hideEnlarge);
    enlarge = $("<div/>").attr("id", "enlarge").appendTo($("body")).hide();
    var close1 = $("<div/>").addClass("close").append($("<a/>").html("Close"));
    close1.click(hideEnlarge);
    enlarge.append(close1);
    imgElement = $("<img/>").appendTo($("<div/>").addClass("image"));
    imgElement.appendTo(enlarge).click(hideEnlarge);
    loading = $("<div/>").addClass("loading").html("Loading...");
    loading.appendTo(enlarge);
    imgCaption = $("<div/>").addClass("caption").appendTo(enlarge);
    imgCredits = $("<div/>").addClass("credit").appendTo(enlarge);
  }
  var caption = img.attr("title");
  
  imgCaption.text(caption);
  if (caption) {
    imgCaption.show();
  } else {
    imgCaption.hide();
  }
  if (credits_url) {
    var a = $("<a/>").attr("href", credits_url);
    if (isExternal(credits_url)) {
      a.attr("target", "_blank");
    }
    imgCredits.append(a.strippedHtml(credits));
  } else {
    imgCredits.strippedHtml(credits);
  }
  if (credits) {
    imgCredits.show();
  } else {
    imgCredits.hide();
  }
  var top = $(window).scrollTop() + 10;
  enlarge.css({top: top});
  loading.width("").height("").show();
  imgElement.css({position: "absolute", top: 0, left: -9999});
  imgElement.attr("title", caption).attr("alt", img.attr("alt"));
  enlarge.show();
  setEnlargeLeft(enlarge.outerWidth(), 0);
  imgLoaded = false;
  // <embed /> tags float above the popup divs.
  $("embed").css("visibility", "hidden");
  /* If the image has to load, then just the next line is necessary. Now, in
   * Chrome the image does not need to load at all the second time,
   * so the load event doesn't fire. In IE8, I've observed the load event just
   * not firing. Hence, call imgLoad right away, and call it periodically until
   * our image is finally loaded. */
  imgElement.load(imgLoad).attr("src", url);
  repeatImgLoad();
}

var imgLoaded = false;
function imgLoad() {
  var animateTime = 250;
  var imgElement = $("#enlarge img");
  var enlarge = $("#enlarge");
  var loading = $("#enlarge .loading");
  if (!imgLoaded && imgElement[0].complete) {
    imgLoaded = true;
    var enlargeWidth = imgElement.outerWidth() + edgeWidth(enlarge);
    setEnlargeLeft(enlargeWidth, animateTime);
    var attrs = {width: imgElement.width(), height: imgElement.height()};
    loading.animate(attrs, animateTime, "linear", function() {
      loading.hide();
      imgElement.css({position: "static"});
    });
  }
}

function repeatImgLoad() {
  if (!imgLoaded) {
    imgLoad();
    window.setTimeout(repeatImgLoad, 100);
  }
}

function setEnlargeLeft(enlargeWidth, animateTime) {
  var left = ($(window).width() - enlargeWidth) / 2;
  $("#enlarge").animate({left: left}, animateTime);
}

function edgeWidth(element) {
  var returnValue = 0;
  for (attribute in {"margin": "", "padding": ""}) {
    for (direction in {"right": "", "left": ""}) {
      var att = attribute + "-" + direction;
      var value = parseInt(element.css(att).replace("px", ""));
      returnValue += value ? value : 0;
    }
  }
  return returnValue;
}

function hideEnlarge() {
  $("#enlarge_bg").hide();
  $("#enlarge").hide();
  $("embed").css("visibility", "visible");
}

/* This code relates to popping open the popup player. It makes sense to have
 * it in whats_on_now.js, except that thetakeaway.org doesn't have the
 * Whats On Now module but does have embedded audio and buttons. */
function openStation(slug) {
  openPopupPlayer({station: slug});
}

function listenAudioFromUrl(url) {
  handleAudioFromUrl(url, "listen");
}

function addAudioFromUrl(url) {
  handleAudioFromUrl(url, "add");
}

/* Assume no extension, or some of the common playlist extensions are
 * playlists, and everything else is direct audio such as mp3. */
function handleAudioFromUrl(url, action) {
  var extension = url.match(/\.([\w]+)($|\?)/);
  extension = extension ? extension[1].toLowerCase() : "";
  if (extension.match(/^(|pls|xspf|m3u)$/)) {
    var parameters = {};
    parameters[action] = url;
    openPopupPlayer(parameters);
  } else {
    url = action + "mp3=" + url.replace("?", "&");
    openPopupPlayer(parametersFromQuery(url));
  }
}

function audioUrlForPopup(audio, title, thumbnail, download) {
  popArgs = [];
  var push = function(key, value) {
    if (value) {
      popArgs.push(key + "=" + value);
    }
  };
  push("title", title);
  push("thumbnail", thumbnail);
  push("download", download);
  return audio + (popArgs.length ? "?" + popArgs.join("&") : "");
}

function embed_audio(audio, id, width, title, thumbnail, download) {
  // IE6 is sensitive to modifying the dom before it's done loading. Here, we
  // add a div to a parent element before we hit the closing tag of the parent.
  // Hence, $(document).ready
  // If audio is an xspf, then download should be a url. If audio is an mp3,
  // then download can just be true, and this function uses audio as the
  // download_url.
  $(document).ready(function() {
    var flashvars = false;
    var params = {
      wmode: "transparent",
      allowscriptaccess: "always",
      quality: "high",
      flashvars: "file=" + audio + "&autostart=false&popurl=" +
          escape(audioUrlForPopup(audio, title, thumbnail, download))
    };
    var new_id = "audioplayer_" + id;
    var attributes = {
      id: new_id,
      name: new_id
    };
    var obj = $("#" + new_id);
    var height = embed_audio_height();
    var buttons = buttons_div(new_id + "_buttons", width, obj);
    var download_url = "";
    if (download) {
      if ("string" == typeof download) {
        download_url = download;
      } else {
        download_url = audio;
      }
    }
    embed_audio_buttons(audio, buttons, title, thumbnail, download_url);
    embed_code_helper(width, height, params,
        inlinePlayerPath(), buttons, "Audio");
    swfobject.embedSWF(inlinePlayerPath(), new_id, width, height,
        "9.0.0","", flashvars, params, attributes);
  });
}

/* JW Player calls openPlayerFromFlash when you click the pop out link. */
openPlayerFromFlash = listenAudioFromUrl;

function embed_audio_buttons(audio, container, title, thumbnail,
    download_url) {
  if ("string" == typeof container) {
    container = $("#" + container);
  }
  var url = audioUrlForPopup(audio, title, thumbnail,
      download_url ? true : false);
  var addButton = function(label, action) {
    var a = $('<a/>').text(label).addClass(label).prependTo(container);
    a.addClass("button");
    if ("string" == typeof action) {
      a.attr("href", action).attr("target", "_blank");
    } else {
      a.attr("href", "#").click(function(evt) {
        evt.preventDefault();
        action(url);
      });
    }
  };
  if (download_url) {
    addButton("Download", download_url);
  }
  addButton("Add", addAudioFromUrl);
  addButton("Listen", listenAudioFromUrl);
  container.find("a").removeClass("first");
  container.find("a:first").addClass("first");
}

function popup_player_width() {
  return 620;
}

function popup_player_height() {
  return 310;
}

function openPopupPlayer(parameters) {
  var paramList = [];
  for (key in parameters) {
    paramList.push(escape(key) + "=" + escape(parameters[key]));
  }
  var link = '/popup_player/#' + paramList.join("&");
  var options = "'toolbar=no,location=no,status=no,menubar=no,scrollbars=no," +
      "resizable=yes,left=0,top=0,width=" + popup_player_width() + ",height=" +
      popup_player_height() + "'";
  var newWindow = window.open(link, "popup_player", options);
  if (newWindow.focus) {
    newWindow.focus();
  }
}

function parametersFromQuery(url) {
  url = url.replace("#", "");
  var hashParts = url.split("&");
  var variables = {};
  for (var i in hashParts) {
    var subParts = hashParts[i].split("=");
    if (subParts.length > 1) {
      // We store unsafe values, so we must avoid XSS during display
      variables[unescape(subParts[0])] = unescape(subParts[1]);
    }
  }
  return variables;
}
