/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Mozilla Communicator client code, released
 * March 31, 1998.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998-1999
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Akkana Peck (akkana@netscape.com)
 *   Charles Manxke (cmanske@netscape.com)
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

// Variables used across all the links being checked:
var gNumLinksToCheck = 0;     // The number of nsILinkCheckers
var gLinksBeingChecked = [];  // Array of nsIURICheckers
var gURIRefObjects = [];      // Array of nsIURIRefObjects
var gNumLinksCalledBack = 0;
var gStartedAllChecks = false;
var gLinkCheckTimerID = 0;

// Implement nsIRequestObserver:
var gRequestObserver =
{
  // urichecker requires that we have an OnStartRequest even tho it's a nop.
  onStartRequest: function(request, ctxt) { },

  // onStopRequest is where we really handle the status.
  onStopRequest: function(request, ctxt, status)
  {
    var linkChecker = request.QueryInterface(Components.interfaces.nsIURIChecker);
    if (linkChecker)
    {
      gNumLinksCalledBack++;
      linkChecker.status = status;
      for (var i = 0; i < gNumLinksCalledBack; i++)
      {
        if (linkChecker == gLinksBeingChecked[i])
          gLinksBeingChecked[i].status = status;
      }

      if (gStartedAllChecks && gNumLinksCalledBack >= gNumLinksToCheck)
      {
        clearTimeout(gLinkCheckTimerID);
        LinkCheckTimeOut();
      }
    }
  }
}

function Startup()
{
  var editor = GetCurrentEditor();
  if (!editor)
  {
    window.close();
    return;
  }

  // Get all objects that refer to other locations
  var objects;
  try {
    objects = editor.getLinkedObjects();
  } catch (e) {}

  if (!objects || objects.Count() == 0)
  {
    AlertWithTitle(GetString("Alert"), GetString("NoLinksToCheck"));
    window.close();
    return;
  }

  gDialog.LinksList = document.getElementById("LinksList");

  // Set window location relative to parent window (based on persisted attributes)
  SetWindowLocation();


  // Loop over the nodes that have links:
  for (var i = 0; i < objects.Count(); i++)
  {
    var refobj = objects.GetElementAt(gNumLinksToCheck).QueryInterface(Components.interfaces.nsIURIRefObject);
    // Loop over the links in this node:
    if (refobj)
    {
      try {
        var uri;
        while ((uri = refobj.GetNextURI()))
        {
          // Use the real class in netlib:
          // Note that there may be more than one link per refobj
          gURIRefObjects[gNumLinksToCheck] = refobj;

          // Make a new nsIURIChecker
          gLinksBeingChecked[gNumLinksToCheck]
            = Components.classes["@mozilla.org/network/urichecker;1"]
                .createInstance()
                  .QueryInterface(Components.interfaces.nsIURIChecker);
          // XXX uri creation needs to be localized
          gLinksBeingChecked[gNumLinksToCheck].init(GetIOService().newURI(uri, null, null));
          gLinksBeingChecked[gNumLinksToCheck].asyncCheck(gRequestObserver, null);

          // Add item  
          var linkChecker = gLinksBeingChecked[gNumLinksToCheck].QueryInterface(Components.interfaces.nsIURIChecker);
          SetItemStatus(linkChecker.name, "busy");
dump(" *** Linkcount = "+gNumLinksToCheck+"\n");
          gNumLinksToCheck++;

        };
      } catch (e) { dump (" *** EXCEPTION\n");}
    }
  }
  // Done with the loop, now we can be prepared for the finish:
  gStartedAllChecks = true;

  // Start timer to limit how long we wait for link checking
  gLinkCheckTimerID = setTimeout(LinkCheckTimeOut, 5000);
  window.sizeToContent();
}

function LinkCheckTimeOut()
{
  // We might have gotten here via a late timeout
  if (gNumLinksToCheck <= 0)
    return;
  gLinkCheckTimerID = 0;

  gNumLinksToCheck = 0;
  gStartedAllChecks = false;
  for (var i=0; i < gLinksBeingChecked.length; i++)
  {
    var linkChecker = gLinksBeingChecked[i].QueryInterface(Components.interfaces.nsIURIChecker);
    // nsIURIChecker status values:
    // NS_BINDING_SUCCEEDED     link is valid
    // NS_BINDING_FAILED        link is invalid (gave an error)
    // NS_BINDING_ABORTED       timed out, or cancelled
    switch (linkChecker.status)
    {
      case 0:           // NS_BINDING_SUCCEEDED
        SetItemStatus(linkChecker.name, "done");
        break;
      case 0x804b0001:  // NS_BINDING_FAILED
        dump(">> " + linkChecker.name + " is broken\n");
      case 0x804b0002:   // NS_BINDING_ABORTED
//        dump(">> " + linkChecker.name + " timed out\n");
      default:
//        dump(">> " + linkChecker.name + " not checked\n");
        SetItemStatus(linkChecker.name, "failed");
        break;
    }
  }
}

// Add url to list of links to check
// or set status for file already in the list
// Returns true if url was in the list
function SetItemStatus(url, status)
{
  if (!url)
    return false;

  if (!status)
    status = "busy";

  // Just set attribute for status icon 
  // if we already have this url 
  var listitems = document.getElementsByTagName("listitem");
  if (listitems)
  {
    for (var i=0; i < listitems.length; i++)
    {
      if (listitems[i].getAttribute("label") == url)
      {
        listitems[i].setAttribute("progress", status);
        return true;
      }
    }
  }

  // We're adding a new item to list
  var listitem = document.createElementNS(XUL_NS, "listitem");
  if (listitem)
  {
    listitem.setAttribute("class", "listitem-iconic progressitem");
    // This triggers CSS to show icon for each status state
    listitem.setAttribute("progress", status);
    listitem.setAttribute("label", url);
    gDialog.LinksList.appendChild(listitem);
  }
  return false;
}

function onAccept()
{
  SaveWindowLocation();
  return true; // do close the window
}

function onCancelLinkChecker()
{
  if (gLinkCheckTimerID)
    clearTimeout(gLinkCheckTimerID);

/*
  LinkCheckTimeOut();
*/
  return onCancel();
}
