// ACK! - an AJAX link checker
//
// Copyright 2006 World Wide Web Consortium, (Massachusetts
// Institute of Technology, European Research Consortium for Informatics
// and Mathematics, Keio University). All Rights Reserved.
//
// Originally written by Ville Skyttä <ville.skytta at iki.fi>
//
// This source code is available under the license at:
//     http://www.w3.org/Consortium/Legal/copyright-software
//
// $Id: check.js,v 1.5 2006/05/25 21:56:22 ville Exp $

var REQS  = new Array();
var TOTAL = 0;
var DONE  = 0;
var BASE  = "grab.pl?";

function el(id)
{
  return id == null ? null : document.getElementById(id);
}

function clear(el)
{
  while (el.firstChild) {
    el.removeChild(el.firstChild);
  }
}

function setTextContent(el, text)
{
  clear(el);
  el.appendChild(document.createTextNode(text));
}

function getLink(key)
{
  return el("L" + key);
}

function getStatusElement(key)
{
  return el("S" + key);
}

function checkAll()
{
  pauseResume(el("pr"));
  var links = document.getElementsByTagName("a");
  TOTAL = links.length;
  updateCount(0);
  for (var i = 0; i < TOTAL; i++) {
    check(links.item(i));
  }
  if (TOTAL == 0) finishCheck();
}

function pauseResume(el)
{
  el.disabled = false;
  if (el.paused == null) el.paused = true;
  el.paused ? resumeCheck() : pauseCheck();
  el.paused = !el.paused;
  el.value = el.paused ? "Resume" : "Pause";
}

function updateCount(n)
{
  DONE += n;
  setTextContent(el("stat"), "(" + DONE + " of " + TOTAL + " checked)");
}

function pauseCheck()
{
  for (var key in REQS) {
    if (REQS[key] == null) continue;
    if (REQS[key].readyState < 4) REQS[key].abort();
    REQS[key] = null;
    var link = getLink(key);
    if (!link.done) {
      link.checking = false;
      setTextContent(getStatusElement(key), "paused");
    }
  }
}

function resumeCheck(pr)
{
  var links = document.getElementsByTagName("a");
  for (var i = 0; i < links.length; i++) {
    var link = links.item(i);
    if (!link.done) check(link);
  }
}

function finishCheck()
{
  var pr = el("pr");
  pr.value = "Completed";
  pr.paused = false;
  pr.disabled = true;
}

function check(link)
{
  if (link.id == null || link.id == "" || link.checking) return;
  link.checking = true;
  var key = link.id.substring(1);
  getStatusElement(key).className = "na";
  var req = null;
  try {
    req = new XMLHttpRequest();
  } catch (e) { /* ignore */ }
  if (req == null)
    try {
      req = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) { /* ignore */ }
  if (req == null)
    try {
      req = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) { /* ignore */ }
  REQS[key] = req;
  if (req != null) {
    if (link.done) updateCount(-1);
    req.onreadystatechange = function() { check_cb(key); }
    // TODO: s/escape/encodeURIComponent/ ?
    req.open("HEAD", BASE + "url=" + escape(link.href) + ";ref=" + escape(el("url").defaultValue), true);
    req.send("");
  }
}

function check_cb(key)
{
  var req = REQS[key];
  var statusText = getStatusElement(key);
  if (req.readyState == 0) {
    setTextContent(statusText, "uninitialized");
  }
  else if (req.readyState == 1) {
    setTextContent(statusText, "initialized");
  }
  else if (req.readyState == 2) {
    setTextContent(statusText, "connected");
  }
  else if (req.readyState == 3) {
    setTextContent(statusText, "receiving data");
  }
  else if (req.readyState == 4) {
    var reqStatus = null;
    try {
      reqStatus = req.status;
    }
    catch (e) { /* Ignore, check value of reqStatus instead */ }
    if (reqStatus == null || reqStatus == 0) { // 0 ~ MSIE sometimes?
      // Paused/aborted?  Ignore.
      req = REQS[key] = null;
      return;
    }

    var linkStatus = req.getResponseHeader("X-LinkCheck-Status");
    var msg = "complete: " + req.getResponseHeader("X-LinkCheck-Message");
    var redirect = "";
    try {
      redirect = req.getResponseHeader("X-LinkCheck-Redirect");
    } catch (e) { /* duh */ }
    req = REQS[key] = null;

    if (redirect == null || redirect == "") {
      setTextContent(statusText, msg);
    }
    else {
      clear(statusText);
      statusText.appendChild(document.createTextNode(msg));
      statusText.appendChild(document.createElement("br"));
      statusText.appendChild(document.createTextNode("\u21d2\u00a0")); // "-> "
      var a = document.createElement("a");
      a.setAttribute("href", redirect);
      a.appendChild(document.createTextNode(redirect));
      statusText.appendChild(a);
    }

    if (reqStatus != 200 || linkStatus > 399) {
      statusText.className = "error";
    }
    else if (linkStatus > 299) {
      statusText.className = "redirect";
    }
    else {
      statusText.className = "ok";
    }
    var link = getLink(key);
    link.done = true;
    link.checking = false;
    updateCount(1);
    if (DONE >= TOTAL) finishCheck();
  }
}

