function tipTrack(evt, always) { with (this)
{
 // Reference the correct event object.
 evt=evt?evt:window.event;

 // Figure out the mouse co-ordinates and call the position function.
 // Also set sX and sY as the scroll position of the document.
 sX = page.scrollX();
 sY = page.scrollY();
 mX = isNS4 ? evt.pageX : sX + evt.clientX;
 mY = isNS4 ? evt.pageY : sY + evt.clientY;

 // If we've set tip tracking, call the position function.
 if (tipStick == 1) position();
}}

function tipPosition(forcePos) { with (this)
{
 // Can't position a tip if there isn't one available...
 if (!actTip) return;

 // Pull the window sizes from the page object.
 // In NS we size down the window a little as it includes scrollbars.
 var wW = page.winW()-(isIE?0:15), wH = page.winH()-(isIE?0:15);

 // Pull the compulsory information out of the tip array.
 var t=tips[actTip], tipX=eval(t[0]), tipY=eval(t[1]), tipW=div.w(), tipH=div.h(), adjY = 1;

 // Add mouse position onto relatively positioned tips.
 if (typeof(t[0])=='number') tipX += mX;
 if (typeof(t[1])=='number') tipY += mY;

 // Check the tip is not within 5px of the screen boundaries.
 if (tipX + tipW + 5 > sX + wW) { tipX = sX + wW - tipW - 5; adjY = 2 }
 if (tipY + tipH + 5 > sY + wH) tipY = sY + wH - (adjY*tipH) - 5;
 if (tipX < sX+ 5) tipX = sX + 5;
 if (tipY < sY + 5) tipY = sY + 5;

 // If the tip is currently invisible, show at the calculated position.
 // Also do this if we're passed the 'forcePos' parameter.
 if ((!showTip && (doFades ? !alpha : true)) || forcePos)
 {
  xPos = tipX;
  yPos = tipY;
 }

 // Otherwise move the tip towards the calculated position by the stickiness factor.
 // Low stickinesses will result in slower catchup times.
 xPos += (tipX - xPos) * tipStick;
 yPos += (tipY - yPos) * tipStick;

 div.x(xPos);
 div.y(yPos);
}}

function tipShow(tipN) { with (this)
{
 if (!isDyn) return;

 // If this tip is nested, call the 'show' function of its parent too.
 if (tips[tipN].parentObj) tips[tipN].parentObj.show(tips[tipN].parentTip);

 // My layer object we use.
 if (!div) div = getLyr(myName + 'Layer');
 
 // IE4 requires a small width set otherwise tip divs expand to full body size.
 if (isDOM) div.sty.width = 'auto';

 // If we're mousing over a different or new tip...
 if (actTip != tipN)
 {
  // Remember this tip number as active, for the other functions.
  actTip = tipN;

  // Set tip's onmouseover and onmouseout handlers for static tips.
  if (tipStick == 0)
  {
   if (isNS4) div.ref.captureEvents(Event.MOUSEOVER | Event.MOUSEOUT);
   div.ref.onmouseover = new Function('evt', myName + '.show("' + tipN + '"); ' +
    'if (isNS4) return this.routeEvent(evt)');
   div.ref.onmouseout = new Function('evt', myName + '.hide(); ' +
   'if (isNS4) return this.routeEvent(evt)');
  }

  // Place it somewhere onscreen - pass true to force a complete reposition.
  position(true);

  // Go through and replace %0% with the array's 0 index, %1% with tips[tipN][1] etc...
  var str = template;
  for (var i=0; i<tips[tipN].length; i++) str = str.replace('%'+i+'%', tips[tipN][i]);
  // Write the proper content... the last <br> strangely helps IE5/Mac...?
  div.write(str + ((document.all && !isWin) ? '<small><br></small>' : ''));
 }

 // For non-integer stickiness values, we need to use setInterval to animate the tip,
 // if it's 0 or 1 we can just use onmousemove to position it.
 clearInterval(trackTimer);
 if (tipStick != parseInt(tipStick)) trackTimer = setInterval(myName+'.position()', 50);

 // Finally either fade in immediately or after 'showDelay' milliseconds.
 // NS4 must always delay by a small amount as sometimes hide events come before show events
 // from a previous mouseout (when two tip triggers overlap), because it's a weird browser.
 // So, this show call can cancel a (slightly later) hide.
 clearTimeout(fadeTimer);
 if (showDelay || isNS4)
  fadeTimer = setTimeout('with ('+myName+') { showTip = true; fade() }', showDelay + 10);
 else { showTip = true; fade() }
}}


function tipHide() { with (this)
{
 // We've got to be a DHTML-capable browser that has a tip currently active.
 if (!isDyn || !actTip) return;

 // If the mouse position is within the tip boundaries, we know NS4 is telling us stories
 // as often it makes hide events unaccompanied by overs or in a weird order.
 // Only applies to static tips that we want the user to mouseover...
 if (isNS4 && tipStick==0 && xPos<=mX && mX<=xPos+div.w() && yPos<=mY && mY<=yPos+div.h())
  return;

 // If this tip is nested, call the 'hide' function of its parent too.
 if (tips[actTip].parentObj) tips[actTip].parentObj.hide();

 // Fade out after a delay so another mouseover can cancel this fade.
 // This allows the user to mouseover a static tip before its hides.
 clearTimeout(fadeTimer);
 fadeTimer = setTimeout('with (' + myName + ') { showTip=false; fade() }', hideDelay);
}}


