  function unique(a)
  {
     var r = new Array();
     o:for(var i = 0, n = a.length; i < n; i++)
     {
        for(var x = 0, y = r.length; x < y; x++)
        {
           if(r[x]==a[i]) continue o;
        }
        r[r.length] = a[i];
     }
     return r;
  }

  var winTips=false;
  var currentTip=0;
  var siteTips=[
      'You can now organize associated files into any order you want.<br /><br />Click on &apos;Public Sorting Order&apos; under the Files tab.',
      'Images are automatically resized for the public when viewed outside this editor.<br /><br />This extra effort maximizes your users experience by preserving bandwidth.',
      'You can now push individual Calendar Events to multiple schools.<br /><br />Click on the &apos;Syndication&apos; tab to share your events!'
    ];
  function changeTip(){
    if (currentTip<0) currentTip=0; 
    if (currentTip>siteTips.length-1) currentTip=siteTips.length-1; 
    Ext.getCmp('tip_prev').setDisabled(currentTip==0);
    Ext.getCmp('tip_next').setDisabled(currentTip==siteTips.length-1);
    $('tipText').update(siteTips[currentTip]);
  }
  function showTips(){
    if (winTips){
      winTips.show(this);
      return false;
    }
    currentTip=Math.floor(Math.random()*(siteTips.length));
    winTips = new Ext.Window({
      width:400,
      height:300,
      title:'Tip of the Day',
      layout:'border',
      closeAction:'close',
      modal:false,
      resizable:false,
      closable:true,
      border:false,
      items: [{
                region: 'west',
                width: 65,
                bodyStyle: 'background: #eee url(/common/images/info.png) 17px 15px no-repeat;',
                html: '&nbsp;'
              },{
                region: 'center',
                bodyStyle: 'font-size: 14px; padding: 20px 15px 15px',
                html: '<strong>Tip of the day</strong><br /><br /><div id="tipText">Loading Tip...</div>'
              },{
                region: 'south',
                height: 30,
                border:true,
                bodyStyle: 'background: #efe; padding: 5px 6px;',
                html: '<input type="checkbox" id="showTipStartup" '+(autoShowTip?'checked="checked"':'')+' style="position: relative; top: 2px;"/>&nbsp; <label for="showTipStartup">Show Tips on First Edit</label>'
              }],
      buttonAlign: 'left',
      fbar: [{
              text: 'Prev',
              id: 'tip_prev',
              handler: function(){ currentTip--; changeTip(); }
            },{
              text: 'Next',
              id: 'tip_next',
              handler: function(){ currentTip++; changeTip(); }
            },'->',{
              text: 'Close',
              handler: function(){ winTips.close(); }
            }],
      listeners: {
        show: function(){ changeTip(); },
        close: function(){ 
          autoShowTip = $('showTipStartup').checked; 
          new Ajax.Request('/ajax/tips/showStartup.cfm?v='+(autoShowTip?1:0));
          if(autoShowTipOnce){
            autoShowTipOnce=false;
            autoShowTip=false;
          }
        },
        destroy: function(){winTips=false;  }
      }
    });
    winTips.show(this);
  }
 
  var journeyHelper = {
    isRunning: false,
    currentAnimSet: null,
    lastState: '',
    lastStateMouth: '',
    lastStateBody: '',
    lastStateBodyShadow: '',
    closing: false,
    blinking: false,
    blinkTimer: false,
    eyeTimer: false,
    mouthTimer: false,
    shadowEffect: false,
    bodyEffect: false,
    showInitMsg: true,
    titleElements: [],
    forceWait: true,
    canClearForceWait: false,
    updateBody: function(style, report, noExtra){
      var _self = this;
      if (this.closing)
        return false;
      var curBody = this.currentAnimSet.getPoseFromBank('body', style);
      var bodyHolder = $('journey_body_skin');
      var bodyFace = $('journey_face');
      bodyHolder.style.top = curBody.top+'px';
      bodyHolder.style.left = curBody.left+'px';
      bodyHolder.style.width = curBody.width+'px';
      bodyHolder.style.height = curBody.height+'px';
      bodyFace.style.top = curBody.facetop+'px';
      bodyFace.style.left = curBody.faceleft+'px';
      bodyHolder.style.backgroundImage = 'url('+this.currentAnimSet.bank.body.image+')';
      bodyHolder.style.backgroundPosition = curBody.xoff+'px '+curBody.yoff+'px';
      if (report)
        this.lastStateBody = style;
    },
    updateBodyShadow: function(style, report){
      var _self = this;
      if (this.closing)
        return false;
      var curBody = this.currentAnimSet.getPoseFromBank('shadow', style);
      var shadowFace = $('journey_body_shadow');
      shadowFace.style.top = curBody.top+'px';
      shadowFace.style.left = curBody.left+'px';
      shadowFace.style.width = curBody.width+'px';
      shadowFace.style.height = curBody.height+'px';
      shadowFace.style.backgroundImage = 'url('+this.currentAnimSet.bank.shadow.image+')';
      shadowFace.style.backgroundPosition = curBody.xoff+'px '+curBody.yoff+'px';
      if (report)
        this.lastStateBodyShadow = style;
    },
    updateEyes: function(style, report){
      if (this.closing)
        return false;
      var curEyes = this.currentAnimSet.getPoseFromBank('eyes', style);
      var eyeHolder = $('journey_eyes');
      eyeHolder.style.position = 'absolute';
      eyeHolder.style.top = curEyes.top+'px';
      eyeHolder.style.left = curEyes.left+'px';
      eyeHolder.style.width = curEyes.width+'px';
      eyeHolder.style.height = curEyes.height+'px';
      eyeHolder.style.backgroundImage = 'url('+this.currentAnimSet.bank.eyes.image+')';
      eyeHolder.style.backgroundPosition = curEyes.xoff+'px '+curEyes.yoff+'px';
      if (report)
        this.lastState = style;
    },
    updateMouth: function(style, report){
      if (this.closing)
        return false;
      var curMouth = this.currentAnimSet.getPoseFromBank('mouth', style);
      var mouthHolder = $('journey_mouth');
      mouthHolder.style.position = 'absolute';
      mouthHolder.style.top = curMouth.top+'px';
      mouthHolder.style.left = curMouth.left+'px';
      mouthHolder.style.width = curMouth.width+'px';
      mouthHolder.style.height = curMouth.height+'px';
      mouthHolder.style.backgroundImage = 'url('+this.currentAnimSet.bank.mouth.image+')';
      mouthHolder.style.backgroundPosition = curMouth.xoff+'px '+curMouth.yoff+'px';
      if (report)
        this.lastStateMouth = style;
    },
    close : function(){
      this.startDestroy();
    },
    startDestroy: function(){
      var _self = this;
      this.isRunning=false;
      this.shadowEffect.cancel();
      this.bodyEffect.cancel();
      clearTimeout(this.blinkTimer);
      clearTimeout(this.eyeTimer);
      clearTimeout(this.mouthTimer);
      clearTimeout(this.squeezeTimer);
      this.updateEyes('up', true);
      this.updateMouth('surprised', true);
      this.closing = true;
      new Effect.Opacity('journey_body_shadow', { from: 0.6, to: 1.0, duration: .5, delay: .5});
      new Effect.Parallel([
          new Effect.Move('journey_body', {sync: true, x: 0, y: 20, mode: 'relative'}),
          new Effect.Fade('journey_text', { sync: true}),
          new Effect.Fade('journey', { sync: true, afterFinish: _self.destroy})
        ],{
          duration: 1.5
        });
    },
    destroy: function(){
      if ($('journey'))
        $('journey').remove();
      if ($('journey_text'))
        $('journey_text').remove();  
    },
    showText: function(text, forceWait, hideDelay, squeezeTo, squeezeOutTo){
      var _self = this;
      this.resetMoves();
      if (this.forceWait && !forceWait)
        return false;        
      
      if (this.hideTextFn)
        this.hideTextFn(function(){_self.showTextAction(text, forceWait, hideDelay, squeezeTo, squeezeOutTo);});
      else
        this.showTextAction(text, forceWait, hideDelay, squeezeTo, squeezeOutTo);
    },
    showTextAction: function(text, forceWait, hideDelay, squeezeTo, squeezeOutTo){
      var _self = this;
      if ($('journey_text'))
        $('journey_text').remove();
        
      this.forceWait = forceWait;
        
      if (squeezeTo)
        this.squeezeTo(squeezeTo);
      this.blink('info');
      this.updateMouth('teeth-open', true);
      
      var divText = new Element('div', { 'id': 'journey_text', 'style' : 'display: none; position: fixed; right: 10px; bottom: 120px; z-index: 14500;' });      
      var mainTextBody = new Element('div', { 'id': 'journey_body', 'style': 'border: 1px solid black; width: 200px; padding: 10px; background: #FFFFCC; -webkit-border-radius: 10px; -moz-border-radius: 10px;'}).update(text);
      mainTextBody.observe('click', function(){_self.hideText(squeezeOutTo)});
      var mainTextSticker = new Element('div', { 'style': 'float: right; margin: -1px 50px 0 0; background: url(/common/images/toolTipStickout.png); width: 11px; height: 6px;'});

      divText.appendChild(mainTextBody);
      divText.appendChild(mainTextSticker);      
      document.body.appendChild(divText);
            
      new Effect.Appear('journey_text', {duration: 0.25});
      this.hideTextFn = function(thenShow){_self.hideText(squeezeOutTo, thenShow);};
      if (hideDelay)
        this.hideTextTimer = setTimeout(function(){_self.hideTextFn();}, hideDelay);
    },
    hideTextFn: null,
    hideText: function(squeezeTo, thenShow){
      var _self = this;
      this.hideTextFn = null;
      if (squeezeTo)
        this.squeezeTo(squeezeTo);
      this.blink('up-left');
      this.updateMouth('worried', true);
      if ($('journey_text')){
        new Effect.Fade('journey_text', {duration: .25, afterFinish: function(){
                                                                    if(_self.canClearForceWait)
                                                                      _self.forceWait=false;
                                                                    _self.canClearForceWait = true;
                                                                    if (thenShow)
                                                                      thenShow();
                                                                  }});

      }

    },
    contextMenu: new Ext.menu.Menu({
          items: [{
            id: 'mnu_item-journey_animate',
            text: 'Make a face!',
            handler: function(){
              journeyHelper.resetMoves();
              journeyHelper.blink(journeyHelper.currentAnimSet.getRandomPoseNameFromBank('eyes'));
              journeyHelper.updateMouth(journeyHelper.currentAnimSet.getRandomPoseNameFromBank('mouth'), true);
            }
          },'-',/*{
            text: 'Show Stoppy!',
            handler: function(){
              journeyHelper.squeezeTo('stoppy');
          },{
            text: 'Show Yeildy!',
            handler: function(){
              journeyHelper.squeezeTo('info');
          }{
            text: 'Show Journey!',
            handler: function(){
              journeyHelper.squeezeTo('normal');
          },'-',*/{
            id: 'mnu_item-journey_close',
            text: 'Close Journey',
            handler: function(){
              journeyHelper.close();
            }
          }]
    }),
    activeHelpTopic : false,
    setHelpTopic : function(topic){
      if (!this.helpTopics)
        return false;
      this.activeHelpTopic = this.helpTopics[topic];
    },
    showHelpTopic : function(){
      if (!this.activeHelpTopic)
        return false;
      this.showText(this.activeHelpTopic.html, true, null, 'info', 'normal');
    },
    show : function(animSet, helpTopics){
      if (!animSet)
        return false;
        
      if (!helpTopics){
        delete this.helpTopics;
        this.activeHelpTopic = false;
      }else{
        this.helpTopics = helpTopics;
        helpTopics['default'] ? this.setHelpTopic('default') : false;
      }
        
      var _self = this;
      this.currentAnimSet = animSet;
      this.destroy();
      this.isRunning=true;
      var div = new Element('div', { 'id': 'journey', 'style' : 'display:none; position: fixed; right: 40px; bottom: 40px; z-index: 14000' });
      
      var mainBody = new Element('div', { 'id': 'journey_body', 'title' : 'Click me for help!', 'style': 'position: relative;'});
      var mainBodySkin = new Element('div', { 'id': 'journey_body_skin', 'title' : 'Click me for help!', 'style': 'position: relative;'});
      mainBody.observe('click', function(){_self.showHelpTopic();});
      var mainBodyShadow = new Element('div', { 'id': 'journey_body_shadow', 'style': 'position: relative;'});
      
      var mainFace = new Element('div', { 'id': 'journey_face','style': 'position: relative; top: 0; left: 0;'});
      var mainBodyEyes = new Element('div', { 'id': 'journey_eyes'});
      var mainBodyMouth = new Element('div', { 'id': 'journey_mouth'});
            
      Event.observe(mainBody, 'contextmenu', function(e){
        Event.stop(e);
        //c.findById('mnu_item-hide').setVisible(node.getUI().isChecked());
        //c.findById('mnu_item-rename').setDisabled(node.attributes.topbar);
        journeyHelper.contextMenu.showAt([Event.pointerX(e)-110,Event.pointerY(e)+10]);
      });
      
      
      var tmpEls = [];
      $$('*[alt], *[title], *[jt]').each(function(s){
        var title = s.title || s.alt;
        s.title = null;
        s.alt = null;
        s.jt = title;
        if (title){
          if (title.indexOf('|||JT:') > -1){
            var tmpSplit = title.split('|||JT:');
            if (tmpSplit.length>1)
              s.jt = tmpSplit[1];
          }
          tmpEls.push(s); 
        }
      });
      tmpEls = unique(tmpEls);
      tmpEls.each(function(s){
        if (s.jt){
          s.observe('mouseover', function(){_self.showText(s.jt, false, null);});
          s.observe('mouseout', function(){_self.hideText();});
        }
      });
      this.titleElements = unique(tmpEls);
      
      mainFace.appendChild(mainBodyEyes);
      mainFace.appendChild(mainBodyMouth);
      
      mainBodySkin.appendChild(mainFace);
      mainBody.appendChild(mainBodySkin);
      div.appendChild(mainBody);
      div.appendChild(mainBodyShadow);
      
      document.body.appendChild(div);
      
      this.updateBody('normal', true, true);
      this.blink('heart');
      this.updateMouth('smile', true);
      this.updateBodyShadow('normal', true);
      
      
      var divView = div.viewportOffset();
      new Effect.Opacity('journey_body_shadow', { from: 0.0, to: 0.0, duration: 0.1});
      //$('journey_body').style.left = (parseInt($('journey_body').style.left,10)-40) + 'px';
      //new Effect.Move('journey_body', {duration: 1.5, transition: Effect.Transitions.spring, x: 0, y: 40, mode: 'relative'});
      new Effect.Appear('journey', {duration: 0.5});
      new Effect.Opacity('journey_body_shadow', {from: 0.0, to: 1.0, duration: 0.3, afterFinish: function(){
        new Effect.Opacity('journey_body_shadow', {from: 1.0, to: 0.3, duration: 0.3, afterFinish: function(){
          new Effect.Opacity('journey_body_shadow', {from: 0.3, to: 0.6, duration: 0.3, afterFinish: function(){
            _self.hoverFloat();
          }})
        }});
      }});
      
      if (helpTopics[History.get('jh')]){
        this.setHelpTopic(History.get('jh'));
        this.showHelpTopic();
      }

/*      
      if(History.get('jh')==1)
        this.showText('Was my advice helpful?<br /><br />Choose: <a href="javascript:void(0);" onclick="setTimeout(function(){journeyHelper.showText(\'<center>I knew it!</center>\', true, 3000); journeyHelper.blink(\'half\'); journeyHelper.updateMouth(\'teeth\', true);},200);">yes</a> | <a href="javascript:void(0);" onclick="setTimeout(function(){journeyHelper.showText(\'<center>LUIS!!!</center>\', true, 3000); journeyHelper.blink(\'wide\'); journeyHelper.updateMouth(\'yell\', true);},200);">no</a>', true, null, 'stoppy', 'normal');
      else{
        if (this.showInitMsg){
          setTimeout(function(){
            _self.forceWait=false;
            if (_self.showInitMsg){
              _self.showText('<center><strong>Hi!</strong> I\'m Journey!<br />Click me if you need help!</center>', true, 4000);
            }
          }, 3000);
        }else{
          _self.forceWait=false;
        }
      }
*/
      _self.forceWait=false;
      this.resetMoves();
    },
    squeezeTo : function(thenShow){
      this.squeezing=true;
      var _self = this;
      this.updateBody('squeeze', true);
      this.squeezeTimer = setTimeout(function(){
                    _self.updateBody(thenShow, true);
                    _self.squeezing=false;
                  }, 50);
      
    },
    blink : function(thenShow){
      if (thenShow)
        this.lastState = thenShow;
      this.blinking=true;
      var _self = this;
      if (this.lastState == 'error' && thenShow == 'error'){
        return false;
      }
      this.updateEyes('closed');
      this.blinkTimer = setTimeout(function(){
                    _self.updateEyes(_self.lastState);
                    _self.blinking=false;
                    if (Math.round(Math.random()*5)==3){ //double blink
                      var blinkSpeed = 900 + Math.round(Math.random()*1600);
                      _self.blinkTimer = setTimeout(function(){_self.blink();}, blinkSpeed);
                    }
                  }, 50);
      
    },
    resetMoves : function(delay){
      var _self = this;
      var myDelay = delay ? delay : 6000;
      clearTimeout(this.eyeTimer);
      clearTimeout(this.mouthTimer);
      clearTimeout(this.hideTextTimer);
      this.eyeTimer = setTimeout(function(){_self.randMoves();}, myDelay);
      this.mouthTimer = setTimeout(function(){_self.randMovesMouth();}, myDelay);
    },
    randMoves : function(){
      var _self = this;
      var moveSpeed = 4000 + Math.round(Math.random()*3000);
      this.eyeTimer = setTimeout(function(){_self.randMoves();}, moveSpeed);
      if (this.blinking)
        return false;      
      this.blink(this.currentAnimSet.getRandomPoseNameFromBank('eyes'));
    },
    randMovesMouth : function(){
      var _self = this;
      var moveSpeed = 4000 + Math.round(Math.random()*3000);
      this.mouthTimer = setTimeout(function(){_self.randMovesMouth();}, moveSpeed);
      if (this.blinking)
        return false;      
      this.updateMouth(this.currentAnimSet.getRandomPoseNameFromBank('mouth'), true);
    },
    hoverFloat : function(){
      var _self = this;
      this.shadowEffect = new Effect.Opacity('journey_body_shadow', {duration: 2.5, from: 0.6, to: 0.8, mode: 'relative', afterFinish: function(){
        _self.shadowEffect = new Effect.Opacity('journey_body_shadow', {duration: 2.5, from: 0.8, to: 0.6, mode: 'relative'});
      }});
      this.bodyEffect = new Effect.Move('journey_body', {duration: 2.5, x: 0, y: 5, mode: 'relative', afterFinish: function(){
        _self.bodyEffect = new Effect.Move('journey_body', {duration: 2.5, x: 0, y: -5, mode: 'relative', afterFinish: function(){
          _self.hoverTimer = setTimeout(function(){_self.hoverFloat();}, 10);
        }});
      }});
      
    }
  };
    

  var helpTopicsV1 = {
    'default': {
      html: 'What kind of assistance do you need?<br /><br />&bull; <a href="/District/schoollist#jh=fmcsw">Finding My Child\'s School Website</a><br /><br />&bull; <a href="/'+currentSchool.Alias+'/staff#jh=sfsm">Search for a staff member for this location</a>'
    },
    settings_edit: {
      html: '<strong>General Site Information</strong><br />Here you can define information such as your site name and contact information.<br /><br />You can also setup swear filtering, webmail, and various other features.'
    },
    navigation_edit: {
      html: '<strong>Site Navigation</strong><br />Drag modules from the right to the tree on the left to start adding new content! Wee!<br /><br />Right click a node on the left to perform actions such as edit, hide or delete.<br /><br />Modules, Links & Pages are only permitted inside horizontal or vertical \'containers\'. '
    },
    school_edit: {
      html: '<strong>School Organizer</strong><br />Here you can define which categories best fit your schools.<br /><br />Drag your schools around to organize them. I don\'t mind.'
    },
    department_edit: {
      html: '<strong>Department Organizer</strong><br />This is where you create your departments. Drag a new department from the right to the main tree to create one.<br /><br />Departments must be placed inside a Category and do not support nesting. Shucks.'
    },
    class_edit: {
      html: '<strong>Class Organizer</strong><br />This is where you create your classes. Drag a new class from the right to the main tree to create one.<br /><br />Classes must be placed inside a Category and do not support nesting. Shucks.'
    },
    forum_edit: {
      html: '<strong>Forum Topic Organizer</strong><br />This is where you manage your forum topics. Drag a new forum category from the right to the main tree to create one. Woo Hoo!'
    },
    category_edit: {
      html: '<strong>Category Organizer</strong><br />This is where you manage your categories. Drag a new category from the right to the main tree to create one.<br /><br />While categories do not currently support nesting, they will in a future update. :D'
    },
    gallery_upload: {
      html: '<strong>Photo Upload</strong><br />This is where you upload photos'    
    },
    'fmcsw': {
      html: 'To visit your school website, browse for your school and then click on the link!'
    },
    'sfsm': {
      html: 'Here you can browse the staff for this location.<br /><br />Use the search box inside the staff list to narrow down your results!'
    }
  
  }

  var animSettings = {
    //future!
  };    
    
  //if (!Ext.isIE && !printView)
    Ext.onReady(function(){journeyHelper.show(animJourney, helpTopicsV1);});

