/**
 * @author TobiasTrozowski
 * @constructor
 * @returns {TuneUpTuningmode}
 */
function TuneUpTuningmode( )
{
  AbstractTuneUpClass.apply(this, arguments);
}
TuneUpTuningmode.prototype = new AbstractTuneUpClass( );

AbstractTuneUpClass.extend(TuneUpTuningmode.prototype, {
  /**
   * define tuning modes
   */
  tuningmodes : {
    standard : 0,
    turbo : 1,
    eco : 2
  },
  tuningmodeStandard : 0,
  tuningmodeTurbo : 1,
  tuningmodeEco : 2,

  tuningmodeStandardId : 'tuning-standard',
  tuningmodeTurboId : 'tuning-turbo',
  tuningmodeEcoId : 'tuning-eco',

  tuningModeButtonId : false,

  currentlyActiveButton : false,

  /**
   * tuningmode currently in progress?
   */
  tuningmodeInProgress : false,

  /**
   * current status
   */
  tuningmodeStatus : 0,

  /**
   * next tuning status
   */
  tuningmodeNextStatus : 0,

  /**
   * throbber settings
   */
  throbberSettings : {
    timeoutId : null
  },
  throbberCurIteration : 0,

  /**
   * parameters for the progress bar that measures how far the mode switching process has gone
   */
  progressBar : {
    backgroundImageMinXPosition : -1,
    length : 140
  },

  /**
   * Internal constructor
   * 
   * @returns {TuneUpTuningmode}
   */
  initialize : function( )
  {
    console.debug("TuneUpTuningmode.initialize()");

    // singleton implementation
    if (TuneUpTuningmode.instance !== undefined) {
      return TuneUpTuningmode.instance;
    }

    tuDispatcher.bind('updateTuningmode', function(evt, mode)
    {
      this.updateTuningmode(mode);
    }, this).bind('updateTuningmodeProgress', function(evt, mode, progress)
    {
      this.updateTuningmodeProgress(mode, progress)
    }, this);

    TuneUpTuningmode.instance = this;

    return TuneUpTuningmode.instance;
  },
  /**
   * Bind Button-Effects to the tuning-buttons - Bound Effects: activated, hovered, pressed, progress, disabled
   * 
   * @returns void
   */
  bindButtonEffects : function( )
  {
    console.debug("TuneUpTuningmode.bindButtonEffects()");

    // remove all states from buttons
    jQuery('.button-tuningarea').removeClass('activated hovered pressed progress disabled');

    // add activated state to button
    if (this.tuningmodeStatus == this.tuningmodeStandard) {
      jQuery('#tuning-standard').parent( ).parent( ).parent( ).addClass('activated');
    } else if (this.tuningmodeStatus == this.tuningmodeTurbo) {
      jQuery('#tuning-turbo').parent( ).parent( ).parent( ).addClass('activated');
    } else if (this.tuningmodeStatus == this.tuningmodeEco) {
      jQuery('#tuning-eco').parent( ).parent( ).parent( ).addClass('activated');
    }

    this.currentlyActiveButton = jQuery('.button-tuningarea.activated > div > div > button');

    jQuery('.button-tuningarea > div > div > button').unbind('mousedown mouseout');

    jQuery('.button-tuningarea > div > div > button').bind('mousedown', jQuery.proxy(function(event)
    {

      if (event.target.id != this.currentlyActiveButton.attr('id')) {
        jQuery('#' + event.target.id).parent( ).parent( ).parent( ).addClass('disabled');
        this.currentlyActiveButton.parent( ).parent( ).parent( ).removeClass('activated');
      }

    }, this));

    jQuery('.button-tuningarea > div > div > button').bind('mouseout', jQuery.proxy(function(event)
    {
      // if the status is not the same as the next status, it means that the onclick event has already started, so
      // don't bother doing the mouseout
      if (this.tuningmodeStatus == this.tuningmodeNextStatus) {
        if (jQuery('#' + event.target.id).parent( ).parent( ).parent( ).hasClass('disabled')) {
          jQuery('#' + event.target.id).parent( ).parent( ).parent( ).removeClass('disabled');
        }

        if (!this.currentlyActiveButton.parent( ).parent( ).parent( ).hasClass('activated')) {
          this.currentlyActiveButton.parent( ).parent( ).parent( ).addClass('activated');
        }
      }

    }, this));

    return this;
  },

  /**
   * Release all events from tuning-buttons
   * 
   * @returns void
   */
  unbindButtonEffects : function( )
  {
    console.debug("TuneUpTuningmode.unbindButtonEffects()");
    // remove all states from buttons
    // jQuery( '.tuning-led > div > div' ).addClass( 'no-display' );
    jQuery('.button-tuningarea').removeClass('activated hovered pressed progress disabled');
    jQuery('.button-tuningarea > div > div > button').unbind('mousedown mouseup mouseover mouseout');

    return this;
  },

  /**
   * @param event
   */
  onButtonClickEvent : function(event)
  {
    console.debug("TuneUpTuningmode.onButtonClickEvent(", arguments, ")");

    switch (event.target.id)
    {
      case this.tuningmodeEcoId:
        this.setMode(this.tuningmodeEco);
        break;
      case this.tuningmodeStandardId:
        this.setMode(this.tuningmodeStandard);
        break;
      case this.tuningmodeTurboId:
        this.setMode(this.tuningmodeTurbo);
        break;
    }
    return this;
  },

  /**
   * 
   */
  bindButtonActions : function( )
  {
    console.debug("TuneUpTuningmode.bindButtonActions()");
    jQuery('.button-tuningarea > div > div > button').bind('click', jQuery.proxy(function(event)
    {
      this.onButtonClickEvent(event);
    }, this));
    return this;
  },

  /**
   * 
   */
  unbindButtonActions : function( )
  {
    console.debug("TuneUpTuningmode.unbindButtonActions()");
    jQuery('.button-tuningarea > div > div > button').unbind('click');
    return this;
  },

  /**
   * 
   */
  bindButtonAnimation : function( )
  {
    console.debug("TuneUpTuningmode.bindButtonAnimation()");

    jQuery('.pillarcontent-item-tuningmode').removeClass('in-progress mode-active mode-inactive');
    jQuery('.pillarcontent-item-tuningmode').addClass('mode-inactive');

    if (this.tuningmodeNextStatus == this.tuningmodeStandard) {
      jQuery('#tuning-standard').parent( ).parent( ).parent( ).addClass('disabled');
      jQuery('#tuning-turbo').parent( ).parent( ).parent( ).addClass('progress');
      jQuery('#tuning-eco').parent( ).parent( ).parent( ).addClass('progress');

      jQuery('#allfunctions-tuningmode-standard').removeClass('mode-inactive');
      jQuery('#allfunctions-tuningmode-standard').addClass('in-progress');

      // this.progressAnimation( );
    } else if (this.tuningmodeNextStatus == this.tuningmodeTurbo) {
      jQuery('#tuning-turbo').parent( ).parent( ).parent( ).addClass('disabled');
      jQuery('#tuning-standard').parent( ).parent( ).parent( ).addClass('progress');
      jQuery('#tuning-eco').parent( ).parent( ).parent( ).addClass('progress');

      jQuery('#allfunctions-tuningmode-turbo').removeClass('mode-inactive');
      jQuery('#allfunctions-tuningmode-turbo').addClass('in-progress');

      // this.progressAnimation( );
    } else if (this.tuningmodeNextStatus == this.tuningmodeEco) {
      jQuery('#tuning-eco').parent( ).parent( ).parent( ).addClass('disabled');
      jQuery('#tuning-turbo').parent( ).parent( ).parent( ).addClass('progress');
      jQuery('#tuning-standard').parent( ).parent( ).parent( ).addClass('progress');

      jQuery('#allfunctions-tuningmode-eco').removeClass('mode-inactive');
      jQuery('#allfunctions-tuningmode-eco').addClass('in-progress');

      // this.progressAnimation( );
    }

    return this;
  },

  /**
   * 
   */
  unbindButtonAnimation : function( )
  {
    console.debug("TuneUpTuningmode.unbindButtonAnimation()");
    if (this.throbberSettings.timeoutId != null) {
      clearTimeout(this.throbberSettings.timeoutId);
    }

    // hide in progress state
    jQuery('.pillarcontent-item-tuningmode').removeClass('in-progress mode-active mode-inactive');
    jQuery('.pillarcontent-item-tuningmode').addClass('mode-inactive');

    if (this.tuningmodeStatus == this.tuningmodeStandard) {
      jQuery('#allfunctions-tuningmode-standard').removeClass('mode-inactive');
      jQuery('#allfunctions-tuningmode-standard').addClass('mode-active');
    } else if (this.tuningmodeStatus == this.tuningmodeTurbo) {
      jQuery('#allfunctions-tuningmode-turbo').removeClass('mode-inactive');
      jQuery('#allfunctions-tuningmode-turbo').addClass('mode-active');
    } else if (this.tuningmodeStatus == this.tuningmodeEco) {
      jQuery('#allfunctions-tuningmode-eco').removeClass('mode-inactive');
      jQuery('#allfunctions-tuningmode-eco').addClass('mode-active');
    }

    return this;
  },

  /**
   * progressAnimation: function not used right now
   */
  /*
   * progressAnimation : function( ) { return this; },
   */

  /**
   */
  updateTuningmode : function(mode)
  {
    console.debug("TuneUpTuningmode.updateTuningmode(", arguments, ")");

    if (!isInteger(mode)) {
      console.warn("Cannot switch to an unknown tuningmode.");
      return this;
    }
    this.tuningmodeStatus = mode;
    this.tuningmodeNextStatus = mode;

    if (!this.inProgress( )) {
      this.unbindButtonActions( ).unbindButtonEffects( );
    }

    this.unbindButtonAnimation( ).bindButtonEffects( ).bindButtonActions( );

    if (this.inProgress( )) {
      this.toggleInProgress( );
    }
    return this;
  },

  /**
   * @param percent
   */
  updateTuningmodeProgress : function(mode, progress)
  {
    console.debug("TuneUpTuningmode.updateTuningmodeProgress(", arguments, ")");
    // we got the progress state, so switch everything in progress
    if (!this.inProgress( ) && ( progress < 100.0 )) {
      if (mode !== undefined && ( mode != this.tuningmodeStatus )) {
        this.inProgress(true);
        this.tuningmodeNextStatus = mode;
        this.setMode(mode, false);
      }

      this.unbindButtonEffects( ).unbindButtonActions( ).bindButtonAnimation( );
    } else if (progress == 100) {
      // this is to deal with the special case in which turbo or eco mode is not yet configured and the user quits.
      // if we reach progress=100 normally, this.tuningmodeStatus should always be the same as
      // this.tuningmodeNextStatus.
      // if not, set the mode back to the old mode.
      if (this.tuningmodeStatus != this.tuningmodeNextStatus) {
        this.tuningmodeNextStatus = this.tuningmodeStatus;
        this.unbindButtonActions( ).unbindButtonEffects( ).unbindButtonAnimation( ).bindButtonEffects( ).bindButtonActions( );
      }
    } else {
      // update progress
    }

    // update the progress bar
    this.updateProgressBar(mode, progress);

    return this;
  },

  /**
   * @param mode
   */
  setMode : function(mode, service)
  {
    if (service !== false) {
      service = true;
    }
    console.debug("TuneUpTuningmode.setMode(", arguments, ")");

    if (this.inProgress( )) { // return if tuning status is currently in progress
      console.error("Cannot change mode, tuning status currently is in progress.");
      return this;
    }

    if (isInteger(mode)) {
      if (( mode == this.tuningmodeStatus )) {
        // remove the following comment to enable fallback to standard mode if any button pressed twice
        // mode = this.tuningmodeStandard;
        return this;
      }

      this.tuningmodeNextStatus = mode;

      if (service) {
        tuDispatcher.trigger("highspeed", mode);
        this.send(String.format("#highspeed:%d", mode));
      }
    }
    return this;
  },

  /**
   * If param mode is given, set to new mode and return old mode, otherwise just return the current mode
   * 
   * @param mode
   * @returns {Boolean} true if tuning status is currently in progress.
   */
  inProgress : function(mode)
  {
    console.debug("TuneUpTuningmode.inProgress(", arguments, ")");
    var oldMode = this.tuningmodeInProgress;
    if (mode) {
      this.tuningmodeInProgress = mode;
    }
    return oldMode;
  },

  /**
   * InProgress state will be toggled
   * 
   * @returns void
   */
  toggleInProgress : function( )
  {
    console.debug("TuneUpTuningmode.toggleProgress()");
    this.tuningmodeInProgress = !this.tuningmodeInProgress;
    return this;
  },

  /**
   * @returns {Boolean}
   */
  isTurboModeActive : function( )
  {
    console.debug("TuneUpTuningmode.isTurboModeActive()");
    return ( this.tuningmodeStatus == this.tuningmodeTurbo );
  },

  /**
   * @returns {Boolean}
   */
  isEcoModeActive : function( )
  {
    console.debug("TuneUpTuningmode.isEcoModeActive()");
    return ( this.tuningmodeStatus == this.tuningmodeEco );
  },

  /**
   * @returns {Boolean}
   */
  isStandardModeActive : function( )
  {
    console.debug("TuneUpTuningmode.isStandardModeActive()");
    return ( this.tuningmodeStatus == this.tuningmodeStandard );
  },

  /**
   * Updates the progress bar to show how far the mode switching process has gone.
   * 
   * @param {String}
   *          mode What mode are currently in
   * @param {String}
   *          progress How far the switching process has got (0-100)
   * @returns {Boolean}
   * 
   */

  updateProgressBar : function(mode, progress)
  {
    console.debug("TuneUpTuningmode.updateProgressBar() called with progress=" + progress);

    if (progress == 0) {
      // if the process is at the beginning, show progess bar balloon
      console.debug("TuneUpTuningmode.updateProgressBar(): going to show progress bar balloon");
      if (this.tuningmodeNextStatus == this.tuningmodeStandard) {
        this.tuningModeButtonId = this.tuningmodeStandardId;
      } else if (this.tuningmodeNextStatus == this.tuningmodeTurbo) {
        this.tuningModeButtonId = this.tuningmodeTurboId;
      } else if (this.tuningmodeNextStatus == this.tuningmodeEco) {
        this.tuningModeButtonId = this.tuningmodeEcoId;
      } else {
        console.error('could not find a value for this.tuningmodeNextStatus');
      }

      if (jQuery(String.format(".progress-bar-balloon-container > .%s", this.tuningModeButtonId)).length <= 0) {
        console.error(String
            .format('could not find progress bar: should be .progress-bar-balloon-container > .%s', this.tuningModeButtonId));
      }

      jQuery(String.format(".progress-bar-balloon-container > .%s", this.tuningModeButtonId)).show( );

    } else if (progress == 100) {
      // if the process is at the end, set the bar to 100%
      console.debug("TuneUpTuningmode.updateProgressBar(): going to set bar to 100%");

      // if the process is at the end, hide progess bar balloon
      console.debug("TuneUpTuningmode.updateProgressBar(): going to hide progress bar balloon");
      jQuery(String.format(".progress-bar-balloon-container > .%s", this.tuningmodeStandardId)).hide( );
      jQuery(String.format(".progress-bar-balloon-container > .%s", this.tuningmodeTurboId)).hide( );
      jQuery(String.format(".progress-bar-balloon-container > .%s", this.tuningmodeEcoId)).hide( );
    }

    // update bar with the current progress
    this.updateProgressBarImageXPosition(progress);

    return true;
  },

  /**
   * Updates the background position of the image in the progress bar div to make it look like the bar is getting
   * longer.
   * 
   * @param {String}
   *          progress How far the switching process has got (0-100)
   * @returns {Boolean}
   * 
   */
  updateProgressBarImageXPosition : function(progress)
  {
    // console.debug( "TuneUpTuningmode.updateProgressBarImageXPosition(): called with progress=" + progress );
    var backgroundImageXPosition = this.progressBar.backgroundImageMinXPosition + Math.round(this.progressBar.length * progress / 100.0);
    jQuery(String.format(".progress-bar-balloon-container > div.%s > div > .progress-bar-balloon-index", this.tuningModeButtonId)).css({
      'background-position-x' : String.format("%spx", backgroundImageXPosition)
    });
    return true;
  }
});

