// BigTextScroller2 JavaScript file.
// Modification of BigTextScroller, using the proposed CSS3 marquee property.

// global defaults
var SCROLLER_DIV_NAME = "scroller";
var DEFAULT_BACKGROUND_COLOUR = "#fff";
var DEFAULT_TEXT_COLOUR = "#000";

// scroller instance vars
var isSafari = false;
var isMobileSafari = false;
var theForm;
var scrollerDiv;
var invert = false;  // false for black writing on white background; true for white writing on black background
var invertTrueValues = ["1", "true", "yes", "on", "invert"];
var scrollingFlag = false;
var savedOffsetWidth;

// define some examples
var exampleScrolls = [
  "text=Newsflash: Eat breakfast every day!&size=150&speed=3&direction=left&font=monospace",
  "text=Please read this carefully&size=300&speed=2&direction=left&font=serif&invert=true",
  "text=I hope you can read this quick little message&size=40&speed=5&direction=left&font=sans-serif",
  "text=Supercalafragelisticexpialadocious&size=75&speed=1&direction=left&font=serif&invert=yes",
  "text=>> scrolling to the right >>&direction=right",
];

// called when page loads
function init()
{
  isSafari = navigator.userAgent.indexOf("Safari") > -1;
  theForm = document.parametersForm;
  scrollerDiv = document.getElementById(SCROLLER_DIV_NAME);
  scrollerDiv.title = "Click to stop/restart scrolling";
  scrollerDiv.style.color = DEFAULT_TEXT_COLOUR;
  scrollerDiv.style.backgroundColor = DEFAULT_BACKGROUND_COLOUR;
  parseURLParameterString(document.location.search);
  scrollerDiv.onclick = function() { toggleScrolling(); };
  restartScroller();
  populateExamples();
  populateURLParamInfo();
}

// called when page loads - special case for Mobile Safari
function initMobileSafari()
{
  isMobileSafari = true;
  init();
}

// parses any parameters passed in on the url, in the format:
//    "text=the%20message&size=150&font=serif&speed=3&direction=left&invert=true"
function parseURLParameterString(paramString)
{
  if (paramString.length > 0)
  {
    var arguments = extractFieldValues(paramString);
    if (arguments["text"] != undefined)
    {
      theForm.text.value = arguments["text"];
    }
    // note that browsers can set the appropriate option based on the value assigned (invalid options are ignored)
    theForm.size.value = arguments["size"];
    theForm.speed.value = arguments["speed"];
    theForm.direction.value = arguments["direction"];
    theForm.font.value = arguments["font"];
    if (arguments["invert"] && validFieldValue(arguments["invert"], invertTrueValues))
    {
      theForm.invert.checked = true;
      if (isMobileSafari)
      {
        invertToggleDiv = document.getElementById("invertToggle");
        invertToggleDiv.setAttribute("toggled", "true");
      }
      invertColours(false);
    }
    else
    {
      theForm.invert.checked = false;
      if (isMobileSafari)
      {
        invertToggleDiv = document.getElementById("invertToggle");
        invertToggleDiv.setAttribute("toggled", "false");
      }
    }
    updateURLForCurrentSettings();
  }
}

// extracts arguments from search string, returning a psuedo-associative array
function extractFieldValues(encodedSearch)
{
  var modifiedSearch = unescape(encodedSearch.substr(1, encodedSearch.length-1));
  var arguments = new Object;
  if (modifiedSearch.indexOf("=") > -1)
  {
    var fields = modifiedSearch.split("&");
    for (var i in fields)
    {
      var name = fields[i].substr(0, fields[i].indexOf("="));
      var value = fields[i].substr(fields[i].indexOf("=")+1, fields[i].length-1);
      arguments[name] = value;
    }
  }
  return arguments;
}

// tests that value is in the set of valid values
function validFieldValue(value, arrayOfValues)
{
  for (var i in arrayOfValues)
  {
    if (value.toLowerCase() == arrayOfValues[i]) return true;
  }
  return false;
}

