/**
 * Site wide JavaScript.
 * 
 * Copying: Copying of this code for non-commercial use is permitted under the following conditions:
 *   - Give credit to the original author listed in this header.
 *   - For any reuse/distribution, make clear the same terms.
 *   
 * @author Steve Knaus
 */

////////////////////////////////////////////////////////////////////////////////
// Public Class Interface
////////////////////////////////////////////////////////////////////////////////

Site._theSite = null;

Site.get = function() {
   if ( Site._theSite === null ) {
      Site._theSite = new Site();
   }
   return Site._theSite;
}



////////////////////////////////////////////////////////////////////////////////
// Public Instance Interface
////////////////////////////////////////////////////////////////////////////////

Site.prototype.beforeHeadEndTag =
function() {
   // Add site level HEAD elements here.
   //   TITLE not included because it must be hard coded to be indexed by a search engine.
   if ( Site.config.ENABLE_FAVICON ) {
      document.write( '<link rel="shortcut icon" href="site.ico">' );
   }
}

Site.prototype.beforeContent =
function() {
   if ( this.m_forPrint ) {
      this._writePrintHeader();
   } else {
      this._writeBanner();
      this._writeNav();
   }
   document.write( '<div id="content-c">' );
}

Site.prototype.afterContent =
function() {
   self.document.write( '</div>' );  // Started by beforeContent()
   this._writeFooter();
   this._debugPage();

   // Add site level stuff that should be done after the document is parsed. e.g.
   //   - Add event listeners 

   // TODO: may need to use DOM 0 approach to work on all supported platforms:
   //  - see http://simon.incutio.com/archive/2004/05/26/addLoadEvent#comment13
   //  - window.onload = this._onloadListener;
   var f = Site.prototype._onloadListener;
   if ( self.addEventListener ) {
      self.addEventListener( 'load', f, false );
   } else if ( self.attachEvent ) {
      self.attachEvent( 'onload', f );
   }
}

Site.prototype.embedContent = 
function ( src, title, height, scale ) {
   if ( title ) {
      self.document.title = title;
   }
   var frameHeight = height;
   if ( !frameHeight ) {
      frameHeight = 300;
      if ( !scale ) {
         scale = 0.55;
      }
      if ( self.innerHeight ) {
         frameHeight = window.innerHeight * scale;
      } else if ( self.document.documentElement && self.document.documentElement.clientHeight ) {
         frameHeight =  self.document.documentElement.clientHeight * scale;
      }
   }
   //document.write( '<b>', frameHeight, '</b>' );
   document.write( 
      '<iframe', 
      ' onload="Site.get()._onEmbeddedContentLoaded();"',
      ' id="embedded-content-c"',
      ' name="embeddedContentC"',
      ' src="', src, '"',
      ' height="', frameHeight, '"',
      '>',
      'Your browser must support frames to view this content.',
      '</iframe>'
      );
}

Site.prototype.getParameter =
function( name ) {
   if ( !this.m_parameters ) {
      var parms = new Object();
      var nvPairs = this.m_queryString.split( '&' );
      for ( var i in nvPairs ) {
         var pair = nvPairs[i];
         if ( pair ) {
            var delimIdx = pair.indexOf('=');
            var n = null, v = '';
            if ( delimIdx == -1 ) {
               n = pair;
            } else {
               n = pair.substring( 0, delimIdx );
               v = pair.substring( delimIdx + 1 );
            }
            if ( n ) {
               if ( ! ( n in parms ) ) {
                  parms[n] = new Array();
               }
               parms[n].push( self.decodeURIComponent( v ) );
            }
         }
      }
      this.m_parameters = parms;
   }
   return ( name in this.m_parameters ) ? this.m_parameters[ name ][0] : void(0);
}


// intentionally ob fus cated. an ti sp - am
Site.prototype.gml = 
function () {
   var foo = arguments[0];
   for (var i=1; i<arguments.length; ++i) {
      if (i % 2 == 0) {
         foo += (i==2) ? String.fromCharCode(64) : '.';
         foo += arguments[i];
      }
   }
   var xyz = 'm';
   xyz += String.fromCharCode(97);
   xyz += 'i' + String.fromCharCode(108);
   var abc = xyz + 'to';
   abc += ':';
   var x = 'E' + xyz + ': ' + '<a ' + 'hre' + 'f="' + abc + foo + '">' + foo + '</' + 'a' + '>';
   self.document.write(x);
}

