if (typeof PS !== 'undefined' && typeof Prototype !== 'undefined') {

  PS.TipBox = Class.create({
      
      /**
       * initialize(catNav, contentList, dayNav, dayClassNames)
       * - catNav (DOM ref): The category navigation. Usually a ul-element.
       * - contentList (DOM ref): The HTML list element in which the category content resides
       * - dayNav (DOM ref) [optional]: If there are multiple days, this points to the day navigation.
       * - dayClassNames (Array) [optional]: If dayNav is defined, these are its active class names
       * 
       * Constructor.
       */
      initialize: function (catNav, contentList, dayNav, dayClassNames) {
  
          var _days = [];
          
          this.hasDayNav = dayNav && dayClassNames;
          
          if (this.hasDayNav) {
              this.dayNav = dayNav;
  
              // Array of CSS class names for dayNav active state
              this.dayClassNames = dayClassNames;
          }
          this.catNav = catNav;
          
          // Current active day
          // always 1 if there is no dayNav, aka no multiple days
          this.day = this.hasDayNav ? null : 1;
  
          this.lastActiveDay = null;
          this.lastActiveCatId = null;
          this.lastActiveCatElem = null;
          
          // Storage Hash, used for each days' categories and content elements
          this.contents = $H({});
          
          // For switchCat() effects, we need to make sure the content area
          // is wrapped in a positioned element
          contentList.wrap('div').makePositioned();
          
          // Detect the unique days and hide content nodes per default
          contentList.childElements().each(function (node) {
              _days.push(node.readAttribute('data-day'));
              node.hide();
          });
          _days = _days.uniq();
          
          // Fill storage Hash
          _days.each(function (s) {
              
              //TODO:
              //activate and insert dayNav links only if the appropriate day has content
  
              var _items = contentList.select('[data-day="' + s + '"]');
  
              this.contents.set('day-'+s, {
                  categories: (function () {
                      var catIds = [];
                      _items.each(function (node) { catIds.push(node.readAttribute('data-genre-id')); });
                      return catIds;
                  }()),
                  items: _items
              });
          }.bind(this));
          
          // Show the first day per default
          this._switchDay(_days.min());
          
          // Event handlers
          catNav.on('click', 'a', function (e, node) {
              var id = node.up().readAttribute('data-genre-id');
              this._switchCat(id);
              
              if (this.autoSwitch) {
                  this.autoSwitch.stop();
              }
              
              e.stop();
          }.bind(this));
          
          if (this.hasDayNav) {
              dayNav.on('click', 'a', function (e, node) {
                  var id = node.readAttribute('data-day');
                  this._switchDay(id);
                  
                  if (this.autoSwitch) {
                    this.autoSwitch.stop();
                  }
                  
                  e.stop();
              }.bind(this));
          }
          
          this.autoSwitch = new PeriodicalExecuter(this._switchToNextCat.bind(this), 5);
  
      },
  
      _switchDay: function (day) {
        
          // If there's no such day, do nothing
          if (!this._getDay(day)) {
              return;
          }
          
          // Remember the day
          this.day = day;
          
          // First, check which categories are available for and activate them
          this._activateCats();
          
          if (this.lastActiveCatId && this.lastActiveCatElem) {
              // not first start, last active cat id and element is available
  
              if (this._getDay(day).categories.include(this.lastActiveCatId)) {
                  // last active category is available in this day, show it
                  this._switchCat(this.lastActiveCatId);
              } else {
                  // last active category is not available in this day
                  // show first available category instead
                  this._switchCat(this._getDay(day).categories.first());
              }
              
          } else {
              // first start, show first available category
              this._switchCat( this._getDay(day).categories.first() );
          }
          
          if (this.hasDayNav) {
              // Set dayNav CSS active class name
              this.dayNav.className = this.dayClassNames[this.day - 1];
          }
  
      },
      
      _activateCats: function () {
  
           var _cats = this._getDay(this.day).categories;
           
           // If we have a current day...
           if (this.day) {
              
              // for each catNav child node, check if value of data-genre-id attr
              // is in _cats array. activate if true, deactivate if not
              this.catNav.childElements().each(function (node) {
                  
                  if ( _cats.include( node.readAttribute('data-genre-id') ) ) {
                      if (!node.down('a')) {
                          node.update(new Element('a', { href: '' }).update(node.innerHTML));
                      }
                  } else {
                      var anchor = node.down('a');
                      if (anchor) {
                          node.update(anchor.innerHTML);
                      }
                  }
              
              });
  
           }
  
      },
      
      _switchCat: function (id) {
  
          var catLink, catElem;
  
          if (!this.lastActiveCatElem && !this.lastActiveCatId) {
              // No last active category id or element = first start
  
              // Cat link
              catLink = this.catNav.down('[data-genre-id="' + id + '"]').down();
              
              // Remember active category element and id for next interaction
              this.lastActiveCatElem = this._getDay(this.day).items.first();
              this.lastActiveCatId = id;
              
              // Show content
              this.lastActiveCatElem.show();
          } else {
              
              if (this.lastActiveCatId === id && this.lastActiveDay === this.day) {
                  // already open, do nothing
                  return;
              }
  
              // Get the new active category element
              catElem = this._getDay(this.day).items.find(function (o) {
                  return o.readAttribute('data-genre-id') === id;
              });
  
              // Position last active category element
              this.lastActiveCatElem.setStyle({
                  position: 'absolute',
                  left: 0,
                  zIndex: 2
              });
              
              // Position new active category element behind last
              catElem.setStyle({
                  display: 'block',
                  position: 'absolute',
                  left: 0,
                  zIndex: 1
              });
      
              // Fade last active category element to make the new appear
              new Effect.Fade(this.lastActiveCatElem, {
                  duration: 0.3,
                  fps: 15
              });
              
              // Cat link
              catLink = this.catNav.down('[data-genre-id="' + id + '"]').down();
              
              // Remember last active category element for next interaction
              this.lastActiveCatElem = catElem;
          }
          
          // Set active class names...
          if (this.lastActiveCatLink) {
              this.lastActiveCatLink.removeClassName('active');
          }
          catLink.addClassName('active');
  
          // Remember active category link element and id for next interaction
          this.lastActiveCatLink = catLink;
          this.lastActiveCatId = id;
          
          // Remember active day for next interaction
          this.lastActiveDay = this.day;
  
      },
      
      _switchToNextCat: function () {
          var nextId = (function () {
              var cats = this._getDay(this.day).categories,
                  index = cats.indexOf(this.lastActiveCatId);
              return cats[index+1] ? cats[index+1] : cats[0];
          }.bind(this)());
          this._switchCat(nextId);
      },
  
      _getDay: function (id) {
          return this.contents.get('day-' + id);
      }
  
  });

}
