/**
 *  ****************************************************************************
 *  File : design/previmer/javascript/previmer_currentstate.js
 *  vers : 1.1
 *  build: 20070731
 *  Author : Virtualys
 *  ****************************************************************************
 **/

/**
 * ============================================================================= 
 * CurrentState
 * Etat actuel du choix de l'utilisateur.
 * ============================================================================= 
 */ 
CurrentState = function(initState)
{
	// Etats initiaux
	this._initialState = initState;
	// Thème en cours
	this.theme = initState.theme;
	// Objet Application en cours
	this.application = null;
	// Objet Variable en cours
	this.variable = null;
	// Objet ResultType en cours
	this.resultType = null;
	// Objet Area en cours
	this.area = null;
	// ID de la profondeur en cours
	this.depth = null;
	// Objet Date en cours (l'heure est fixée à minuit)
	this.date = null;
	// Décalage en millisecondes dans la journee en h locale indiquant l'heure choisie
	// dans la liste déroulante, 0 si non applicable (heure masquee)
	this.hourOffset = 0;
	// Objet AnimationSettings en cours ou null
	this.animation = null;
	// Item géométrique
	this.geoItem = null;
	// état de l'application Flash
	this.flashState = null;
}
CurrentState.TYPE_RESULT = 0;
CurrentState.TYPE_APP_INFOS = 1;
CurrentState.TYPE_BULLETIN = 2;
CurrentState.TYPE_ANALYSIS = 3;
CurrentState.TYPE_TIMECONFIG = 4;
CurrentState.prototype = {
/**
 * -----------------------------------------------------------------------------
 * Initialise l'état courant à partir de l'application lue depuis le réseau.
 * @param application l'objet application 
 */ 
	'initObjects' : function(application)
	{
		// Initialisation de l'application
		this.application = application;
		// Variable
		if (application._variables[this._initialState.variable])
		{
			this.selectVariable(this._initialState.variable);
		}
		else
		{
			for (var variable in application._variables)
			{
				this.selectVariable(variable);
				break;
			}
		}
		// Type de résultat
		if (this.variable.resultTypes[this._initialState.resultType])
		{
			this.selectResultType(this._initialState.resultType);
		}
		else
		{
			for (rType in this.variable.resultTypes)
			{
				this.selectResultType(rType);
				break;
			}
		}
		// Emprise / GeoItem
		if (application.getArea(this._initialState.area))
		{
			this.selectArea(this._initialState.area);
		}
		else
		{
			this.selectArea(application._rootArea._id);
		}
		if (this._initialState.resultType != 'map')
		{
			if (this.resultType.geoItems[this.area._id + "_" + this._initialState.geoID])
			{
				this.selectGeoItem(this.area._id + "_" + this._initialState.geoID);
			}else
			{
		      this.selectGeoItem(this.area._id);
			}
		}
		// Profondeur
		if (this._initialState.depth &&
				this.resultType.depths[this._initialState.depth])
		{
			this.selectDepth(this._initialState.depth);
		}
		else
		{
			for (depth in this.resultType.depths)
			{
				this.selectDepth(depth);
				break;
			}
		}
	},
   'initTimeConfig' : function()
   {
      // Date
      if (this._initialState.date || this.date )
      {
         if ( this.date ) {
            this.selectDate( this.date );
         }
         else {
            var strDate = this._initialState.date;
            this.selectDate(new Date(
               parseInt(strDate.substring(0, 4), 10), parseInt(strDate.substring(4, 6), 10) - 1,
               parseInt(strDate.substring(6, 8), 10)));
         }

         var timeconfig = this.getTimeConfig();
         if ( timeconfig )
         {
            var unit = timeconfig.unit;
            if (unit == 'minute' || unit == 'hour')
            {
               var hourOffset = null;
               if ( this.hourOffset === 0 )
               {
                  var hrs = parseInt(strDate.substring(9, 11), 10) * 3600000;
                  var mins = parseInt(strDate.substring(11, 13), 10) * 60000;
                  var secs = parseInt(strDate.substring(13, 15), 10) * 1000;
                  hourOffset = hrs + mins + secs;
               }
               else {
                  hourOffset = this.hourOffset;
               }
   
               // On arrondi éventuellement si la valeur ne tombe pas juste en fonction du pas :
               // si la valeur est >= pas/2, on arrondi au pas supèrieur ;
               // sinon on arrondi au pas inférieur
               if (unit == 'minute')
               {
                  var timeStepMs = timeconfig.step * 60000;
                  var timeOffsetMs = timeconfig.offset * 60000 - this.date.getTimezoneOffset() * 60000;
               }
               else if (unit == 'hour')
               {
                  var timeStepMs = timeconfig.step * 3600000;
                  var timeOffsetMs = timeconfig.offset * 3600000 - this.date.getTimezoneOffset() * 60000;
               }
               else
               {
                  this.hourOffset = hourOffset;
                  return;
               }
               var remainder = hourOffset - timeOffsetMs;
               while (remainder < 0)
               {
                  remainder += timeStepMs;
               }
               remainder = remainder % timeStepMs;
               if (remainder == 0)
               {
                  this.hourOffset = hourOffset;
               }
               else if (remainder >= (timeStepMs / 2))
               {
                  this.hourOffset = Math.min(
                     hourOffset - remainder + timeStepMs,
                     86400000 - timeStepMs);
               }
               else
               {
                  this.hourOffset = Math.min(
                     hourOffset - remainder,
                     86400000 - timeStepMs);
               }
            }
            else
            {
               this.hourOffset = 0;
            }
         }
      }
      else
      {
         this.selectDate(new Date());
         this._synchronizeHours();
      }
      
//      this.getTimeConfig();
	},
/**
 * -----------------------------------------------------------------------------
 * Synchronise l'offset de l'heure avec les choix actuels.
 */ 
   '_synchronizeHours' : function()
   {
      var timeConfig = this.getTimeConfig();

      if ( timeConfig && 
            ( timeConfig.unit == 'minute' || timeConfig.unit == 'hour' ) )
      {
         // Il faut que l'offset tombe sur une valeur permise
         var now = this.hourOffset == 0 ? new Date() :
            new Date(this.date.getTime() + this.hourOffset);
         switch (timeConfig.unit) 
         {
            case 'minute' :
               var correctedTime = now.getUTCHours() * 60 +
                  now.getUTCMinutes() - timeConfig.offset;
               this.hourOffset = ((correctedTime - correctedTime % timeConfig.step -
                  now.getTimezoneOffset() + timeConfig.offset) * 60000) % 86400000;
               break;
            case 'hour' :
               var correctedTime = now.getUTCHours() - timeConfig.offset;
               this.hourOffset = (((correctedTime - correctedTime % timeConfig.step) * 60 -
                  now.getTimezoneOffset() + timeConfig.offset) * 60000) % 86400000;
               break;
         }
      }
   },
/**
 * -----------------------------------------------------------------------------
 * Sélectionne une nouvelle variable.
 * @param variableID l'identifiant de la variable 
 */ 
	'selectVariable' : function(variableID)
	{
		this.variable = this.application.getVariables()[variableID];
		if (this.resultType)
		{
			this.selectResultType(this.resultType.id);
		}
	},
/**
 * -----------------------------------------------------------------------------
 * Sélectionne une nouveau type de résultat.
 * @param rtypeID l'identifiant du nouveau type de résultat 
 */ 
	'selectResultType' : function(rtypeID)
	{
		this.resultType = this.variable.resultTypes[rtypeID];
		if (!this.resultType)
		{
			for( var id in this.variable.resultTypes)
			{
				if (this.resultType = this.variable.resultTypes[id])
				{
					break;
				}
			}
			if (!this.resultType)
			{
				alert("Aucun type de résultat disponible");
				return;
			}
		}
		this._synchronizeGeoItem();
	},
/**
 * -----------------------------------------------------------------------------
 * Sélectionne une nouvelle emprise.
 * @param areaID l'identifiant de la nouvelle emprise
 */ 
	'selectArea' : function(areaID)
	{
		this.area = this.application.getArea(areaID);
		this._synchronizeGeoItem();
		this.getTimeConfig();
	},
/**
* Sélectionne l'élément géométrique précédent ou celui par défaut lors du
* changement de carte.
*/
	'_synchronizeGeoItem' : function() 
	{
		if (this.resultType.id != 'map')
		{
			if (this.geoItem == null
					|| !this.resultType.geoItems[this.area._id + "_" + this.geoItem._id])
			{
				if (this.area && this.resultType.defaultGeoItem[this.area._id])
				{
					// Sélection du geoitem par défaut
					this.selectGeoItem(this.area._id + "_" + this.resultType.defaultGeoItem[this.area._id]._id);
				}else
				{
					this.selectGeoItem(null);
				}
			}
		}else
		{
			this.selectGeoItem(null);
		}
	},
/**
* -----------------------------------------------------------------------------
* S‚lectionne un nouvel ‚l‚ment g‚ographique (un point, une ligne ...).
* @param geoItemIndex l'identifiant de l'‚l‚ment
*/
	'selectGeoItem' : function(geoItemIndex)
	{
		if ((geoItemIndex) && this.resultType.geoItems[geoItemIndex])
		{
			this.geoItem = this.resultType.geoItems[geoItemIndex];
		}else
		{
			this.geoItem = this.resultType.defaultGeoItem[geoItemIndex];
		}
//		this.getTimeConfig();
	},
/**
 * -----------------------------------------------------------------------------
 * Sélectionne une nouvelle profondeur.
 * @param depthID l'identifiant de la nouvelle profondeur
 */ 
	'selectDepth' : function(depthID)
	{
		this.depth = depthID;
	},
/**
 * -----------------------------------------------------------------------------
 * Sélectionne une nouvelle journée.
 * @param date la date à utiliser
 */ 
	'selectDate' : function(date)
	{
	   var timeConfig = this.getTimeConfig();
	   if( timeConfig )
	   {
   		var unit = timeConfig.unit;
   		if (unit == 'minute' || unit == 'hour')
   		{
   			// On gère les heures locales
   			this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
   		}
   		else
   		{
   			// On utilise minuit
   			this.date = new Date(
   				date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0);
   		}
	   }else
	   {
	      this.date = new Date();
	   }
	},
/**
 * -----------------------------------------------------------------------------
 * Sélectionne une nouvelle heure dans la journée.
 * @param hour la nouvelle heure (un offset par rapport à minuit)
 */ 
	'selectHour' : function(hour)
	{
		if (typeof(hour) == 'string')
		{
			this.hourOffset = parseInt(hour, 10);
		}
		else
		{
			this.hourOffset = hour;
		}
	},
/**
 * -----------------------------------------------------------------------------
 * Sélectionne une nouvelle animation.
 * @param animationID l'identifiant de la nouvelle animation ou null pour ne pas
 * sélectionner d'animation en cours 
 */ 
	'selectAnimation' : function(animID)
	{
		if (animID == null)
		{
			this.animation = null; 
		}
		else
		{
			this.animation = this.resultType.getAnimations()[animID];
		}
	},
/**
 * -----------------------------------------------------------------------------
 * Compile une structure de paramètres utilisable avec une requête Ajax vers le
 * serveur Tomcat, à partir des informations courantes.
 * @param type le type de requête ciblée (voir les constantes CurrentState.TYPE_xxx)
 * @param config un objet de configuration contenant en particulier la langue à
 * utiliser
 */ 
	'getRequestParams' : function(type, config)
	{
		switch (type)
		{
			case CurrentState.TYPE_APP_INFOS :
				var appID = (this.application ?
					this.application._id : this._initialState.application);
				var params = {
					'theme' : this.theme,
					'appli' : appID,
					'w' : 1000,
					'h' : 1000 };
				break;

			case CurrentState.TYPE_RESULT :
				var params = {
					'theme' : this.theme,
					'appli' : this.application._id,
					'var' : this.variable.id,
					'type' : this.resultType.id
				};
				var timeConfig = this.getTimeConfig();
				var stepUnit = timeConfig ? this.getTimeConfig().unit : null;
				if (stepUnit == 'hour' || stepUnit == 'minute')
				{
					params['date'] = this.date.getTime() + this.hourOffset;
				}
				else
				{
					params['date'] = this.date.getTime() - this.date.getTimezoneOffset() * 60000;
				}
				if (this.depth)
				{
					params['level'] = this.depth;
				}
				if (this.resultType.id == 'map')
				{
					params['area'] = this.area._id;
				}
				else
				{
					params['area'] = this.geoItem ? this.geoItem._area : '';
					params['geoid'] = this.geoItem ? this.geoItem._id : '';
				}
				break;
				
			case CurrentState.TYPE_BULLETIN :
				var appID = (this.application ?
					this.application._id : this._initialState.application);
				var params = {
					'theme' : this.theme,
					'appli' : appID};
				if ( this.area !== null )
				{
				   params.area = this.area._id;
				}else if ( this.isAlone && this._initialState.area )
				{
				   params.area = this._initialState.area;
				}
				break;
				
			case CurrentState.TYPE_ANALYSIS :
				var appID = (this.application ?
					this.application._id : this._initialState.application);
				var params = {
					'theme' : this.theme,
					'appli' : appID,
					'type' : 'analyse',
					'area' : this.area._id,
					'date' : this.date.getTime() };
				break;
			case CurrentState.TYPE_TIMECONFIG :
			   var appID = this.application ?
	               this.application._id : this._initialState.application;
			   var params = {
		         'theme' : this.theme,
		         'appli' : (this.application ?
		               this.application._id : this._initialState.application),
               'type' : this.resultType.id,
               'var' : this.variable.id
            };
            if (this.resultType.id == 'map')
            {
               params['area'] = '*';
            }
            else
            {
               params['area'] = this.geoItem ? this.geoItem._area : '';
               params['geoid'] = '*';
            }
            if (this.depth)
            {
               params['level'] = this.depth;
            }
            break;
		}
		if (config)
		{
			params['lang'] = config.locale;
		}
		return params;
	},
/**
 * -----------------------------------------------------------------------------
 * Obtient un lien permanent déduit des informations courantes.
 * @param temporal true pour générer un lien permanent incluant la date
 */ 
	'getPermaLink' : function(forTemporal)
	{
		var variable = '/(variable)/' + this.variable.id;
		var resultType = '/(typevisu)/' + this.resultType.id;
		var depth = this.depth ? ('/(zlevel)/' + this.depth) : '';
		var zone = '/(zoneid)/' + this.area._id;
		if (this.geoItem)
		{
			var geoItem = '/(geoid)/' + this.geoItem._id;
		}
		else
		{
			var geoItem = '';
		}
		if (forTemporal)
		{
			var temporal = '/(date)/' + this.date.getFullYear();
			var digit = this.date.getMonth() + 1;
			if (digit < 10)
			{
				temporal += '0';
			}
			temporal += digit;
			digit = this.date.getDate();
			if (digit < 10)
			{
				temporal += '0';
			}
			temporal += digit + '_';
			digit = Math.floor(this.hourOffset / 3600000);
			if (digit < 10)
			{
				temporal += '0';
			}
			temporal += digit;
			digit = Math.floor((this.hourOffset % 3600000) / 60000);
			if (digit < 10)
			{
				temporal += '0';
			}
			temporal += digit + '00';
		}
		else
		{
			var temporal = '';
		}
		var href = variable + resultType + depth + zone + geoItem + temporal;
		return href;
	},
	
/**
 * Recopie de l'objet
 * @return un objet CurrentState
 */
	'copy' : function()
	{
		var copie = new CurrentState(this);
		// Etats initiaux
		copie._initialState = this._initialState;
		// Thème en cours
		copie.theme = this.theme;
		// Objet Application en cours
		copie.application = this.application;
		// Objet Variable en cours
		copie.variable = this.variable;
		// Objet ResultType en cours
		copie.resultType = this.resultType;
		// Objet Area en cours
		copie.area = this.area;
		// ID de la profondeur en cours
		copie.depth = this.depth;
		// Objet Date en cours (l'heure est fixée à minuit)
		copie.date = this.date;
		// Décalage en millisecondes dans la journee en h locale indiquant l'heure choisie
		// dans la liste déroulante, 0 si non applicable (heure masquee)
		copie.hourOffset = this.hourOffset;
		// Objet AnimationSettings en cours ou null
		copie.animation = this.animation;
		// Item géométrique
		copie.geoItem = this.geoItem;
		return copie;
	},
	/**
	 * Renvoit un tableau associatif contenant l'ensemble de l'état en cours.
	 * @return un tableau associatif
	 */
	'getState' : function()
	{
		var state = {
				theme		: this.theme,
				appli		: this.application._id,
				variable	: this.variable.id,
				type		: this.resultType.id
		};
		if (this.area != null)
		{
			state['area'] = this.area._id;
		}
		if (this.depth != null)
		{
			state['level'] = this.depth;
		}
		if (this.geoItem != null)
		{
			state['geoid'] = this.geoItem._id;
		}
		return state;
	},
	
	/**
	 * Renvoie l'état actuel de l'application Flash
	 */
	'getFlashState' : function()
	{
		return this.flashState;
	},
	
	/**
	 * Change l'état de l'applicaion Flash
	 */
	'setFlashState' : function( state )
	{
		this.flashState = state;
	},
	/**
	* Selectionne le timeconfig adequate
	*/
	'_synchronizeTimeConfig' : function() 
	{
		if (this.area && this.area != null) {
			this.resultType.updateCurrentTimeConfig(
					this.area._id+'|'+
					(this.geoItem && this.geoItem != null ? this.geoItem._id : "") +'|'+
					(this.depth && this.depth != null ? this.depth : "") );
		}
	},
	'getTimeConfig' : function()
	{
	   var key = this.area._id +
	      ( this.geoItem ? '|' + this.geoItem._id : '' ) +
	      ( this.depth ? '|' + this.depth : '' );
	   return this.resultType.getTimeConfig( key );
	}
}