jQuery(document).ready(function($)
{
  tuTuningmode = new TuneUpTuningmode( );

  jQuery('.info-icon-ecoturbo').bind('mouseover mouseout', function( )
  {
    jQuery(this).toggleClass('tooltip');
    if (jQuery(this).hasClass('tooltip')) {
      var b = jQuery('.info-icon-ecoturbo');
      var pos = b.offset( );
      tuDispatcher.trigger("tooltip", 1, "info-performancemode", pos.left, ( pos.top - 1 ), b.width( ), b.height( ));
    } else {
      tuDispatcher.trigger("tooltip", 0, "info-performancemode");
    }
  });

  jQuery('.info-icon-tuningindex').bind('mouseover mouseout', function( )
  {
    jQuery(this).toggleClass('tooltip');
    if (jQuery(this).hasClass('tooltip')) {
      var b = jQuery('.info-icon-tuningindex');
      var pos = b.offset( );
      tuDispatcher.trigger("tooltip", 1, "info-tuningindex", pos.left, ( pos.top - 1 ), b.width( ), b.height( ));
    } else {
      tuDispatcher.trigger("tooltip", 0, "info-tuningindex");
    }
  });

});

/**
 * @author TobiasTrozowski
 * @constructor
 * @returns {TuneUpTuningStatus}
 */
