// shows and manages hints
// the different div ids produce different hints and
// they are handled separately

// ------------------------------------------------------------------
// global variables 
// ------------------------------------------------------------------
var hintsSettings = new Array();
// this array is indexed by the hint element id and has
// those elements inside:
// object - keeps the object of this element
// previousElementId - keeps the previous element id
// switchingTimeout - the switching timeout (milliseconds)
// chancelHiding - defines, if this element is protected from
//   hiding one-by-one when the top one is hided, the
//   link will be broken on this element

// the hiding last and showing new element timer object
switchingTimer = 0;
// the timer creation time
timerCreationTime = 0;
// keeps the last element id
lastElementId = 0;
// keeps the id of the element, to be shown next
newElementId = 0;

// ------------------------------------------------------------------
// helper functions
// ------------------------------------------------------------------
// stops and deletes the timer
function deleteSwitchingTimer()
{
  if ( switchingTimer )
  {
    clearTimeout( switchingTimer );
    switchingTimer = 0;
  };
}

// ------------------------------------------------------------------
// creates the new timer with the timeout, given. There will be
// no timer created, if it is currently running
function createSwitchingTimer( timeout )
{
  if ( !switchingTimer )
  {
    currentTime = new Date();
    switchingTimer = setTimeout( "hideLastElementIfSameAndShowNew()", timeout );
    timerCreationTime = currentTime.getTime();
  };
}

// ------------------------------------------------------------------
// hides the last element, shown
function hideLastElement()
{
  if ( lastElementId != 0 && 
       hintsSettings[lastElementId]['object'] &&
       !hintsSettings[lastElementId]['chancelHiding'] )
  {
    // hiding
    setVisibilityState( hintsSettings[lastElementId]['object'], "hidden" );
    // moving it out of the window not to have ghosts there
    setElementLeftById( lastElementId, -10000 );
    setElementTopById( lastElementId, -10000 );
    // remembering the previous element id by the link to use below
    previousElementId = hintsSettings[lastElementId]['previousElementId'];
    // removing settings for this ID
    hintsSettings[lastElementId] = 0;
    // setting the previous element to be hided next
    lastElementId = previousElementId;
  };
}

// ------------------------------------------------------------------
// shows the new to show, if any (and disables this element from 
// being shown again)
function showNewElement()
{
  if ( newElementId != 0 && 
       hintsSettings[newElementId]['object'] )
  {
    // showing
    setVisibilityState( hintsSettings[newElementId]['object'], "visible" );
    // this element is the last shown now
    lastElementId = newElementId;
    // but not the one, to be shown
    newElementId = 0;
  };
}

// ------------------------------------------------------------------
// the handler for timer, that hides the last element, shown and
// shows the new to show, if any
function hideLastElementIfSameAndShowNew()
{
  if ( newElementId == 0 )
    hideLastElement();
  showNewElement();
  deleteSwitchingTimer();
  if ( lastElementId != 0 && !hintsSettings[lastElementId]['chancelHiding'] )
    startHidingLastElement(0);
}

// ------------------------------------------------------------------
// places the element with identifier, given at the position, specified
//.and shows it.  If there's no element shown currently, this element
// will be shown immediately, otherwise the timer will be started, that
// will hide the current element and show the new (the most current one)
// hidingDelay is the time in milliseconds, before it will hide, after
// the startHidingElements() will be called
function placeElement( elementId, left, top, hidingDelay ) 
{
  element = obtainElementById( elementId );
  if ( !element ) return 0;
  
  // initializing settings for the hint with new id
  if ( !hintsSettings[elementId] )
  {
    hintsSettings[elementId] = new Array();
    hintsSettings[elementId]['previousElementId'] = 0;
  };

  // remembering current settings
  hintsSettings[elementId]['chancelHiding'] = true;
  hintsSettings[elementId]['object'] = element;
  hintsSettings[elementId]['switchingTimeout'] = hidingDelay;
  // to prevent loosing the previous element when opening the
  //  new with the same ID as the current one
  if ( lastElementId != elementId )
    hintsSettings[elementId]['previousElementId'] = lastElementId;
  
  // remembering the current time for the timeout calculation below
  currentTime = new Date();
  // defining, if the timer is currently running and stopping it to
  // prevent it's onTimer message occuance while this function runs
  deleteSwitchingTimer();
  // setting it as to be shown next
  newElementId = elementId;
  // setting up the place of the element to be shown, if there's
  // any content
  setElementLeftById( elementId, left );
  setElementTopById( elementId, top );
  var timeout;
  // calculating the time in the timer, left
  if ( lastElementId != 0 )
    timeout = hintsSettings[lastElementId]['switchingTimeout'] - 
      ( currentTime.getTime() - timerCreationTime );
  else timeout = hintsSettings[elementId]['switchingTimeout'] - 
      ( currentTime.getTime() - timerCreationTime );

  // almost immediately if the current element is not shown
  if ( timeout < 1 || lastElementId == 0 ||
       getVisibilityStateById(elementId) != 'visible' ) timeout = 1;
  // showing it
  createSwitchingTimer( timeout ); 
  return 1;
}