function tipFade() { with (this)
{
 // Clear to stop existing fades.
 clearTimeout(fadeTimer);

 // Show it and optionally increment alpha from minAlpha to maxAlpha or back again.
 if (showTip)
 {
  div.vis('visible');
  if (doFades)
  {
   alpha += fadeSpeed;
   if (alpha > maxAlpha) alpha = maxAlpha;
   div.alpha(alpha);
   // Call this function again shortly, fading tip in further.
   if (alpha < maxAlpha) fadeTimer = setTimeout(myName + '.fade()', 50);
  }
 }

 else
 {
  // Similar to before but counting down and hiding at the end.
  if (doFades && alpha > minAlpha)
  {
   alpha -= fadeSpeed;
   if (alpha < minAlpha) alpha = minAlpha;
   div.alpha(alpha);
   fadeTimer = setTimeout(myName + '.fade()', 50);
   return;
  }
  div.vis('hidden');
  // Clear the active tip flag so it is repositioned next time.
  actTip = '';
  // Stop any sticky-tip tracking if it's invisible.
  clearInterval(trackTimer);
 }
}}



function TipObj(myName)
{
 // Holds the properties the functions above use.
 this.myName = myName;
 this.tips = new Array();
 this.template = '';
 this.actTip = '';
 this.showTip = false;
 this.tipStick = 1;
 this.showDelay = 50;
 this.hideDelay = 50;
 this.xPos = this.yPos = this.sX = this.sY = this.mX = this.mY = 0;

 this.track = tipTrack;
 this.position = tipPosition;
 this.show = tipShow;
 this.hide = tipHide;
 this.fade = tipFade;
 
 this.div = null;
 this.trackTimer = this.fadeTimer = 0;
 this.alpha = 0;
 this.doFades = true;
 this.minAlpha = 0;
 this.maxAlpha = 100;
 this.fadeSpeed = 10;
}
    // This script is object orientated. That means we create 'tip objects', with a collection
    // of settings, a template to display tips, and a list of tips to show in that template.
    var stickyTip = new TipObj('stickyTip');
    with (stickyTip)
    {
     tips.scheduleShowing = new Array(-235, 5, 100, 'You can schedule multiple showings by selecting the corresponding properties checkbox and then clicking on any of the <b><u>schedule showing</u></b> links.<p>You must check at least one property in order to use the <b><u>schedule showing</u></b> feature.</p> ');
     tips.metrolistIdxDisclaimer = new Array(-235, 5, 100, 'The data relating to real estate for sale in this website comes in part from the Internet Data eXchange ("IDX") program of METROLIST, INC.  Real estate listings held by brokers other than SavingStreet Realty are marked with the IDX Logo.  All data in this website is deemed reliable but is not guaranteed.');
     tips.iresIdxDisclaimer = new Array(-235, 5, 100, 'The data relating to real estate for sale in this website comes in part from the Internet Data eXchange ("IDX") program of IRES, LLC.  Real estate listings held by brokers other than SavingStreet Realty are marked with the IDX Logo.  All data in this website is deemed reliable but is not guaranteed.');
     tips.openCloseHelp = new Array(-235, 5, 100, 'Click here to open and close this section.');

     // Home Page Help tool tips
     tips.cashBackHelp = new Array(-235, 5, 100, 'Get Money back for buying your dream Home!Use the SavingStreet tools to become a qualified buyer and to locate your dream home. When you close on this home, earn up to 2% back.');
     tips.advancedSearchHelp = new Array(-235, 5, 100, 'Beyond the basic search. These advanced tools will allow you to tailor your search beyond square footage and number of bedrooms. Pinpoint the home you have always been searching for.');
     tips.expAgentsHelp = new Array(-235, 5, 100, 'SavngStreet is affiliated with top real estate sales professionals.');
     tips.fastSellHelp = new Array(-235, 5, 100, 'SavingStreet uses all the standard marketing techniques a traditional broker uses, but we reach farther using the Internet and cash back incentives to bring the buyer directly to your home.');
     tips.listLowHelp = new Array(-235, 5, 100, 'SavingStreet’s affiliation with local Real Estate Sales Professionals will match your home with a local sales pro committed to getting your listing sold.');
     tips.powerfulMarketingHelp = new Array(-235, 5, 100, 'SavingStreet has implemented comprehensive marketing strategies developed by top marketing executives.  We employ all forms of media to reach more potential buyers than most of our competitors.  Our depth of experience with marketing enables us to effeciently target the "right" prospects at the point they are prepared to buy.');
     tips.topProfessionalsHelp = new Array(-235, 5, 100, 'SavingStreet has developed a network of Real Estate Professionals that will take you through the home touring and contracting process.  SavingStreet affiliated Real Estate Sales professionals will guide you through the toughest part of buying your next home.');

     template = '<table cellpadding="0" cellspacing="0" width="225" border="0">' +
      '<tr><td align="right"><img src="images/tooltip_corner.gif" WIDTH="6" HEIGHT="5"></td></tr><td><table bgcolor="#397A2A" cellpadding="4" cellspacing="2" width="100%" border="0">' +
      '<tr><td align="center" class="tipClass">%3%</td></tr></table></td></tr></table>';

     tipStick = 0.2;
    }

    // Capture the onmousemove event so tips can follow the mouse. Add in all your tip objects here
    // and also any functions from other scripts that need this event (e.g. my DHTML Scroller) too.
    if (isNS4) document.captureEvents(Event.MOUSEMOVE);
    document.onmousemove = function(evt) {

     // Add or remove all your tip objects from here!jav
     stickyTip.track(evt);

      if (isNS4) return document.routeEvent(evt);
    }

    // A small function that refreshes NS4 on horizontal resize.
    var nsWinW = window.innerWidth, nsWinH = window.innerHeight;
    function ns4BugCheck(){
     if (isNS4 && (nsWinW!=innerWidth || nsWinH!=innerHeight)) location.reload()
    }

    window.onresize = function() {
     ns4BugCheck();
    }