Site.prototype.clearAdjustTitle = 
function () {
   this.m_adjustTitle = false;
}


////////////////////////////////////////////////////////////////////////////////
// Private Class Interface
////////////////////////////////////////////////////////////////////////////////

// ctor
function Site() {
   var d = self.document;

   // Instance fields
   this.m_adjustTitle = true;
   this.m_parameters = null;
   this.m_pathname = d.location.pathname;
   if ( this.m_pathname.indexOf( '\\' ) != -1 ) {
      // For IE file: urls
      this.m_pathname = this.m_pathname.replace( /\\/g, '/' );
   }
   this.m_page = this.m_pathname.substring( this.m_pathname.lastIndexOf( '/' ) + 1 ).toLowerCase();
   this.m_queryString = ( d.location.search ? d.location.search.substring( 1 ) : '' );
   this.m_forPrint = ( this.m_queryString.indexOf( 'forprint' ) == 0 );
   this.m_cannedContent = this.m_page.indexOf('tinc') == 0;

   // When determining which category/topic a page maps to, only the page
   // name and parameters beginning with the special prefix 'x-' are used.
   // The benefit of this approach is it allows multiple topics to
   // map to the same page, while not preventing the passing of
   // page dependent parameters.
   //
   // A few example transformations of m_page to m_navPage:
   //
   //     1) frame.html?x-content=album&cur-index=1 
   //        frame.html?x-content=album
   //
   //     2) frame.html?anchor-name=tuesday&x-content=schedule
   //        frame.html?x-content=schedule
   //
   this.m_navPage = this.m_page;
   if ( this.m_cannedContent ) {
      this.m_navPage += '?' + this.m_queryString;
   } else if ( this.m_queryString && this.m_queryString.indexOf( 'x-' ) != -1 ) {
      var navPageParms = '';
      var nvPairs = this.m_queryString.split( '&' );
      for ( var i = 0; i < nvPairs.length; ++i ) {
         if ( nvPairs[i].indexOf( 'x-' ) == 0 ) {
            navPageParms += ( navPageParms.length == 0 ) ? '?' : '&';
            navPageParms += nvPairs[i];
         }
      }
      this.m_navPage += navPageParms;
   }
}

// SITE_MAP Constants
Site.CAT_HOME                  = 0;
Site.CAT_DEFAULT               = Site.CAT_HOME;
Site.CAT_IDX_NAME              = 0;
Site.CAT_IDX_PRIMARY_PAGE      = 1;
Site.CAT_IDX_TOOLTIP           = 2;
Site.CAT_IDX_TOPICS            = 3;
Site.CAT_IDX_SECONDARY_PAGES   = 4;
Site.TOPIC_DEFAULT             = -1;
Site.TOPIC_IDX_NAME            = 0;
Site.TOPIC_IDX_PRIMARY_PAGE    = 1;
Site.TOPIC_IDX_TOOLTIP         = 2;
Site.TOPIC_IDX_SECONDARY_PAGES = 3;

////////////////////////////////////////////////////////////////////////////////
// Private Instance Interface
////////////////////////////////////////////////////////////////////////////////

Site.prototype._debugPage =
function() {
   return;
   var d = window.document;
   d.write( 'm_forPrint=', this.m_forPrint, '<br>' );
   d.write( 'm_cannedContent=', this.m_cannedContent, '<br>' );
   d.write( 'm_pathname=', this.m_pathname, '<br>' );
   d.write( 'm_page=', this.m_page, '<br>' );
   d.write( 'm_navPage=', this.m_navPage, '<br>'  );
   d.write('<span class="debug">');
   d.writeln( window.location );
   d.write('</span><br>');
   for (var p in window.location) {
      d.write( p, '="', window.location[p], '"<br>' );
   }
}

Site.prototype._debugProps =
function( obj ) {
   document.write( '<table border="1">' );
   for ( var p in obj ) {
      document.write( '<tr><th>', p, '</th><td>', obj[p], '</td></tr>' );
   }
   document.write( '</table>' );
}