// restarts the scroller, using the current text input by the user
function restartScroller()
{
  // update scroller settings
  updateText(theForm.text, false);
  updateSpeed(theForm.speed, false);
  updateSize(theForm.size, false);
  updateDirection(theForm.direction, false);
  updateFont(theForm.font, false);
  updateURLForCurrentSettings();

  // start scrolling
  scrollingFlag = true;
  scrollerDiv.style.webkitMarqueeSpeed = "fast";
  scrollerDiv.style.webkitMarqueeStyle = "scroll";
  scrollerDiv.title = "Click to stop scrolling";
  updateStopOrRestartButton();
}

// changes the scroller's text based on user's input
function updateText(textareaObj, updateURL)
{
  // update the scroller text
  var textToScroll = textareaObj.value;
  if (textToScroll.replace(/\s/g, "").length == 0)
  {
    textToScroll = "Please enter some text to scroll";
  }
  scrollerDiv.innerHTML = textToScroll;
  if (updateURL) updateURLForCurrentSettings();
}

// changes the size setting based on user's input
function updateSize(selectObj, updateURL)
{
  var scrollHeight = new Number(selectObj.options[selectObj.selectedIndex].value);
  var fontSize = (isSafari ? Math.round(scrollHeight / 1.15) : scrollHeight);
  scrollerDiv.style.height = scrollHeight + "px";
  scrollerDiv.style.fontSize = fontSize + "px";
  if (updateURL) updateURLForCurrentSettings();
}

// changes the speed setting based on user's input
function updateSpeed(selectObj, updateURL)
{
  var scrollSpeed = new Number(selectObj.options[selectObj.selectedIndex].value);
  if (isMobileSafari) scrollSpeed = 3 * scrollSpeed - 2;
  scrollerDiv.style.webkitMarqueeIncrement = scrollSpeed;
  if (updateURL) updateURLForCurrentSettings();
}

// changes the direction setting based on user's input
function updateDirection(selectObj, updateURL)
{
  var scrollDirection = selectObj.options[selectObj.selectedIndex].value;
  scrollerDiv.style.webkitMarqueeDirection = scrollDirection;
  if (updateURL) updateURLForCurrentSettings();
}

// changes the font setting based on user's input
function updateFont(selectObj, updateURL)
{
  var fontFamily = selectObj.options[selectObj.selectedIndex].value;
  scrollerDiv.style.fontFamily = fontFamily;
  if (updateURL) updateURLForCurrentSettings();
}

// swaps the text and background colours
function invertColours(updateURL)
{
  invert = !invert;
  var previousColor = scrollerDiv.style.color;
  scrollerDiv.style.color = scrollerDiv.style.backgroundColor;
  scrollerDiv.style.backgroundColor = previousColor;
  if (theForm.invert.checked != invert) theForm.invert.checked = invert;
  if (updateURL) updateURLForCurrentSettings();
}

// toggles the scrolling state
function toggleScrolling()
{
  scrollingFlag ? stopScroller() : restartScroller();
}

// cancel the scrolling
function stopScroller()
{
  scrollingFlag = false;
  scrollerDiv.style.webkitMarqueeStyle = "none";
  scrollerDiv.title = "Click to restart scrolling (from beginning)";
  updateStopOrRestartButton();
}

// updates the label of the stop/restart button
function updateStopOrRestartButton()
{
  if (isMobileSafari)
  {
    document.getElementById("stopOrRestartButton").innerHTML = (scrollingFlag ? "Stop" : "Restart");
  }
  else
  {
    theForm.stopOrRestartButton.value = (scrollingFlag ? "Stop" : "Restart");
  }
}

