//// Copyright 2008 by Kelvin Thompson. All Rights Reserved.//// FILE: mfutil.js//

//==========================================================================//function isPosInteger ( inputStr ){  if ( inputStr == null )    return false;  var regexp = /^\d*$/;  inputStr = inputStr.toString();  return inputStr.match(regexp) ? true : false;}function isNumber ( inputStr ){  if ( inputStr == null )    return false;  var regexp = /^[-]?\d*\.?\d*$/;  inputStr = inputStr.toString();  return inputStr.match(regexp) ? true : false;}

function isAllWhite ( inputStr )
{
  var regexp = /\S/;
  return inputStr.search(regexp) < 0;
}
function isElemType ( obj, name ){  return obj  &&         obj.nodeType == 1  &&       //Node.ELEMENT_NODE==1         obj.nodeName.toLowerCase() == name.toLowerCase();}function isADiv ( obj ){  return isElemType( obj, "div" );}
function isATextNode ( obj ){  return obj && obj.nodeType==3;       //Node.TEXT_NODE==3}

function mfAttachOnclickListener ( elem, func )
{
  if ( elem.addEventListener )    elem.addEventListener( "click", func, false );  else    elem.attachEvent( "onclick", func );}
//==========================================================================//function mfOrderedArray ( )
{
  this.array = new Array();
  this.count = 0;
}

mfOrderedArray.prototype.getArray = function ( )
{
  this.array.length = Math.min( this.count, this.array.length );
  return this.array;
}

mfOrderedArray.prototype.getCount = function ( )
{
  return this.count;
}

mfOrderedArray.prototype.getElement = function ( num )
{
  return this.array[num];
}

mfOrderedArray.prototype.getLast = function ( )
{
  return this.count ? this.array[this.count-1] : null;
}

mfOrderedArray.prototype.push = function ( obj )
{
  this.array[this.count++] = obj;
  return obj;
}

mfOrderedArray.prototype.deleteLast = function ( )
{
  if ( this.count > 0 )
    delete this.array[--this.count];
}
//==========================================================================//

function handleExamplesButton ( )
{
  var exampleDiv = document.getElementById("exampleDiv");
  var button     = document.getElementById("exampleButton");
  var buttText   = button.firstChild;

  if ( exampleDiv.style.display == "block" )
  {
    exampleDiv.style.display = "none";
    buttText.nodeValue = buttText.nodeValue.replace( /Hide/, "Show" );
  }
  else
  {
    exampleDiv.style.display = "block";
    buttText.nodeValue = buttText.nodeValue.replace( /Show/, "Hide" );
  }
}

function scrubExampleList ( )
{
  var pendingContainers = new Array();
  var pendingHeaders    = new Array();
  var pendingLinks      = new Array();

  var listTop = document.getElementById("listTop");
  listTop.style.display = "block";

  pendingContainers.push( listTop );
  while ( pendingContainers.length || pendingHeaders.length || pendingLinks.length )
  {
    while ( pendingContainers.length )
    {
      var obj = pendingContainers.shift();
      obj.className = "listContainer";

      for ( var child=obj.firstChild; child; child=child.nextSibling )
      {
        if ( isADiv(child) )
        {
          var textNode = child.firstChild;
          if ( isATextNode(textNode)  &&  ! isAllWhite(textNode.nodeValue) )
          {
            if ( textNode.nodeValue.charAt(0) == "+" )
              pendingHeaders.push( child );
            else if ( child.getAttribute("id")  &&  child.id.substring(0,5) == "link-" )
              pendingLinks.push( child );
          }
        }
      }
    }

    while ( pendingHeaders.length )
    {
      var obj = pendingHeaders.shift();
      obj.className = "listHeader";
      
      // remove "+ " from start of string
      var txtNode = obj.firstChild;
      if ( txtNode )
        txtNode.nodeValue = txtNode.nodeValue.substring(2);

      // add "+" icon
      var imgElem = document.createElement("img");
      imgElem.src = "plus.png";
      imgElem.alt = "+";
      imgElem.hspace = 2;
      obj.insertBefore( imgElem, txtNode );
      
      // add listeners
      mfAttachOnclickListener( obj, handleListHeaderClick );

      // kill margin on top-level headers
      if ( obj.parentNode  &&  obj.parentNode.id == "listTop" )
        obj.style.marginLeft = "0";
      
      for ( var sib=obj.nextSibling; sib; sib=sib.nextSibling )
      {
        if ( isADiv(sib) )
        {
          pendingContainers.push( sib );
          break;
        }
      }
    }

    while ( pendingLinks.length )
    {
      var obj = pendingLinks.shift();
      obj.className = "listLink";
      mfAttachOnclickListener( obj, handleListLinkClick );
    }
  }

  document.getElementById("listTop").style.marginLeft = "0";
}

function handleListHeaderClick ( evt )
{
  // get browser-independent event
  evt = evt ? evt : (window.event ? window.event : null);
  if ( ! evt )
    return false;

  // get broswer-independent target element
  var elem = evt.target ? evt.target : evt.srcElement;
  if ( ! elem )
    return false;

  // if we hit the +/- IMG element, move up to the parent
  if ( isElemType(elem,"img") )
    elem = elem.parentNode;

  // find the next sibling that is a DIV
  var container;
  for ( container=elem.nextSibling;
        container && !isADiv(container);
        container=container.nextSibling )
    {
      // no-op
    }

  // bail out if no sibling found
  if ( ! container )
    return false;

  // See if the container is displayed or not. Note that
  // 'container.style.display' is initially the empty string.
  if ( container.style.display == "block" )
  {
    // hide items below this header
    container.style.display = "none";
    
    // switch icon to "+"
    elem.firstChild.src = "plus.png"
    elem.firstChild.alt = "+";
  }
  else
  {
    // show items below this header
    container.style.display = "block";

    // switch icon to "-"
    elem.firstChild.src = "minus.png";
    elem.firstChild.alt = "-";
  }

  return false;
}

function handleListLinkClick ( evt )
{
  evt = evt ? evt : window.event;
  if ( ! evt )
    return false;
  
  var elem = evt.target ? evt.target : evt.srcElement;
  if ( ! elem )
    return false;

  var saveNum = elem.id.substring(5);
  mfuf_fetchURL( saveNum );

  return false;
}
//==========================================================================//

// "mfum" = MAPfrappe URL Make
// REQUIRED to be assigned by page-specific code:
// mfum_phpURL        - string containing URL for PHP
// mfum_makeXML       - function to build XML from current page state
// mfum_urlCallback   - function called with persistent URL
  
// OPTIONAL to be assigned by page-specific code
var mfum_abortCallback = null;  // function called when request aborted

// "private" variables
var mfum_abortTimeoutId = null;  // ID for timeout
var mfum_request        = null;  // in-progress request object

// invoked via Function.call() - so 'this' is an instance of 'urlGen'function mfum_checkReqState ( req ){  // Safari 3.0.4 (and probably other versions) doesn't seem to invoke  // 'onreadystatechange' for 'readyState==1', so we must call setRequestHeader()  // elsewhere.   //if ( req.readyState == 1 )  //{  //  req.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );  //  return;  //}  if ( !req  ||  !mfum_request  ||  req.readyState != 4 )    return;

  // clear pending timeout - server has responded in a timely manner
  if ( mfum_abortTimeoutId != null )
  {
    window.clearTimeout( mfum_abortTimeoutId );
    mfum_abortTimeoutId = null;
  }
  
  // Clear our saved reference to the XMLHttpRequest object. Only
  // mfum_abortTimeoutFunc() requires that reference, and now we know
  // that won't be necessary.
  mfum_request = null;

  // parse the XML text that came back from POST  var xmlNode = GXml.parse(req.responseText);
  
  // look for 'rowid' element in XML node set  var idElement = xmlNode.documentElement.getElementsByTagName("rowid");  if ( idElement.length != 1 )  {    alert( "Unfortunately, an error occurred attempting to create the permanent URL." );    return;  }
  
  // get value of 'rowid' element - it should be a positive integer  var idStr = idElement[0].getAttribute('value');  if ( ! isPosInteger(idStr) )  {    alert( "Unfortunately, an error occurred attempting to create the permanent URL." );    return;  }

  // get URL of the current page - truncate anything after '?'  var baseURL = location.href;  var qmarkIdx = location.href.indexOf( '?' );  if ( qmarkIdx > 0 )    baseURL = location.href.slice( 0, qmarkIdx );
  
  // assemble the new URL  var newURL = baseURL + "?show=" + idStr;  
  // call page-specific method to display the new URL  mfum_urlCallback( newURL );}
function mfum_abortTimeoutFunc ( ){
  mfum_abortTimeoutId = null;
  
  var req = mfum_request;
  mfum_request = null;
  
  // kill the pending XMLHttpRequest
  if ( req )
    req.abort();

  // call page-specific handler for request that timed out
  if ( (typeof mfum_abortCallback) == "function" )
    mfum_abortCallback();
}

function mfum_requestURL ( )
{
  if ( mfum_request )
    return false;

  mfum_request = GXmlHttp.create();
    mfum_request.open( "POST", mfum_phpURL, true );  mfum_request.onreadystatechange = function(){mfum_checkReqState(mfum_request);};  mfum_request.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );  mfum_request.send( "xml=" + mfum_makeXML() );
  
  mfum_abortTimeoutId = window.setTimeout( "mfum_abortTimeoutFunc()", 17000 );
  
  return true;
}
//==========================================================================//

// "mfuf" = MAPfrappe URL Fetch
// REQUIRED to be assigned by page-specific code:
// mfuf_phpURL        - string containing URL for PHP
// mfuf_parseXMLNode  - function to parse saved XML
  
// OPTIONAL to be assigned by page-specific code
var mfuf_abortCallback = null;  // function called when request aborted

// "private" variables
var mfuf_abortTimeoutId = null;  // ID for timeout
var mfuf_request        = null;  // in-progress request object
function mfuf_checkReqState ( req ){  // Safari 3.0.4 (and probably other versions) doesn't seem to invoke  // 'onreadystatechange' for 'readyState==1', so we must call setRequestHeader()  // elsewhere.   //if ( req.readyState == 1 )  //{  //  req.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );  //  return;  //}  if ( !req  ||  !mfuf_request  ||  req.readyState != 4 )    return;

  // clear pending timeout - server has responded in a timely manner
  if ( mfuf_abortTimeoutId != null )
  {
    window.clearTimeout( mfuf_abortTimeoutId );
    mfuf_abortTimeoutId = null;
  }

  // Clear our saved reference to the XMLHttpRequest object. Only
  // mfuf_abortTimeoutFunc() requires that reference, and now we know
  // that won't be necessary.
  mfuf_request = null;
  // parse the XML text that came back from POST
  var xmlNode = GXml.parse( req.responseText );  // 'error' element in XML indicates a problem  var errElem = xmlNode.documentElement.getElementsByTagName("error");  if ( errElem.length != 0 )  {    var msg = "Unfortunately, an error occurred attempting to retrieve the saved map.";    var textNode = errElem[0].firstChild;    var text = textNode ? textNode.nodeValue : null;    if ( textNode && textNode.nodeType==3 && textNode.nodeValue )      msg += "\n\n" + textNode.nodeValue;    alert( msg );    return;  }
  
  // call page-specific XML parser
  mfuf_parseXMLNode( xmlNode );}
function mfuf_abortTimeoutFunc ( ){
  mfuf_abortTimeoutId = null;
  
  var req = mfuf_request;
  mfuf_request = null;
  
  // kill the pending XMLHttpRequest
  if ( req )
    req.abort();

  // call page-specific handler for request that timed out
  if ( (typeof mfuf_abortCallback) == "function" )
    mfuf_abortCallback();
}

mfuf_fetchURL = function ( idnum )
{
  if ( mfuf_request )
    return false;

  mfuf_request = GXmlHttp.create();  mfuf_request.open( "POST", mfuf_phpURL, true );  mfuf_request.onreadystatechange = function(){mfuf_checkReqState(mfuf_request);};  mfuf_request.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );  mfuf_request.send( "id=" + idnum );
  
  mfuf_abortTimeoutId = window.setTimeout( "mfuf_abortTimeoutFunc()", 17000 );
  
  return true;
}

