// function $el(id) { return document.getElementById(id); }

var TICKS_PER_SEC = 4;
var TICK_INTERVAL = 1000/TICKS_PER_SEC;

var initialURLByParam;
var initialURLByHash;
var start;
var trial;
var trialRow;
var trials = [];
// var durations;
var totalDuration = 0;
var paused = false;
var loadTimer;
var countdownTimer;
var url;
var ticksRemaining;
var loading = false;
var siteFrame;
var completeReadyStateChanges; // IE (6 at least) fires "complete" 3 times, bizzare, so it has to be tracked. 
var runs;
var durationsExpanded = true;

var exportOption;

$(function() {

	siteFrame=$("#siteFrame");
	siteFrame.attr("src", "sampleSite.html");
	// console.log($("#site").width());
	// siteFrame.width($("#site").width()-30);
	$(siteFrame).load(onLoaded);
	siteFrame.get()[0].onreadystatechange = onIEReadyStateChange;
	
  $("#cover").click(function() { window.open (trial.url, "win" + new Date().getTime()); });
	
  $("#url")
    .keyup(function(e) {
      var key = e.charCode || e.keyCode || 0;
      if (key==13) enqueueTrial();
    })
  $("input").focus(function() {
    autoSelect(this); 
  })
	$("#start").click(enqueueTrial); // TODO keyboard shortcut
	
	$("#pause").click(function() {
		paused = !paused;
		// $el("pausedNotice").style.display = (paused ? "inline" : "none");
		$("#pausedNotice").css({display: (paused ? "inline" : "none")});
		$("#pause").css({backgroundImage: "url('images/" + (paused?"play":"pause") + ".png')"}); // className not working in IE
		$("#url").focus(); // Remove ugly focus border
	});
	
  // var newHash = document.location.hash.replace(/#([^\/])/, "#/$1"); // legacy URLs
  // if (document.location.hash.length && document.location.hash!=newHash) document.location.hash = newHash;
	initialURLByHash = decodeURI(document.location.hash.substr(2));
	if (initialURLByHash.length) { $("#url").val(initialURLByHash); } // Hash overrides param

	// if ($("#url").val().length > 0) resetTrial();
  $("#launchSaver").click(showSaver);
	
  // robot();

});

function robot() {
  $("#url").val("http://ajaxify.com");
  $("#start").click();
  setTimeout(showSaver, 2000);
}