// displays the URL with query string that can be used to link to the current message settings
function updateURLForCurrentSettings()
{
  var formParams = new Array();
  formParams.push("text=" + escape(theForm.text.value));
  formParams.push("size=" + theForm.size.options[theForm.size.selectedIndex].value);
  formParams.push("speed=" + theForm.speed.options[theForm.speed.selectedIndex].value);
  formParams.push("direction=" + theForm.direction.options[theForm.direction.selectedIndex].value);
  formParams.push("invert=" + escape(theForm.invert.checked));
  formParams.push("font=" + theForm.font.options[theForm.font.selectedIndex].value);
  var theURL = window.location.protocol + "//" + window.location.hostname;
  if (window.location.port) theURL += ":" + window.location.port;
  theURL += window.location.pathname + "?" + formParams.join("&");
  if (isMobileSafari)
  {
    var theURLForCurrentSettingsDiv = document.getElementById("theURLForCurrentSettings");
    while (theURLForCurrentSettingsDiv.hasChildNodes())
    {
      theURLForCurrentSettingsDiv.removeChild(theURLForCurrentSettingsDiv.lastChild);
    }
    theURL = "<a href=\"" + theURL + "\">Direct link to an iScrollBigText message:<br /> (" + theURL + ")</a>";
    var mailToLink = document.createElement("a");
    // mailToLink.type = "cancel";
    mailToLink.href = "mailto:?subject=iScrollBigText%20Link&body=" + encodeURIComponent(theURL);
    mailToLink.title = "Current message URL is: " + theURL;
    mailToLink.appendChild(document.createTextNode("Send URL by email"));
    theURLForCurrentSettingsDiv.appendChild(mailToLink);
  }
  else
  {
    document.getElementById("theURLForCurrentSettings").innerHTML = theURL;
  }
}

// populates the URL parameter info bits of the page
function populateURLParamInfo()
{
  var parameterNames = ["size", "font", "speed", "direction"];
  for (var i in parameterNames)
  {
    var valueAndTextPairs = collectOptionValues(theForm[parameterNames[i]]);
    var infoSpan = document.getElementById(parameterNames[i] + "ParamInfo");
    if (infoSpan) infoSpan.innerHTML = "Accepted values: " + valueAndTextPairs.join(", ");
  }
  var invertInfoSpan = document.getElementById("invertParamInfo");
  if (invertInfoSpan) invertInfoSpan.innerHTML = "Accepted values: <code>" + invertTrueValues.join(", ") + "</code> (all other values treated as <code>false</code>)";
}

// collects an array of formatted text/value pairs for a given <select> object's options
function collectOptionValues(selectObj)
{
  var optionArguments = new Array();
  for (var i in selectObj.options)
  {
    if (typeof selectObj.options[i].value == "string")
    {
      optionArguments.push("<code>" + selectObj.options[i].value + "</code> = <i>" + selectObj.options[i].text + "</i>");
    }
  }
  return optionArguments;
}

// populates the lists of examples
function populateExamples()
{
  // first, populate the in-page examples list
  var ul = document.getElementById("examplesList");
  for (var i in exampleScrolls)
  {
    var arguments = extractFieldValues("?" + exampleScrolls[i])
    var li = document.createElement("li");
    var exampleLink = document.createElement("a");
    exampleLink.i = i;
    if (isMobileSafari)
    {
      exampleLink.className = "exampleLink";
      exampleLink.type = "cancel";
      exampleLink.onclick = function() {
        if (invert) invertColours(false);
        parseURLParameterString("?" + exampleScrolls[this.i]);
      };
    }
    else
    {
      exampleLink.onclick = function() {
        if (invert) invertColours(false);
        parseURLParameterString("?" + exampleScrolls[this.i]);
        restartScroller();
      };
      exampleLink.href = "#";
    }
    exampleLink.appendChild(document.createTextNode(arguments["text"]));
    li.appendChild(exampleLink);
    ul.appendChild(li);
  }
  // next, populate the example URLs list
  var ul = document.getElementById("exampleURLsList");
  var pathElements = window.location.pathname.split("/");
  var filename = pathElements[pathElements.length-1];
  for (var i in exampleScrolls)
  {
    var li = document.createElement("li");
    var linkWrapper = document.createElement("nobr");
    var exampleLink = document.createElement("a");
    if (isMobileSafari)
    {
      exampleLink.className = "exampleLink";
      exampleLink.type = "cancel";
      exampleLink.href = filename + "?" + exampleScrolls[i] + "#_home";
      exampleLink.onclick = function() {
        window.location = this.href;
      };
      exampleLink.appendChild(document.createTextNode(exampleLink.href));
      li.appendChild(exampleLink);
    }
    else
    {
      exampleLink.href = "?" + exampleScrolls[i];
      exampleLink.appendChild(document.createTextNode(filename + "?" + exampleScrolls[i]));
      linkWrapper.appendChild(exampleLink);
      li.appendChild(linkWrapper);
    }
    ul.appendChild(li);
  }
}

// called when user changes orientation of Mobile device
function handleOrientationChange()
{
  scrollerDiv.style.width = window.innerWidth;
}