function TuneUpTuningStatus( )
{
  AbstractTuneUpClass.apply(this, arguments);
// this.initialize( );
}
TuneUpTuningStatus.prototype = new AbstractTuneUpClass( );

// TuneUpTuningStatus.prototype = {
AbstractTuneUpClass.extend(TuneUpTuningStatus.prototype, {
  activeIndex : {
    activities : 0,
    potentials : 0
  },

  rendered : false,
  optimizationProgress : 0,

  /**
   * 
   */
  initialize : function( )
  {
    console.debug("TuneUpTuningStatus.initialize()");

    // singleton implementation
    if (TuneUpTuningStatus.instance !== undefined) {
      console.warn("TuneUpTuningStatus instantiated twice, returning previous instance.");
      return TuneUpTuningStatus.instance;
    }

    tuDispatcher.bind("updateTuningIndex", function(evt, prefs)
    {
      this.updateTuningIndex(prefs.index, prefs.length, prefs.text, prefs.benefit, prefs.active);
    }, this).bind("updateTuningStatus", function(evt, obj)
    {
      this.updateTuningStatus(obj);
    }, this).bind("updateTurboIndex", function(evt, cur, max)
    {
      this.updateTurboIndex(cur, max);
    }, this).bind("updateEcoIndex", function(evt, cur, max)
    {
      this.updateEcoIndex(cur, max);
    }, this);

    TuneUpTuningStatus.instance = this;

    return TuneUpTuningStatus.instance;
  },

  /**
   * 
   * @param cur
   * @param max
   */
  updateTurboIndex : function(cur, max)
  {
    // console.debug("TuneUpTuningStatus.updateTurboIndex(", cur, ", ", max, ")");

    var stepSize = 4;
    cur = ( cur > max ) ? max : cur;

    jQuery(".tuningarea .turbo-eco-index .turbo-index .indexbar").width(max * stepSize).removeClass('bar-full bar-empty');
    jQuery(".tuningarea .turbo-eco-index .turbo-index .indexbar .index-0").width(cur * stepSize);
    jQuery(".tuningarea .turbo-eco-index .turbo-index .index-info a").html(
      String.format("<localized>%d von %d Optionen</localized>", cur, max));
    if (cur == max) {
      jQuery(".tuningarea .turbo-eco-index .turbo-index .indexbar").addClass('bar-full');
    } else if (cur == 0) {
      jQuery(".tuningarea .turbo-eco-index .turbo-index .index-info a").html("<localized>Nicht konfiguriert</localized>");
      jQuery(".tuningarea .turbo-eco-index .turbo-index .indexbar .index-0").width(max * stepSize);
      jQuery(".tuningarea .turbo-eco-index .turbo-index .indexbar").addClass('bar-empty');
    }

  },

  /**
   * 
   * @param cur
   * @param max
   */
  updateEcoIndex : function(cur, max)
  {
    // console.debug( "TuneUpTuningStatus.updateEcoIndex(", cur, ", ", max, ")" );
    var stepSize = 20, states = new Array("<localized>Nicht konfiguriert</localized>", "<localized>Niedrig{Energieeinsparung}</localized>",
      "<localized>Mittel{Energieeinsparung}</localized>", "<localized>Hoch{Energieeinsparung}</localized>");

    // max should always be 3
    max = 3;
    cur = cur > max ? max : cur;

    jQuery(".tuningarea .turbo-eco-index .eco-index .indexbar").width(max * stepSize);
    jQuery(".tuningarea .turbo-eco-index .eco-index .indexbar .index-0").width(cur * stepSize);
    jQuery(".tuningarea .turbo-eco-index .eco-index .indexbar").removeClass("bar-full bar-empty");
    jQuery(".tuningarea .turbo-eco-index .eco-index .index-info a").text(
      String.format("<localized>Einsparung:</localized> %s", states[ cur ]));
    if (cur == max) {
      jQuery(".tuningarea .turbo-eco-index .eco-index .indexbar").addClass("bar-full");
    } else if (cur == 0) {
      jQuery(".tuningarea .turbo-eco-index .eco-index .index-info a").text(String.format("%s", states[ cur ]));
      jQuery(".tuningarea .turbo-eco-index .eco-index .indexbar .index-0").width(max * stepSize);
      jQuery(".tuningarea .turbo-eco-index .eco-index .indexbar").addClass("bar-empty");
    }
  },

  /**
   * 
   * @param obj
   */
  updateTuningStatus : function(obj)
  {
    console.debug("TuneUpTuningStatus.updateTuningStatus(", arguments, ")");
    assert(obj.activities !== undefined && obj.potentials !== undefined,
      "Either activities neither potentials for tuningstatus are undefined.");

    var activeIndexActivity = ( obj.activities.activeIndex > 4 ) || ( obj.activities.activeIndex < 0 ) ? 0 : obj.activities.activeIndex;
    var activeIndexPotential = ( obj.potentials.activeIndex > 4 ) || ( obj.potentials.activeIndex < 0 ) ? 0 : obj.potentials.activeIndex;
    var activitiesPagesLength = potentialsPagesLength = activitiesCount = obj.activities.list.length;
    var activityPages = potentialPages = 0;
    // hide content-container and pager and index-segments
    jQuery(
      ".tuningindex .tuninginfo .activities .content .index-piece, .tuningindex .tuninginfo .potentials .content .index-piece,"
        + ".tuningindex .tuninginfo .activities .pager .pages:not(.arrow-right), "
        + ".tuningindex .tuninginfo .potentials .pager .pages:not(.arrow-right)").hide( );
    jQuery(".tuningindex .indexarea .indexbar .index-piece").hide( ).removeClass("first-child last-child activities potentials");

    // fill activities
    for ( var i in obj.activities.list) {
      var segment = obj.activities.list[ i ], fn = jQuery.proxy(function(evt)
      {
        // just update the status index if we click on a different index as the current one
        if (jQuery(evt.currentTarget).attr('page') != this.activeIndex.activities) {
          this.pageStatusIndex("activities", jQuery(evt.currentTarget).attr('page'));
        }
      }, this);
      // show pager-index
      jQuery(String.format(".tuningindex .tuninginfo .activities .pager .pages.index-%s", i)).attr({
        page : i
      }).unbind("click.pager").bind("click.pager", fn).show( );
      // show segment-text
      jQuery(String.format(".tuningindex .tuninginfo .activities .content .index-%s", i)).html(segment.text);

      var indexPiece = jQuery(String.format(".tuningindex .indexarea .indexbar .index-%s", i)).css({
        // set segment width
        width : segment.length
      }).attr({
        page : i
      }).addClass("activities").unbind("mouseover.pager mouseout.pager").bind("mouseover.pager mouseout.pager", fn);
      if (segment.length !== 0) {
        indexPiece.show( );
      }
      activitiesPagesLength = activitiesPagesLength + segment.length;
      if (segment.length > 0) {
        // increase page size
        activityPages++;
      }
    }

    // fill potentials
    for ( var i in obj.potentials.list) {
      var segment = obj.potentials.list[ i ], fn = jQuery.proxy(function(evt)
      {

        // just update the status index if we click on a different index as the current one
        if (jQuery(evt.currentTarget).attr('page') != this.activeIndex.potentials) {
          this.pageStatusIndex("potentials", jQuery(evt.currentTarget).attr('page'));
        }
      }, this);
      // show segment-text
      jQuery(String.format(".tuningindex .tuninginfo .potentials .content .index-%s", i)).html(segment.text);

      if (segment.length <= 0) {
        /*
         * it seems like there are no more potentials (everything is optimized)
         */

        // unbind and hide
        jQuery(String.format(".tuningindex .indexarea .indexbar .index-%s", ( parseInt(i) + parseInt(activitiesCount) ))).unbind(
          "mouseover.pager mouseout.pager").hide( );
        jQuery(String.format(".tuningindex .tuninginfo .potentials .pager .pages.index-%s", i)).unbind("click.pager").hide( );

      } else {
        // show pager-index
        jQuery(String.format(".tuningindex .tuninginfo .potentials .pager .pages.index-%s", i)).attr({
          page : i
        }).unbind("click.pager").bind("click.pager", fn).show( );

        // add activities count to current index
        jQuery(String.format(".tuningindex .indexarea .indexbar .index-%s", ( parseInt(i) + parseInt(activitiesCount) ))).css({
          // set segment width
          width : segment.length
        }).attr({
          page : i
        }).addClass("potentials").unbind("mouseover.pager mouseout.pager").bind("mouseover.pager mouseout.pager", fn).show( );

        // increase page size
        potentialPages++;
      }
      potentialsPagesLength = potentialsPagesLength + segment.length;
    }

    // style hack to get float left/ right effect to work properly for .tuninginfo .h3 (could not find another
    // way)
    if (( activityPages >= 0 ) && ( activityPages < 6 )) {
      jQuery('.tuningarea .activities .h3').css({
        'width' : String.format("%dpx", ( 150 + ( 5 - activityPages ) * 12 ))
      });
    }
    if (( potentialPages >= 0 ) && ( potentialPages < 6 )) {
      jQuery('.tuningarea .potentials .h3').css({
        'width' : ( 150 + ( 5 - potentialPages ) * 12 ) + 'px'
      });
    }

    jQuery(".tuningindex .indexarea .indexbar .index-piece:visible:first").addClass("first-child");
    jQuery(".tuningindex .indexarea .indexbar .index-piece:visible:last").addClass("last-child");

    if (( activityPages + potentialPages ) > 0) {
      this.optimizationProgress = Math.round(100.0 * activityPages / ( activityPages + potentialPages ));
    }

    this.pageStatusIndex("activities", activeIndexActivity, false).pageStatusIndex("potentials", activeIndexPotential, false);
    return this.render( );
  },

  isRendered : function( )
  {
    return this.rendered;
  },

  /**
   * 
   */
  render : function( )
  {
    console.debug("TuneUpTuningStatus.render(", arguments, ")");
    if (tuIntegrator.isTrialEnabled( )) {
      jQuery('.tuningindex > .indexarea > .index-info > a').text(String.format("%d%%", this.optimizationProgress));
    } else {
      jQuery('.tuningindex > .indexarea > .index-info > a').text(
        String.format("<localized>%d%% Optimierungsfortschritt erreicht</localized>", this.optimizationProgress));
    }
    rendered = true;
    return this.renderGraph( );
  },

  /**
   * 
   * @param type
   * @param page
   * @param render
   */
  pageStatusIndex : function(type, page, render)
  {
    console.debug("TuneUpTuningStatus.pageStatusIndex(", arguments, ")");

    var typeObj = jQuery(String.format(".tuningindex .tuninginfo .%s", type));
    assert(typeObj !== null && ( ( type == "activities" ) || ( type == "potentials" ) ), "Unkown message-type.");

    if (type == "activities") {
      this.activeIndex.activities = page;
    } else if (type == "potentials") {
      this.activeIndex.potentials = page;
    }

    render = ( render === true || render === false ) ? render : true;

    // remove all other active pager-segments
    typeObj.find(".pager .pages").removeClass("activated");
    // set current pager-segment to active
    typeObj.find(String.format(".pager .pages.index-%s", page)).addClass("activated");
    // hide all content-segments
    typeObj.find(".content .index-piece").hide( );
    // show currently active segment
    typeObj.find(String.format(".content .index-%s", page)).show( );

    return render ? this.render( ) : this;
  },

  /**
   * 
   * @param activityIndex
   * @param potentialIndex
   */
  renderGraph : function(type)
  {
    console.debug("TuneUpTuningStatus.renderGraph(", arguments, ")");

    if (type === undefined) {
      try {
        this.renderGraph("activities");
      } catch (e) {
      }
      try {
        this.renderGraph("potentials");
      } catch (e) {
      }
      return this;
    }

    var currentIndex = ( type == "activities" ) ? this.activeIndex.activities : this.activeIndex.potentials, segment = jQuery(String
        .format(".tuningindex .indexarea .indexbar .%s[page=%s]:visible", type, currentIndex));

    // hide all connectors
    jQuery(String.format(".tuning-status-pointers .%s div", type)).hide( );

    assert(segment !== undefined && segment.length !== 0,
      "Cannot render graphs, segment could not be found. Either there is everything optimized or there occured an error.");

    var graphLeft = graphTop = pointerLeftPositionFromEndOfGraph = pointerLeft = pointerBottom = pointerTotalHeight = null;
    var totalLength = 1 /* add 1 for the left border */, graphSectionIndexId = 0;

    // calculate the absolute position of the graph
    graphLeft = parseInt(jQuery(".tuningindex .indexarea").css("margin-left"), 10);
    graphTop = jQuery(".tuningarea").height( ) - jQuery(".tuningindex .h2").height( ) - jQuery(".tuningindex .tuninginfo").height( );

    jQuery(String.format(".tuningindex .indexarea .indexbar .index-piece:visible")).each(function(idx, el)
    {
      var cPage = parseInt(jQuery(this).attr("page"));
      totalLength = totalLength + jQuery(this).width( ) + 1;
      if (jQuery(this).hasClass(type) && ( cPage == currentIndex )) {
        return false;
      }
    });

    // calculate the horizontal distance of the pointer left from the start of the graph
    pointerLeftPositionFromEndOfGraph = totalLength - 1 - Math.ceil(segment.width( ) / 2.0) - 2; // -2
    // is to allow for width of image used as pointer

    // calculate the absolute left position of the pointer
    pointerLeft = graphLeft + ( totalLength - Math.ceil(segment.width( ) / 2.0) - 2 );

    // calculate the absolute bottom position of the pointer
    pointerBottom = graphTop - 4; // move pointer slightly down for style reasons

    // calculate the height of the bar dynamically based on the height of the content box it is pointing to
    pointerTotalHeight = jQuery(".tuningindex .tuninginfo").height( )
      - jQuery(String.format(".tuningindex .tuninginfo .%s .h3", type)).height( )
      - jQuery(String.format(".tuningindex .tuninginfo .%s .content .index-%s", type, currentIndex)).height( );

    pointerTotalHeight = pointerTotalHeight + 1; // make pointer slightly bigger for style reasons

    // determine whether we have to show a straight or bendy bar
    var bendyPointerUpperSectionLeft = 0, useBendyBar = false;
    // if the pointer's bottom position is outside the boundary of this container, whether activities or
    // potentials, we need to show a bendy bar
    bendyPointerUpperSectionLeft = jQuery(String.format(".%s", type)).outerWidth(true);
    if (type == 'activities') {
      // calculate the right-hand edge of the activities box
      // if activities, align the upper section with the right-hand edge of the activities box
      bendyPointerUpperSectionLeft = bendyPointerUpperSectionLeft * 0.7;
      useBendyBar = ( pointerLeft > bendyPointerUpperSectionLeft );
    } else {
      // calculate the left-hand edge of the potentials box
      // if potentials, align the upper section with the left-hand edge of the potentials box
      bendyPointerUpperSectionLeft = bendyPointerUpperSectionLeft / 0.9;
      useBendyBar = ( pointerLeft < bendyPointerUpperSectionLeft );
    }

    if (useBendyBar) {
      // calculate the bendy bar upper vertical section coordinates
      var bendyPointerHorizontalSectionLeft = 0;
      // calculate the bendy bar horizontal section coordinates
      var bendyPointerHorizontalSectionWidth = Math.abs(bendyPointerUpperSectionLeft - pointerLeft) + 2;
      if (pointerLeft < bendyPointerUpperSectionLeft) {
        bendyPointerHorizontalSectionLeft = pointerLeft + 2; // the extra px is to deal with the
        // width of the images used for the vertical pointers
        bendyPointerHorizontalSectionWidth = Math.abs(bendyPointerUpperSectionLeft - pointerLeft);
      } else {
        bendyPointerHorizontalSectionLeft = bendyPointerUpperSectionLeft + 2; // the extra px is to deal with
        // the width of the images used for the vertical pointers
      }

      // show the upper vertical section and position it correctly
      jQuery(String.format(".tuning-status-pointers .%s .bendy-pointer-vertical-upper", type)).css({
        'left' : String.format("%dpx", bendyPointerUpperSectionLeft),
        // 'bottom' : String.format("%dpx", bendyPointerUpperSectionBottom),
        'height' : String.format("%dpx", ( pointerTotalHeight - 13 ))
      // 'background-position' : String.format("0px %dpx", ( bendyPointerUpperSectionHeight - 60.0 ))
      }).show( );
      // show the bendy bar horizontal section and position it correctly
      jQuery(String.format(".tuning-status-pointers .%s .bendy-pointer-horizontal", type)).css({
        'left' : String.format("%dpx", bendyPointerHorizontalSectionLeft),
        // 'bottom' : String.format("%dpx", bendyPointerHorizontalSectionBottom),
        'width' : String.format("%dpx", bendyPointerHorizontalSectionWidth)
      }).show( );
      // show the lower vertical section and position it correctly
      jQuery(String.format(".tuning-status-pointers .%s .bendy-pointer-vertical-lower", type)).css({
        'left' : String.format("%dpx", pointerLeft)
      }).show( );
    } else {
      // show the straight bar and position it correctly
      jQuery(String.format(".tuning-status-pointers .%s .straight-pointer", type)).css({
        'left' : String.format("%dpx", pointerLeft),
        'height' : String.format("%dpx", pointerTotalHeight),
        'background-position' : String.format("0px %dpx", ( pointerTotalHeight - 70.0 ))
      }).show( );
    }

    return this;
  },

  /**
   * 
   * @returns {TuneUpTuningStatus}
   */
  dialog : function( )
  {
    console.debug("TuneUpTuningStatus.dialog(", arguments, ")");
    this.send("#potential:dialog");
    return this;
  }

});

jQuery(document).ready(function( )
{
  // make the tuningindex globally available
  window.tuTuningStatus = new TuneUpTuningStatus( );
});