Site.prototype._onloadListener =
function(e) {
   if ( Site._theSite && Site._theSite.m_adjustTitle ) {
      document.title += ' - ' + Site.config.SITE_SHORT_NAME;
   }
}

Site.prototype._writePrintHeader =
function() {
   var s = ''
   + '<div id="print-header-ph">'
   + '   <span id="title-ph">'
   +        Site.config.SITE_NAME
   + '   </span>'
   + '</div>'
   ;
   document.write( s );
}

Site.prototype._writeBanner = 
function() {
   var s = ''
   + '<table id="banner-b">'
   + '   <tr>'
   + '      <td id="logo-b">'
   + '         <a href="#" onclick="return Site.get()._onHome();" title="Go to our home page."><img src="logo.gif" alt="Site logo." title="Go to our home page." /></a>'
   + '      </td>'
   + '      <td id="title-b">'
   +           Site.config.SITE_NAME
   + '      </td>'
   ;

   if ( Site.config.BANNER_TOP_RIGHT_CONTENT ) {
      s += ''
      + '      <td id="top-right-content-b">'
      +           Site.config.BANNER_TOP_RIGHT_CONTENT
      + '      </td>'
   } else {
      s += ''
      + '      <td id="search-b">'
      + '         <form>'
      + '            Site Search'
      + '            <div id="term-box-b">'
      + '               <input type="text" name="term" size="10" title="Enter search terms and click &quot;Find&quot;">'
      + '            </div>'
      + '            <div id="submit-box-b">'
      + '               <input type="submit" value="Find">'
      + '            </div>'
      + '         </form>'
      + '      </td>'
      ;
   }

   s += ''
   + '   </tr>'
   + '</table>'
   ;

   document.write( s );
}

Site.prototype._writeFooter =
function() {
   var d = window.document;
   d.write( '<div id="footer-f">' );
   if ( !this.m_forPrint ) {
      d.write( '<span>', '<a href="#" onclick="return Site.get()._onPrintableView();" title="View a page formatted for printing.">', '<img src="printer.gif">', 'Printable View', '</a>', '</span>' );
      d.write( '<span>', '<a href="#" onclick="return Site.get()._onHome();" title="Go to our home page.">', '<img src="home.gif">', 'Home', '</a>', '</span>' );
      if ( Site.config.FOOTER_HTML ) {
         d.write( '<span>',  Site.config.FOOTER_HTML, '</span>' );
      }
   }
   d.write( '<span id="footer-last-modified-f">', this._formatLastModified( d ), '</span>' );
   d.write( '<span>',  '&copy;&nbsp;', Site.config.ORGANIZATION_NAME, '</span>' );
   d.write( '</div>' );
}

Site.prototype._formatLastModified =
function( doc ) {
   var lm = new Date( doc.lastModified );
   var dstr = ( lm.getMonth() + 1 ) + '/' + lm.getDate() + '/' + lm.getFullYear();
   return 'Updated: ' + dstr;
}

Site.prototype._onEmbeddedContentLoaded = 
function() {
   var frame = self.frames.embeddedContentC;
   if ( frame ) {
      var el = self.document.getElementById( 'footer-last-modified-f' );
      if ( el ) {
         el.innerHTML = this._formatLastModified( frame.document );
      }
   }
}

Site.prototype._onPrintableView =
function() {
   var forPrintUrl = '#';
   if ( this.m_cannedContent ) {
      forPrintUrl = 'forprint/' + this.m_navPage;
   } else if ( self.frames.length && self.frames.embeddedContentC ) {
      forPrintUrl = self.frames.embeddedContentC.location;
   } else {
      forPrintUrl = this.m_pathname + '?forprint';
      if ( this.m_queryString ) {
         forPrintUrl += '&' + this.m_queryString;
      }
   }
   self.location = forPrintUrl;
   return false;
}

Site.prototype._onHome =
function() {
   self.location = this._getHomeUrl();
   return false;
}