function startNextTrial() {

  if (trial) return;

  var newTrial = null;
  var newTrialRow = null;
  $("#trials tr.trial").each(function() {
    var trial = $(this).data("trial");
    if (!trial.complete) {
      newTrial=trial;
      newTrialRow=$(this);
      return false;
    }
  });
  if (!newTrial) { $("#start").html("Time it!"); return; }

  trial=newTrial;
  trialRow=newTrialRow;

  trialRow.addClass("active");
  // trialRow.find("span.trialCountValue").html("loading");
  trialRow.find("span.trialCountValue").html("...");

  changePopupFinishedStatus(false);
  $("#averageDurationValue").html("0");
  
  var urlValue = trial.url.replace(/^http\:\/\//, "");
  $("#statsUrlCopy").html(urlValue.substr(0,30));
  $("#popupUrlCopy").html(urlValue.substr(0,30));
  $("#urlCopy").html(urlValue.substr(0,15));
  primeTrapWarning();

  totalDuration = ticksRemaining = 0;
  loading = false;

  clearTimeout(countdownTimer);
  countdownTimer = setInterval(onTick, TICK_INTERVAL);
  onTick();
}

function enqueueTrial(urlValue) {

  $("#url").val($("#url").val().replace(/^http\:\/\//, ""));
  var urlValue = $("#url").val();
  if (/^ *$/.test(urlValue)) return;

  $("#doco").slideUp("slow", function() { 
    // $("#tableZone").height($("iframe").height()-$("#singleTrial").height()).show();
    $("#tableZone").show();
    var gapHeight = 10+2; // margin top and bottom of launchSaver
    $("#trialsWrapper").height($("iframe").height()-$("#singleTrial").height()-$("#trialsHeading").height()-$("#launchSaver").height()-gapHeight);
  });
  $("#start").html("Add it!");

  $("#url").val("");

  // var durations = [];
  var newTrial = { url: "http://"+urlValue, durations: [], start: (new Date()) };

  window.location.hash  = "/" + encodeURI(urlValue);


  var currentTrialRow, durationsTR, expander, trialCount, deleter;
  $("#trials")
    .append(currentTrialRow=$("<tr class='trial'></tr>")
      .data("trial", newTrial)
      .append($("<td class='trialURL'></td>")
        .append("<div>"+urlValue.substr(0,60)+"</div>")
      )
      .append($(trialCount=$("<td class='trialCount'></td>"))
        .append("<span class='trialCountValue'><em>---</em></span>")
        .append(expander=$("<span class='expander'>&#9660;</span>"))
      )
      .append("<td class='trialAverage'>---</td>")
      .append("<td class='trialMedian'>---</td>")
      .append("<td class='trialDev'>---</td>")
      .append($("<td class='trialDel'></td>")
        .append(deleter=$("<div class='deleter' alt='delete row'>&nbsp;</div>"))
      )
      // .append("<td class='trialPadding'>&nbsp;</td>")
    )
    .append(durationsTR=$("<tr class='durations'></tr>")
      .append($("<td></td>"))
      .append($("<td colspan='5'></td>")
        .append($("<table class='durationsTable'></table>").data("trial", newTrial)
        )
      )
    );
  ;
  scrollTrialsToBottom();

  trialCount.click(function() { 
    durationsExpanded=!durationsExpanded;
    updateExpanding();
  });
  updateExpanding();
  deleter.click(function() {
    $(currentTrialRow).remove();
    $(durationsTR).remove();
    trial=null;
    startNextTrial();
  });

  startNextTrial();

}

function updateExpanding() {
  durationsExpanded ? $(".durations").show() : $(".durations").hide();
  $(".expander").html(durationsExpanded ? "&#9650;" : "&#9660");
}

function runs() { return parseInt($("#runs").val()); }
// function delay() { return 1000*parseInt($el("delay").value); } // TODO Rename
function delay() { return parseInt($("#delay").val()); } // TODO Rename

function startLoading() {
	$(siteFrame).attr("src","");
	// siteFrame.contentWindow.document.body.open();
	// siteFrame.contentWindow.document.body.close();
	showLoadingPopup();
	hideCallPopup();
	$("#pause").css({visibility: "visible"});
	start=new Date().getTime();
	completeReadyStateChanges = 0;
	$(siteFrame).attr("src", trial.url);
}

function primeTrapWarning() {
	window.onunload = function() {
		alert("Uh-oh! You're about to leave WebWait. This might be because " + url + " won't load inside WebWait and is about to take up the whole page instead. " +
			"If so, there's nothing I can do about it! You won't be able to test it with WebWait, sorry.\n\nMore info at http://webwait.com/faq");
	}
}

function unprimeTrapWarning() { window.onunload = null; }

function onIEReadyStateChange() {
	if (++completeReadyStateChanges==3) onLoaded();
}

function onLoaded() {
  if (siteFrame.attr("src")=="" || siteFrame.attr("src")=="sampleSite.html") return;
	loading = false;
	unprimeTrapWarning();
	var end=new Date().getTime();
	var duration = end - start;

  totalDuration+=duration;
  trial.durations.push(duration);
  var deleter;
  // console.log("ADDING TO", trialRow, "---", trialRow.find(".durationsTable"));
  var durationsTable = trialRow.next().find("table.durationsTable");

  var trialCopy = trial; // take copy to avoid race condition, as trial may have changed when this runs
  $("#trials").blink(function() {
    durationsTable.append(
      $("<tr></tr>")
      // .addClass("durations"+trials.length-1)
      .append("<td class='durationCount'>["+trialCopy.durations.length+"]</td>")
      .append("<td class='durationTime'>"+durationSecs(duration)+"</td>")
      .append(deleter=$("<td class='durationDeleter'><span class='durationDeleterIcon'>x</td>")
        .data("trial", trialCopy) 
      )
      .data("index", trialCopy.durations.length-1)
    );

    // scrollTrialsToBottom();
    deleter.click(function() {
      var unwantedTrial = $(this).data("trial");
      // var trial = $($(this).parents("table")[0]).data("trial");
      unwantedTrial.durations.splice($(this).parent().data("index"), 1);
      var updatedTrialRow = $(this).parents("tr.durations").prev();
      $(this).parent().remove();
      var i=0;
      $(durationsTable.children()[0]).children().each(function() {
        $(this).data("index", i);
        $(this).find(".durationCount").html("["+(++i)+"]");
      });
      updateDurationsView(unwantedTrial, updatedTrialRow);
    });
    trialRow.find(".expander").show(); // always show after first load
    updateDurationsView(trialCopy, trialRow);
  });

  $("#runAmount").html(trial.durations.length);
  // $("#averageDurationValue").html(durationSecs(totalDuration/durations.length));
  // $("#averageDurationValue").html(averageDurationSecs(trial));
  $("#lastDurationValue").html(durationSecs(duration));
  
  showCallPopup();
  hideLoadingPopup();
  
  ticksRemaining = delay() * TICKS_PER_SEC; // Reset
  // if (runs()==0 || trial.durations.length<runs())
    // ticksRemaining = delay() * TICKS_PER_SEC; // Reset
  // else {
  if (runs()>0 && trial.durations.length>=runs()) {
    changePopupFinishedStatus(true);
    trial.complete = true;
    trial=null;
    clearTimeout(countdownTimer);
    startNextTrial();
    $("#trials tr.trial").removeClass("active");
  }

	// }
	
	// TODO REFACTOR - Use this instead of main timer
	
}

function updateDurationsView(updatedTrial, row) {
  var total = 0;
  var copy = [];
  for (var i=0; i<updatedTrial.durations.length; i++) {
    total+=updatedTrial.durations[i];
    copy.push(updatedTrial.durations[i]);
  }
  var average=updatedTrial.average=total/updatedTrial.durations.length;
  var sumOfSquares = 0;
  for (var i=0; i<updatedTrial.durations.length; i++) {
    sumOfSquares+=Math.pow(updatedTrial.durations[i]-average,2);
  }
  var dev = updatedTrial.dev = Math.sqrt(sumOfSquares/updatedTrial.durations.length);
  /*
  var rangeLow = average-2*dev; // 95% range
  if (rangeLow<0) rangeLow=0;
  var rangeHigh = average+2*dev; // 95% range
  */

  var median = 0;
  copy.sort();
  if (copy.length==0) median=0;
  else if (copy.length==1) median=copy[0];
  else if (copy.length%2==0) median=(copy[(copy.length/2)-1]+copy[copy.length/2])/2;
  else if (copy.length%2==1) median=copy[Math.floor(copy.length/2)];
  updatedTrial.median = median;

  row.children(".trialCount").children(".trialCountValue").html(updatedTrial.durations.length);
  row.children(".trialAverage").html(durationSecs(average));
  row.children(".trialDev").html(durationSecs(dev));
  // row.children(".trialRange").html(durationSecs(rangeLow) + "&nbsp;-&nbsp;" + durationSecs(rangeHigh));
  row.children(".trialTime").html(updatedTrial.start);
  if (updatedTrial.durations.length) $("#averageDurationValue").html(durationSecs(average));
  row.children(".trialMedian").html(durationSecs(median));
}

//+ adapted from Carlos R. L. Rodrigues
////@ http://jsfromhell.com/array/average [rev. #1]
average = function(a,mean){
  for(m = mean, l = t, s = 0; l--; s += Math.pow(a[l] - m, 2));
  return r.deviation = Math.sqrt(r.variance = s / t), r;
}

function changePopupFinishedStatus(isFinished) {
	$("#finished").css({display: isFinished ? "block" : "none"});
	$("#countdown").css({display: isFinished ? "none" : "block"});
}




var exportStrategies = {

  exportCSV: function() {
    var content = "";
    $("#trials tr.trial").each(function() {
      var trial=$(this).data("trial");
      content += [
               trial.url.replace(",","%2C"),
               trial.durations.length,
               trial.durations.join(";"),
               trial.average,
               trial.median,
               trial.dev
             ].join(",");
      content+="\n";
    });
    return content;
  },

  exportText: function() {
    var content = "Load times from http://WebWait.com:\n\n";
    $("#trials tr.trial").each(function() {
      var trial=$(this).data("trial");
      content+= ""+
        trial.url + ". " +
        "Average: " + durationSecs(trial.average) + "s. " +
        "Median: " + durationSecs(trial.median) + "s. " +
        "StdDev: " + durationSecs(trial.average) + "s. " +
        " From " + trial.durations.length + " calls.\n"
    });
    return content;
  },

  exportHTML: function() {
    var trialRowsHTML = "";
    $("#trials tr.trial").each(function() {
      var trial=$(this).data("trial");
      trialRowsHTML += "" +
        "<tr>" +
          "<td>" + trial.url + "</td>" +
          "<td>" + trial.durations.length + "</td>" +
          "<td>" + durationSecs(trial.average) + "</td>" +
          "<td>" + durationSecs(trial.median) + "</td>" +
          "<td>" + durationSecs(trial.dev) + "</td>" +
        "</tr>\n";
    });
    return "" +
      "<h3>Load times from <a href='http://webwait.com'>WebWait.com</a></h3>\n" +
      "<table border='1'>\n" +
      $("#trialsHeading tbody").html() + "\n" +
      trialRowsHTML + "\n" +
      "</table>";
  }

}

function showSaver() {

  var html=$("#saverStore").html();
  // var tableHTML=$("#trials").html();
  // var tableHTML="hello";
  // html+="<textarea>"+tableHTML+"</textarea>";

  $.nyroModalManual({
    bgColor: '#3333cc',
    content: html,
    endShowContent: function() {
      $('#nyroModalFull').css('zIndex',99999)
      exportOption = exportOption || "exportText"; // remember option from last invocation
      $("#saver #"+exportOption).click();
      // autoSelect($("#code").get()[0]);
    }
  });

  $("#saver .option").click(function() {
    $("#saver .option").removeClass("selected");
    $(this).addClass("selected");
    exportOption = $(this).attr("id");
    var content = exportStrategies[exportOption]();
    $("#saver textarea").val(content).select();
  });

}

function onTick() {
	if (paused || loading) return;
	
	if (ticksRemaining--) {
		var countdown = Math.ceil(ticksRemaining/TICKS_PER_SEC);
    if (countdown!=$("#countdownValue").html()) $("#countdownValue").html(countdown);
	} else {
		loading=true;
		startLoading();
	}
}

function durationSecs(durationMillis) {
  return isNaN(durationMillis) ? "---" : (durationMillis/1000).toFixed(2);
}
function showCallPopup() { $("#callPopup,#cover").show(); }
function hideCallPopup() { $("#callPopup,#cover").hide(); }
function showLoadingPopup() { $("#loadingPopup").show(); }
function hideLoadingPopup() { $("#loadingPopup").hide(); }

// http://www.matts411.com/post/auto_selecting_text/
var autoSelect = function (el) {
  if (/textarea/i.test(el.tagName) || (/input/i.test(el.tagName) && /text/i.test(el.type))) {
    el.select();
  } else if (!!window.getSelection) { // FF, Safari, Chrome, Opera
    var sel = window.getSelection();
    var range = document.createRange();
    range.selectNodeContents(el);
    sel.removeAllRanges();
    sel.addRange(range);
  } else if (!!document.selection) { // IE
    document.selection.empty();
    var range = document.body.createTextRange();
    range.moveToElementText(el);
    range.select();
  }
};

function scrollTrialsToBottom() {
  $("#trialsWrapper").animate({ scrollTop: $("#trialsWrapper").attr("scrollHeight") });
}

// use opacity 0.01 to avoid scrolling problems
$.fn.blink = function(elementUpdater) {
  $(this).animate({opacity: 0.01}, function() { elementUpdater(); $(this).animate({opacity:1}, 300); });
}

// function log(message) {
// 
// }