// ------------------------------------------------------------------
// public functions
// ------------------------------------------------------------------
// Those four functions do place the new element (hint) on the
// corresponding side from the sender and show this hint
// The hint text container id is contentElementId and content 
// is the string with it's content. The ID of the element, that
// surrounds the content and and shows/hides it on showing/
// hiding itself is constrainElementId
// Offsets should be specified either
// hidingDelay is the time in milliseconds, before it will hide, after
// the startHidingElements() will be called
// the position on the hint will be corrected so to make in most
// visible in the window, if it will be going to go outside the
// window's client area

// on the right side from sender
function placeElementWithContentOnRightFromMe( sender, constrainElementId, contentElementId, content, offsetFromRight, offsetFromTop, hidingDelay ) 
{
  // hiding to prevent bad visual effects
  /*
  hideElementById( constrainElementId );
  setElementTopById( constrainElementId, -10000 );
  setElementLeftById( constrainElementId, -10000 );
  */
    
  constrainElement = obtainElementById( constrainElementId );
  contentElement = obtainElementById( contentElementId );
  if ( constrainElement && contentElement )
  {
    // setting the element's content
    contentElement.innerHTML = content;
    // calculating the place of the element to be shown,and showing it
    // reserving some space for scrollbars, due to they're hided, but
    // present in some browsers
    return placeElement( constrainElementId,
      max( 0, min( offsetFromRight + calculatePosition( sender, "Left" ) + sender.offsetWidth,
                   getDocumentWidth() - constrainElement.offsetWidth - 1 ) ),
      max( 0, min( offsetFromTop + calculatePosition( sender, "Top" ), 
                   getDocumentHeight() - constrainElement.offsetHeight - 1 ) ),
      hidingDelay );
  }
  else return 0;
}

// on the botton side from the sender
function placeElementWithContentOnBottomFromMe( sender, constrainElementId, contentElementId, content, offsetFromRight, offsetFromTop, hidingDelay ) 
{
  // hiding to prevent bad visual effects
  /*
  hideElementById( constrainElementId );
  setElementTopById( constrainElementId, -10000 );
  setElementLeftById( constrainElementId, -10000 );
  */
    
  constrainElement = obtainElementById( constrainElementId );
  contentElement = obtainElementById( contentElementId );
  if ( constrainElement && contentElement )
  {
    // setting the element's content
    contentElement.innerHTML = content;
    // calculating the place of the element to be shown,and showing it
    // reserving some space for scrollbars, due to they're hided, but
    // present in some browsers
    return placeElement( constrainElementId,
      max( 0, min( offsetFromRight + calculatePosition( sender, "Left" ),
                   getDocumentWidth() - constrainElement.offsetWidth - 1 ) ),
      max( 0, min( offsetFromTop + calculatePosition( sender, "Top" ) + sender.offsetHeight,
                   getDocumentHeight() - constrainElement.offsetHeight - 1 ) ),
      hidingDelay );
  }
  else return 0;
}