/**
 * NAVIGATION MODEL
 * 
 * INTRO:
 * 
 * The website is arranged into one or more categories. Each category may be 
 * further subdivided into zero or more topics. Each page should be associated with 
 * a category and optional topic. 
 * 
 * Users will navigate the website either using the category/topic navigation 
 * system (the "site" navigation sytem), or some alternative means. Alternative 
 * means include bookmarks, external links, or a search engine. 
 * 
 * Categories will be displayed as tabs and topics as links.  Whenever the user 
 * navigates to a page, whether it be through the site or alternative navigation 
 * system, the category tab and topic link associated with that page will be 
 * highlited so that users know where they are in the site.  
 * 
 * We refer to pages that are directly linked to categories and topics as primary 
 * pages.  Now some pages in the site are not accessible by clicking a category 
 * or topic link.  These are referred to as secondary pages.  Secondary pages are 
 * those not accessible through the site navigation system.  For example you 
 * click a category tab and on that category's primary page is a link to a 
 * secondary page.  
 * 
 * DATA MODEL:
 * 
 * The site has one or more categories. Each category has a name, primary page, 
 * zero or more secondary pages, and zero or more topics. Each topic has a name, 
 * primary page, and zero or more secondary pages. 
 * 
 */

Site.prototype._writeNav = 
function() 
{
   // Get page name
   var page = this.m_navPage;

   // Map page name to category and topic id
   var catId = Site.CAT_DEFAULT;
   var topicId = Site.TOPIC_DEFAULT;
   OUTER:
   for (var i in Site.config.SITE_MAP) {
      var category = Site.config.SITE_MAP[i];
      if (page == category[Site.CAT_IDX_PRIMARY_PAGE]) {
         catId = i;
         break OUTER;
      }
      var topics = category[Site.CAT_IDX_TOPICS];
      if ( topics ) {
         for (var j in topics) {
            var topic = topics[j];
            if (page == topic[Site.TOPIC_IDX_PRIMARY_PAGE]) {
               catId = i;
               topicId = j;
               break OUTER;
            }
            var secondaryTopicPages = topic[Site.TOPIC_IDX_SECONDARY_PAGES];
            if (secondaryTopicPages) {
               for (var jj in secondaryTopicPages) {
                  if (page == secondaryTopicPages[jj]) {
                     catId = i;
                     topicId = j;
                     break OUTER;
                  }
               }
            }
         }
      }
      var secondaryCategoryPages = category[Site.CAT_IDX_SECONDARY_PAGES];
      if (secondaryCategoryPages) {
         for (var ii in secondaryCategoryPages) {
            if (page == secondaryCategoryPages[ii]) {
               catId = i;
               break OUTER;
            }
         }
      }
   }

   // Navigation block
   var x = '<div id="nav-n">';

   // Calc html for category tabs
   x += '<div id="category-n">';
   for (var i in Site.config.SITE_MAP) {
      var category = Site.config.SITE_MAP[i];
      x += '<a href="' + category[Site.CAT_IDX_PRIMARY_PAGE] + '"';
      var tooltip = category[Site.CAT_IDX_TOOLTIP];
      if ( tooltip ) {
         x += ' title="' + tooltip + '"';
      }
      if ( i == catId ) {
         x += ' id="cur-category-n"';
      }
      x += '>' + category[Site.CAT_IDX_NAME] + '</a>';
   }
   x += '</div>';

   // Calc html for topic links
   var topics = Site.config.SITE_MAP[catId][Site.CAT_IDX_TOPICS];
   if ( topics ) {
      x += '<div id="topic-n">';
      for (var i in topics) {
         var topic = topics[i];
         x += '<a href="' + topic[Site.TOPIC_IDX_PRIMARY_PAGE] + '"';
         var tooltip = topic[Site.TOPIC_IDX_TOOLTIP];
         if ( tooltip ) {
            x += ' title="' + tooltip + '"';
         }
         if ( i == topicId ) {
            x += ' id="cur-topic-n"';
         }
         x += '>' + topic[Site.TOPIC_IDX_NAME] + '</a>';
      }
      x += '</div>';
   }

   x += '</div>';

   document.write( x );
}

Site.prototype._getHomeUrl = 
function() {
   return Site.config.SITE_MAP[Site.CAT_HOME][Site.CAT_IDX_PRIMARY_PAGE];
}