// on the top side from the sender
function placeElementWithContentOnTopFromMe( sender, constrainElementId, contentElementId, content, offsetFromRight, offsetFromTop, hidingDelay ) 
{
  // hiding to prevent bad visual effects
  //*
  hideElementById( constrainElementId );
  setElementTopById( constrainElementId, -10000 );
  setElementLeftById( constrainElementId, -10000 );
  /**/
    
  constrainElement = obtainElementById( constrainElementId );
  contentElement = obtainElementById( contentElementId );
  if ( constrainElement && contentElement )
  {
    // setting the element's content
    contentElement.innerHTML = content;
    // calculating the place of the element to be shown,and showing it
    // reserving some space for scrollbars, due to they're hided, but
    // present in some browsers
    return placeElement( constrainElementId,
      max( 0, min( offsetFromRight + calculatePosition( sender, "Left" ),
                   getDocumentWidth() - constrainElement.offsetWidth - 1 ) ),
      max( 0, min( offsetFromTop + calculatePosition( sender, "Top" ) - constrainElement.offsetHeight,
                   getDocumentHeight() - constrainElement.offsetHeight - 1 ) ),
      hidingDelay );
  }
  else return 0;
}

// on the left side from the sender
function placeElementWithContentOnLeftFromMe( sender, constrainElementId, contentElementId, content, offsetFromRight, offsetFromTop, hidingDelay ) 
{
  // hiding to prevent bad visual effects
  //*
  hideElementById( constrainElementId );
  setElementTopById( constrainElementId, -10000 );
  setElementLeftById( constrainElementId, -10000 );
  /**/
    
  constrainElement = obtainElementById( constrainElementId );
  contentElement = obtainElementById( contentElementId );
  if ( constrainElement && contentElement )
  {
    // setting the element's content
    contentElement.innerHTML = content;
    // calculating the place of the element to be shown,and showing it
    // reserving some space for scrollbars, due to they're hided, but
    // present in some browsers
    return placeElement( constrainElementId,
      max( 0, min( offsetFromRight + calculatePosition( sender, "Left" ) - constrainElement.offsetWidth,
                   getDocumentWidth() - constrainElement.offsetWidth - 1 ) ),
      max( 0, min( offsetFromTop + calculatePosition( sender, "Top" ),
                   getDocumentHeight() - constrainElement.offsetHeight - 1 ) ),
      hidingDelay );
  }
  else return 0;
}

// in the bottom right corner
function placeElementWithContentInCenter( constrainElementId, contentElementId, content, offsetFromRight, offsetFromTop, hidingDelay ) 
{
  // hiding to prevent bad visual effects
  /*
  hideElementById( constrainElementId );
  setElementTopById( constrainElementId, -10000 );
  setElementLeftById( constrainElementId, -10000 );
  /**/
    
  constrainElement = obtainElementById( constrainElementId );
  contentElement = obtainElementById( contentElementId );
  if ( constrainElement && contentElement )
  {
    // setting the element's content
    contentElement.innerHTML = content;
    // calculating the place of the element to be shown,and showing it
    // reserving some space for scrollbars, due to they're hided, but
    // present in some browsers
    //var sender = obtainElementById('tempppp');
    //alert(getWindowHeight());
    return placeElement( constrainElementId,
      max( 0, min( ( getWindowWidth() - constrainElement.offsetWidth ) / 2,
                   getDocumentWidth() - constrainElement.offsetWidth - 1 ) ),
      max( 0, min( ( getWindowHeight() - constrainElement.offsetHeight ) / 2,
                   getDocumentHeight() - constrainElement.offsetHeight - 1 ) ),
      hidingDelay );
  }
  else return 0;
}

// ------------------------------------------------------------------
// turns on the hiding the last element and showing none of the new ones
// the unprotectedElementId is the id of the element, that should
// be chancelled being protected from hiding
function startHidingLastElement( unprotectedElementId )
{
  // allowing hiding the unportected element
  if ( hintsSettings[unprotectedElementId] )
    hintsSettings[unprotectedElementId]['chancelHiding'] = false;

  newElementId = 0;
  if ( hintsSettings[lastElementId] )
    createSwitchingTimer( hintsSettings[lastElementId]['switchingTimeout'] );
}

// ------------------------------------------------------------------
// canceles hiding of the last element and showing the new one
// the protectedElementId is the id of the element, that should
// be protected from hiding
function cancelChangingElementsVisibility( protectedElementId )
{
  // if creating the new element, then not allowing to
  //  chancel changin the state, because the new element
  // woun't appear, but the previous will stay any way
  // if it is not the same as the new one
  if ( newElementId == 0 && (protectedElementId == lastElementId ) )
    deleteSwitchingTimer();
  // also denying hiding this element if it is the one, 
  // specified (the current one)
  if ( hintsSettings[protectedElementId] )
    hintsSettings[protectedElementId]['chancelHiding'] = true;
}
