(function() {
/*************************************************************************[info]
  PACKAGE:              eXtend
  DATA:                 18/09/2008
  COMPANY:              Onlime S.n.c.
 
  VERS:                 1
  LAST EDIT:            18/12/2008
  
      
  [INTERFACCIA]
  
  $  (selector) : DOM element
  $$ (selector) : DOM.eXtend element
      
  [ToDo] ---------------------------------------------------------------------
  
  ToDoList:
    ...
      
  Changes:
  
    Gestione garbage oggetti

    - Old Code -
    this.id = eXtend.Instances.length;
    eXtend.Instances[this.id] = this;
    - End Old Code -
    
    - New Code - 
    eXtend.Instances.push( this ) ;
    this.id = eXtend.Instances.indexOf( this ); // required JavaScript 1.6
    - End New Code - 
        
*******************************************************************************/

/*******************************************************************************
  [REQUIRED]  
*******************************************************************************/        
if (!Array.indexOf) 
{
  Array.prototype.indexOf = function (obj, start) 
  {
    for (var i = (start || 0); i < this.length; i++) 
    {
      if (this[i] == obj){ return i; }
    }
  }
}

if (!Array.each) 
{
  Array.prototype.each = function ( fn, scope )
  {
    for(var j = 0, len = this.length; j < len; j++)
    {
	    fn.apply( scope || this[j], [ this[j], j, this ] );
	  }
  }
}

/* http://www.brockman.se/writing/method-references.html.utf8 */

// Most implementations don’t like expressions such as foo.concat(arguments)
// or arguments.slice(1), due to a kind of reverse duck typing: an argument
// object looks like a duck and walks like a duck, but it isn’t really a
// duck and it won’t quack like one.
function toArray( pseudoArray ) 
{
   var result = [];
   for (var i = 0; i < pseudoArray.length; i++) result.push(pseudoArray[i]);
   return result;
}

Function.prototype.bind = function (object) 
{
   var method = this;
   var oldArguments = toArray(arguments).slice(1);
   return function () {
       var newArguments = toArray(arguments);
       return method.apply(object, oldArguments.concat(newArguments));
   };
}

/* NOT USED
Function.prototype.bindEventListener = function (object) 
{
   var method = this;
   var oldArguments = toArray(arguments).slice(1);
   return function (event) {
       return method.apply(object, [event || window.event].concat(oldArguments));
   };
}

Function.prototype.wrap = function(wrapper) {
  var __method = this;
  return function() {
    return wrapper.apply(this,
        [__method.bind(this)].concat($A(arguments)));
  }
}
*/

// Funzione Cross per recuperare gli oggetti appartenenti ad una data classe 
// dato il nodo di partenza e il tipo di nodo 
function getElementsByClassName(oElm, strTagName, strClassName)
{
	var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
	
	var arrReturnElements = new Array();
	
  strClassName = strClassName.replace(/\-/g, "\\-");
  var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
	var oElement;
	
  for(var i=0; i<arrElements.length; i++)
  {
		oElement = arrElements[i];
		if( oRegExp.test(oElement.className) )
    {
			arrReturnElements.push(oElement);
		}
	}
	
	return (arrReturnElements)
}

// Funzione Cross per recuperare tutti gli oggetti appartenenti ad una data classe
function getElementsByClass(strClassName)
{
  return getElementsByClassName(document, "*", strClassName);
}

// typeof ottimizzata (torna direttamente anche tipo array e null) 
function typeOf(value) {
    var s = typeof value;
    if (s === 'object') {
        if (value) {
            if (typeof value.length === 'number' &&
                    !(value.propertyIsEnumerable('length')) &&
                    typeof value.splice === 'function') {
                s = 'array';
            }
        } else {
            s = 'null';
        }
    }
    return s;
}


/*******************************************************************************
  [INTERFACE]  
*******************************************************************************/      
window.$ = function( selector ) 
{
  // selector Array, String, Object
  // "#"        => take element by Id
  // "."        => take elements by ClassName
  // "HtmlTag"  => take elements by TagName
  
  var array_ret = new Array();
  
  if ( typeOf(selector) == 'string' )
  {  
    var splitted = selector.split(' ');
    for (var i=0;i<splitted.length;i++)
    {
      if ( splitted[i].charAt(0) == '#')
      {
        // element by id
        var obj  = document.getElementById( splitted[i].substring(1) );
        if ( obj ) array_ret.push( obj );
      }
      else if( splitted[i].charAt(0) == '.' )
      {
        // element by classname
        var arr_obj = getElementsByClass( splitted[i].replace('.','') );
        for (var j=0;j<arr_obj.length;j++){ array_ret.push( arr_obj[j] ); }
      }
      else
      {
        // todo: element by tagname
      }
    }
  }
  else if ( typeOf(selector) == 'object' )
  {
    array_ret.push( selector );
  }
  else if( typeOf(selector) == 'array' )
  {
    /* Todo */ 
  }
  else
  {
    return null;
  }
  
  if ( array_ret.length == 0 ) return null; //tocheck condition
  
  if( (array_ret.length > 1) )
  {
    // Attach delle funzioni estese
    array_ret.fn = new eXtend.obj.Group ( array_ret );
    return array_ret; 
    //return new eXtend.obj.Group ( array_ret ); 
  }
  else
  {
    // effettuo controllo su garbage oggetti creati, se é giá esistente torno
    // l'oggetto precedentemente istanziato altrimenti istanzia nuovo oggetto eXtend
     
    if( eXtend.Instances )
    {
      for (var i=0;i<eXtend.Instances.length;i++)
      {
        if ( array_ret[0] == eXtend.Instances[i].dom_elm ) return eXtend.Instances[i].dom_elm;
      }
      
      // Attach delle funzioni estese
      array_ret[0].fn = new eXtend( array_ret[0] );
      return array_ret[0];
    } 
  } 
}

window.$$ = function( selector ) 
{
  return $( selector ).fn;
}

/*******************************************************************************
  [EXTEND OBJECT]  
*******************************************************************************/
eXtend = function ( obj )
{
  // Closure
  var obj_eXtend = this;
  var $ = null;
  
  this.dom_elm = $ = null;
	this.elm_id = null;
  this.lock = false;
  
  // Gestione garbage oggetti
  eXtend.Instances.push( this );
  this.istance_id = eXtend.Instances.indexOf( this );
  
  /***************************************************************************
   COSTRUTTORE EXTEND OBJECT  
  ***************************************************************************/
  	
	this.eXtend = function ( obj )
	{ 
	  if (!obj) return;
    this.dom_elm = $ = obj;
    this.elm_id  = obj.id;
    
    data.init(); // Inizializzazione datastore
	};	
  
  /***************************************************************************
    PRIVATE DATASTORE 
  ***************************************************************************/
  var listener = new JEvent();
  
  var data = {};
  
  // Store data.init
  data.init = function()
  { 
    if ( obj_eXtend.css('display') == 'none' )      data.effects.display = false;
    if ( obj_eXtend.css('visibility') == 'hidden' ) data.effects.visible = false;
    
    data.effects.curBgColor = ( obj_eXtend.css('background-color') || '#FFFFFF' );
    data.effects.curBdColor = ( obj_eXtend.css('border-color')     || '#FFFFFF' );
    data.effects.oHeight    = ( parseInt(obj_eXtend.css('height')) || $.offsetHeight );
    data.effects.oWidth     = ( parseInt(obj_eXtend.css('width'))  || $.offsetWidth  );    
  };
  
  // Store data.effects ( per effetti )
  data.effects = {
    visible       : true,
    display       : true,
    velocity      : 40,
    accuracy      : 20,
    curBgColor    : '#FFFFFF',    // Background Color
    curBdColor    : '#FFFFFF',    // Border Color
    curFtColor    : '#000000',    // Font Color
    oHeight       : null,         // Original Height
    oWidth        : null          // Original Width
  };
  
  /*
  // Store data.dom
  data.dom = {
  };
  */
  
  /***************************************************************************
    UI - USER INTERFACE EXTEND OBJECT 
  ***************************************************************************/
  
  this.UI = {
    
    // Semplici ------------------------------------------------------------
    fadeIn : function( parameters ){
      if(!obj_eXtend.lock) return( packages.effects.fadeIn(parameters,-1) ); },
    
    fadeOut : function( lim_opacity, opacity, parameters ){
      if(!obj_eXtend.lock) return( packages.effects.fadeOut(parameters,-1) ); },
    
    fadeColor : function( parameters ){
      if(!obj_eXtend.lock) return( packages.effects.fadeColor(parameters,-1) ); },
      
    morphing : function( parameters ){
      if(!obj_eXtend.lock) return( packages.effects.morphing(parameters,-1) ); },
    
    slide : function( parameters ){
      if(!obj_eXtend.lock) return( packages.effects.slide(parameters,-1) ); },
    
    slideAndMorphing: function( parameters ){
      if(!obj_eXtend.lock) return( packages.effects.slideAndMorphing(parameters,-1) ); },
    
    quiet: function( parameters ){
      if(!obj_eXtend.lock) return( packages.effects.quiet(parameters,-1) ); },

    // Compositi (using Sequence) ------------------------------------------
    fadeOutAndClose : function(){ 
      if(!obj_eXtend.lock) return( packages.effects.fadeOutAndClose() ); },  
      
    openAndFadeIn : function( openParameters, fadeInParameters ){ 
      if(!obj_eXtend.lock) return( packages.effects.openAndFadeIn( openParameters, fadeInParameters ) ); },
    
    reduceAndClose : function(){ 
      if(!obj_eXtend.lock) return( packages.effects.reduceAndClose() ); },
      
    reduceFadeOutAndClose : function(){ 
      if(!obj_eXtend.lock) return( packages.effects.reduceFadeOutAndClose() ); },    
    
    blink : function( color , duration ){
      if(!obj_eXtend.lock) return( packages.effects.blink(color,duration) ); },
    
    swopImage : function( newSrcImage,callbackFn ){
      if(!obj_eXtend.lock) return( packages.effects.swopImage(newSrcImage,callbackFn) ); }                                                   
  }
  
  /***************************************************************************
    PACKAGES PRIVATI 
    
    Note:
      - Per muoversi all'interno del package (tra fn e variabili) si puó 
      utilizzare il riferimento this o packages.effects, ricordarsi in caso di
      utilizzo di fn con settimeout o "sequenziali" di bindarle con il costrutto
      fn.bind( this ) per non perdere lo scope.
      ! verificare differenza tempi di esecuzione.
  ***************************************************************************/
  
  var packages = {};
  packages.effects = {};
  
  /* [PACKAGES.EFFECTS] *****************************************************/
  
    /* [fadeIn]
    @parameters v    : velocitá
    @parameters a    : accuratezza
    @parameters o    : opacitá
    @parameters cbFn : funzione di callback
    @pid  : id processo
    */
    packages.effects.fadeIn = function ( parameters, pid ) 
    {   
      if ( obj_eXtend.lock ) return;
      
      if (!parameters) parameters = false;
      var v = (parameters['v']) || data.effects.velocity;
      var a = (parameters['a']) || data.effects.accuracy;
      var o = (parameters['o']) || 0;    
      if (parameters['cbFn']) this.fadeIn.callbackFn = parameters['cbFn'];
      this.fadeIn.pid = pid;
             
      if( o <= 100)
      {
        this.setOpacity( o ); 
        o = o+ a;
        var fn = function(){ this.fadeIn({'o':o},pid) }.bind ( this );
        window.setTimeout(fn, v);
      }
      else
      {
        this.setOpacity( 100 );
        
        // Exit condition
        obj_eXtend.todoList.checkingList.call(this.fadeIn);
        return;
      } 
    };
    
    /* [fadeOut]
    @parameters v    : velocitá
    @parameters a    : accuratezza
    @parameters o    : opacitá
    @parameters lim_opacity : limite opacitá
    @parameters cbFn : funzione di callback
    @pid  : id processo
    */            
    packages.effects.fadeOut  = function ( parameters, pid )
    { 
      if ( obj_eXtend.lock ) return;
      
      if (!parameters) parameters = false;
      var v = (parameters['v']) || data.effects.velocity;
      var a = (parameters['a']) || data.effects.accuracy;
      var x = (parameters['lim_opacity']) || 0;
      var y = (parameters['o'] == undefined ) ? 100 : parameters['o'];
      if (parameters['cbFn']) this.fadeOut.callbackFn = parameters['cbFn'];
      this.fadeOut.pid = pid;
       
      if(y >= x)
      {
        this.setOpacity( y );
        y = y - a;
        var fn = function(){ this.fadeOut({'o':y},pid) }.bind( this );
        window.setTimeout(fn, v);
      }
      else
      {
        // Exit condition
        obj_eXtend.todoList.checkingList.call(this.fadeOut);
        return;               
      }
    };
      
    /* [setOpacity]
    @opacity  : opacitá
    */ 
    packages.effects.setOpacity = function ( opacity )
    {
      opacity=(opacity==100) ? 99.999 : opacity;
      
      obj_eXtend.css ({
        // IE/Win
        filter: "alpha(opacity:"+opacity+")",
        //filter: "progid:DXImageTransform.Microsoft.Alpha(opacity="+opacity+")",
        // Safari<1.2, Konqueror
        KHTMLOpacity : opacity/100,
        // Older Mozilla and Firefox
        MozOpacity : opacity/100,
        // Safari 1.2, newer Firefox and Mozilla, CSS3
        opacity : opacity/100
      });
    };
    
    /* [quiet]
    @parameters cbFn : funzione di callback
    @pid  : id processo
    */
    packages.effects.quiet = function ( parameters, pid ) 
    { 
      if (!parameters) parameters = false;
      if (parameters['cbFn']) this.quiet.callbackFn = parameters['cbFn'];
      this.quiet.pid = pid;
          
      if(!parameters['eseguito'] || false)
      { 
        var fn = function(){ this.quiet({time:parameters['time'],eseguito:true},pid) }.bind( this );
        window.setTimeout(fn, parameters['time']);
      }
      else
      {
        obj_eXtend.todoList.checkingList.call(this.quiet);
        return;
      }
    };
    
    /* [fadeOutAndClose] */  
    packages.effects.fadeOutAndClose = function ()
    {
      if ( obj_eXtend.lock ) return;
      
      if ( data.effects.display )
      {
        var seq = new Sequence(null);
        obj_eXtend.todoList.arrObjSequence.push ( seq );
        var pid = obj_eXtend.todoList.arrObjSequence.indexOf ( seq ); 
        
        var functs = [];
        functs[0]  = function(){ this.fadeOut(null,pid) }.bind( this );
        functs[1]  = function(){ obj_eXtend.close(); obj_eXtend.todoList.arrObjSequence[pid].exec(); };
        
        obj_eXtend.todoList.arrObjSequence[pid].set_arr_func ( functs );
        obj_eXtend.todoList.arrObjSequence[pid].set_parameters({evalMode:false,loop:false});
        obj_eXtend.todoList.arrObjSequence[pid].exec();
      } 
    };
    
    /* [openAndFadeIn]
    @parameters openParameters   : openParameters
    @parameters fadeInParameters : fadeInParameters
    */
    packages.effects.openAndFadeIn = function( openParameters, fadeInParameters )
    {
      if ( obj_eXtend.lock ) return;
      
      if (!openParameters)   openParameters = null;
      if (!fadeInParameters) fadeInParameters = null;
      
      if ( (!data.effects.display) )
      { 
        var seq = new Sequence(null);
        obj_eXtend.todoList.arrObjSequence.push ( seq );
        var pid = obj_eXtend.todoList.arrObjSequence.indexOf ( seq );
        
        var functs = [];
        functs[0]  = function(){
          this.setOpacity(0);
          obj_eXtend.open( openParameters );
          obj_eXtend.todoList.arrObjSequence[pid].exec(); 
        }.bind( this );
        
        functs[1]  = function(){this.fadeIn(openParameters,pid)}.bind( this );
        
        obj_eXtend.todoList.arrObjSequence[pid].set_arr_func ( functs );
        obj_eXtend.todoList.arrObjSequence[pid].set_parameters({evalMode:false,loop:false});
        obj_eXtend.todoList.arrObjSequence[pid].exec();
      } 
    };
    
    /* [reduceAndClose] */ 
    packages.effects.reduceAndClose = function ()
    {
      if ( obj_eXtend.lock ) return;
      
      if ( data.effects.display )
      {
        var seq = new Sequence(null);
        obj_eXtend.todoList.arrObjSequence.push ( seq );
        var pid = obj_eXtend.todoList.arrObjSequence.indexOf ( seq ); 
        
        var functs = [];
        functs[0]  = function(){ this.morphing({newWidth:1,newHeight:1,v:30},pid) }.bind( this );
        functs[1]  = function(){ obj_eXtend.close(); obj_eXtend.todoList.arrObjSequence[pid].exec(); };
        
        obj_eXtend.todoList.arrObjSequence[pid].set_arr_func ( functs );
        obj_eXtend.todoList.arrObjSequence[pid].set_parameters({evalMode:false,loop:false});
        obj_eXtend.todoList.arrObjSequence[pid].exec();
      } 
    };
    
    /* [reduceFadeOutAndClose] */
    packages.effects.reduceFadeOutAndClose = function ()
    {
      if ( obj_eXtend.lock ) return;
      
      if ( data.effects.display )
      { 
        var seq = new Sequence(null);
        obj_eXtend.todoList.arrObjSequence.push ( seq );
        var pid = obj_eXtend.todoList.arrObjSequence.indexOf ( seq ); 
        
        var functs = [];
        functs[0]  = function(){ this.fadeOut({a:50},-1); this.morphing({newWidth:1,newHeight:1,v:50},pid) }.bind( this );
        functs[1]  = function(){ obj_eXtend.close(); obj_eXtend.todoList.arrObjSequence[pid].exec(); };
        
        obj_eXtend.todoList.arrObjSequence[pid].set_arr_func ( functs );
        obj_eXtend.todoList.arrObjSequence[pid].set_parameters({evalMode:false,loop:false});
        obj_eXtend.todoList.arrObjSequence[pid].exec();
      } 
    };
    
    /* [fadeColor]
    @parameters v    : velocitá
    @parameters a    : accuratezza
    @parameters t    : on css element ['background'/'border'/'font']
    @parameters fromColor : da colore
    @parameters toColor   : a colore
    @parameters cbFn : funzione di callback
    @pid  : id processo
    */ 
    packages.effects.fadeColor = function ( parameters, pid )
    { 
      if ( obj_eXtend.lock ) return;
      
      if (!parameters) parameters = false;
      var v = (parameters['v'])  || data.effects.velocity;
      var a = (parameters['a'])  || data.effects.accuracy;
      var t = (parameters['on']) || 'background';
      if (parameters['cbFn']) this.fadeColor.callbackFn = parameters['cbFn'];

      this.fadeColor.pid = pid;
      
      if ( t=='background' )
      {
        var fromRgbColor = eXtend.utility.RGB( (parameters['fromColor']) || (data.effects.curBgColor) );
        var toRgbColor   = eXtend.utility.RGB( (parameters['toColor'])   || (data.effects.curBgColor) );
      }
      else if ( t=='border' )
      {
        var fromRgbColor = eXtend.utility.RGB( (parameters['fromColor']) || (data.effects.curBdColor) );
        var toRgbColor   = eXtend.utility.RGB( (parameters['toColor'])   || (data.effects.curBdColor) );
      }
      else if ( t=='font' )
      {
        var fromRgbColor = eXtend.utility.RGB( (parameters['fromColor']) || (data.effects.curFtColor) );
        var toRgbColor   = eXtend.utility.RGB( (parameters['toColor'])   || (data.effects.curFtColor) );
      }
      
      var cresciteRgb = [];
      for (i=0;i<3;i++)
      {
        cresciteRgb[i] = ( fromRgbColor[i] <= toRgbColor[i] ) ? true : false;
        
        if( fromRgbColor[i] < toRgbColor[i] ){ cresciteRgb[i] = 1 }
        else if( fromRgbColor[i] > toRgbColor[i] ){ cresciteRgb[i] = 2 }
        else{ cresciteRgb[i] = 3 }    
      }
      
      // Call computing_fade
      this.executeFadeColor( fromRgbColor, toRgbColor, cresciteRgb, a, v, t );   
    };  
    
    /* [executeFadeColor]
    @currentRgbColor : array valori rgb correnti
    @toRgbColor      : array valori rgb finali
    @cresciteRgb     : array crescite rgb
    @accuracy        : accuratezza
    @time            : velocitá
    @on              : css element ['background'/'border'/'font']
    */
    packages.effects.executeFadeColor = function ( currentRgbColor, toRgbColor, cresciteRgb, accuracy, time, on )
    { 
      // exit condition
      if ( 
        (currentRgbColor[0] == toRgbColor[0]) &&
        (currentRgbColor[1] == toRgbColor[1]) &&
        (currentRgbColor[2] == toRgbColor[2])
      )
      {
        obj_eXtend.todoList.checkingList.call(this.fadeColor);
        return; 
      }
      
      for (i=0;i<3;i++)
      {
        if ( (cresciteRgb[i] == 1) && ( (currentRgbColor[i]+accuracy) < toRgbColor[i]) )
        {
          currentRgbColor[i] += accuracy;
        }
        else if ( (cresciteRgb[i] == 2) && ( (currentRgbColor[i]-accuracy) > toRgbColor[i]) )
        {
          currentRgbColor[i] -= accuracy;
        }
        else
        {
          cresciteRgb[i] = 3;
          currentRgbColor[i] = toRgbColor[i];
        }
      }
      
      if ( on=='background' )
      {     
        obj_eXtend.css({ 'backgroundColor': eXtend.utility.HEX( currentRgbColor ) });
        data.effects.curBgColor = eXtend.utility.HEX( currentRgbColor );
      }
      else if ( on=='border' )
      { 
        obj_eXtend.css({ 'borderColor': eXtend.utility.HEX( currentRgbColor ) });
        data.effects.curBdColor = eXtend.utility.HEX( currentRgbColor );
      }
      else if ( on=='font' )
      {
        obj_eXtend.css({ 'color': eXtend.utility.HEX( currentRgbColor ) });
        data.effects.curFtColor = eXtend.utility.HEX( currentRgbColor );
      }
      
      var fn = function(){ this.executeFadeColor(currentRgbColor,toRgbColor,cresciteRgb,accuracy,time,on) }.bind( this );
      window.setTimeout(fn, time);
    };
    
    // [Metodo Privato] blink
    packages.effects.blink = function ( color, duration )
    {
      if ( obj_eXtend.lock ) return;
      
      var restoreColore = data.effects.curBgColor;
      
      var seq = new Sequence(null);
      obj_eXtend.todoList.arrObjSequence.push ( seq );
      var pid = obj_eXtend.todoList.arrObjSequence.indexOf ( seq ); 
      
      var functs = [];
      functs[0]  = function(){this.fadeColor({toColor:color},pid)}.bind( this );
      functs[1]  = function(){this.fadeColor({toColor:restoreColore},pid)}.bind( this ); 
      
      obj_eXtend.todoList.arrObjSequence[pid].set_arr_func ( functs );
      obj_eXtend.todoList.arrObjSequence[pid].set_parameters({evalMode:false,loop:true});
      obj_eXtend.todoList.arrObjSequence[pid].exec();
      
      // Se durata viene settata disabilito il loop nella sequenza dopo il tempo
      // richiesto.
      if ( duration )
      {
        var fn = function(){ obj_eXtend.todoList.arrObjSequence[pid].set_parameters({loop:false}); };
        window.setTimeout(fn, duration);
      }
    };
    
    packages.effects.morphing = function ( parameters, pid )
    { 
      if (!parameters) parameters = false;
      var v = (parameters['v']) || data.effects.velocity;
      var a = (parameters['a']) || data.effects.accuracy;
      var x = (parameters['newWidth'])  || data.effects.oWidth;
      var y = (parameters['newHeight']) || data.effects.oHeight;
      
      if( parameters['saveNewDimensions'] === true )
      {
        data.effects.oWidth  = x;
        data.effects.oHeight = y;
      }
      
      if (parameters['cbFn']) this.morphing.callbackFn = parameters['cbFn'];
      this.morphing.pid = pid;
      
      var arrFromDimension = [ $.offsetWidth, $.offsetHeight ];
      var arrToDimension = [x,y];
      
      var arrCrescita = [];
      for (i=0;i<2;i++)
      {
        arrCrescita[i] = ( arrFromDimension[i] <= arrToDimension[i] ) ? true : false;
        
        if( arrFromDimension[i] < arrToDimension[i] ){ arrCrescita[i] = 1 }
        else if( arrFromDimension[i] > arrToDimension[i] ){ arrCrescita[i] = 2 }
        else{ arrCrescita[i] = 3 }    
      }
      
      // Call computing_fade
      this.executeMorphing( arrFromDimension, arrToDimension, arrCrescita, a, v, pid );
    }
    
    packages.effects.executeMorphing = function (arrCurDimension, arrToDimension, arrCrescita, accuracy, time, pid )
    { 
      // exit condition
      if ( 
        (arrCurDimension[0] == arrToDimension[0]) &&
        (arrCurDimension[1] == arrToDimension[1]) 
      )
      {
        obj_eXtend.todoList.checkingList.call(this.morphing);
        return; 
      }
           
      for (i=0;i<2;i++)
      {
        if ( (arrCrescita[i] == 1) && ( (arrCurDimension[i]+accuracy) < arrToDimension[i]) )
        {
          arrCurDimension[i] += accuracy;
        }
        else if ( (arrCrescita[i] == 2) && ( (arrCurDimension[i]-accuracy) > arrToDimension[i]) )
        {
          arrCurDimension[i] -= accuracy;
        }
        else
        {
          arrCrescita[i] = 3;
          arrCurDimension[i] = arrToDimension[i];
        }
      }
      
      obj_eXtend.css ({
        width  : arrCurDimension[0],
        height : arrCurDimension[1]
      });
      
      var fn = function(){ this.executeMorphing(arrCurDimension,arrToDimension,arrCrescita,accuracy,time,pid) }.bind( this );
      window.setTimeout(fn, time);
    };
    
    // [Metodo Privato] swopImage
    packages.effects.swopImage = function ( newSrcImage,callbackFn )
    {
      if ( obj_eXtend.lock ) return; 
      callbackFn = (callbackFn) ? (callbackFn) : (null);
      
      if ( data.effects.display )
      {
        var seq = new Sequence(null);
        obj_eXtend.todoList.arrObjSequence.push ( seq );
        var pid = obj_eXtend.todoList.arrObjSequence.indexOf ( seq ); 
        
        // Attach onload event listener
        var funct = function()
        { 
          obj_eXtend.todoList.arrObjSequence[pid].exec();
          listener.remove ($, 'load', funct, false); 
        }.bindEventListener( this );
        
        listener.add ($, 'load', funct, false);
        
        var functs = [];
        functs[0]  = function(){ this.fadeOut(null,pid) }.bind( this );
        functs[1]  = function(){ $.src = newSrcImage };
        functs[2]  = function(){ this.fadeIn({cbFn:callbackFn},pid) }.bind( this );
        
        obj_eXtend.todoList.arrObjSequence[pid].set_arr_func ( functs );
        obj_eXtend.todoList.arrObjSequence[pid].set_parameters({evalMode:false,loop:false});
        obj_eXtend.todoList.arrObjSequence[pid].exec();
      } 
    };
    
    // [Metodo Privato] slideAndMorphing            
    packages.effects.slideAndMorphing  = function ( parameters, pid )
    { 
      if ( obj_eXtend.lock ) return;
      
      if (!parameters) parameters = false;
      var v = (parameters['v']) || data.effects.velocity;
      var a = (parameters['a']) || data.effects.accuracy;
      var nw = (parameters['newWidth'])  || $.offsetWidth;
      var nh = (parameters['newHeight']) || $.offsetHeight;
      
      var x = (parameters['x']) || 0;
      var y = (parameters['y']) || 0;
      var z = (parameters['z']) || 'auto';
      var p = (parameters['p']) || 'relative';
      
      this.slide({'v':v,'a':a,'x':x,'y':y,'z':z,'p':p},pid);
      this.morphing({'v':v,'a':a,'newWidth':nw,'newHeight':nh},pid);
    }
    
    
    // [Metodo Privato] slide            
    packages.effects.slide  = function ( parameters, pid )
    { 
      if ( obj_eXtend.lock ) return;
      
      if (!parameters) parameters = false;
      var v = (parameters['v']) || data.effects.velocity;
      var a = (parameters['a']) || data.effects.accuracy;
      var x = (parameters['x']) || 0;
      var y = (parameters['y']) || 0;
      var z = (parameters['z']) || 'auto';
      var p = (parameters['p']) || 'relative';
      
      if (parameters['cbFn']) this.slide.callbackFn = parameters['cbFn'];
      this.slide.pid = pid;      
      
      
      obj_eXtend.css ({
        position : String(p),
        zIndex : String(z) & "" // forcing casting for solve ie problem
      });
      
      var arrFromCoord = [ 
        parseInt(obj_eXtend.css('left')) || 0, 
        parseInt(obj_eXtend.css('top'))  || 0
      ];
      
      var arrToCoord = [x,y];
      
      var arrCrescita = [];
      for (i=0;i<2;i++)
      { 
        if( arrFromCoord[i] < arrToCoord[i] ){ arrCrescita[i] = 1 }
        else if( arrFromCoord[i] > arrToCoord[i] ){ arrCrescita[i] = 2 }
        else{ arrCrescita[i] = 3 }    
      }
      
      // Call executeSlide
      this.executeSlide( arrFromCoord, arrToCoord, arrCrescita, a, v );
    };
    
    packages.effects.executeSlide = function ( arrCurCoord, arrToCoord, arrCrescita, accuracy, time)
    { 
      // exit condition
      if ( 
        (arrCurCoord[0] == arrToCoord[0]) && (arrCurCoord[1] == arrToCoord[1]) 
      )
      {
        obj_eXtend.todoList.checkingList.call(this.slide);
        return; 
      }
           
      for (i=0;i<2;i++)
      {
        if ( (arrCrescita[i] == 1) && ( (arrCurCoord[i]+accuracy) < arrToCoord[i]) )
        {
          arrCurCoord[i] += accuracy;
        }
        else if ( (arrCrescita[i] == 2) && ( (arrCurCoord[i]-accuracy) > arrToCoord[i]) )
        {
          arrCurCoord[i] -= accuracy;
        }
        else
        {
          arrCrescita[i] = 3;
          arrCurCoord[i] = arrToCoord[i];
        }
      }
      
      obj_eXtend.css({
        left : arrCurCoord[0] + 'px',
        top  : arrCurCoord[1] + 'px'
      });

      var fn = function(){ this.executeSlide(arrCurCoord,arrToCoord,arrCrescita,accuracy,time) }.bind( this );
      window.setTimeout(fn, time);
    };

  /************************************************* [END PACKAGES.EFFECTS] */
  
  /***************************************************************************
    METODI PUBBLICI  
  ***************************************************************************/
  
  //
  this.css = function (parameters, obj)
  {
    // In caso non venga passato l'oggetto uso quello interno
  	obj = obj || $;
  	
  	if ( typeOf(parameters) == "object" ){  	
    	for (var param in parameters) 
      {
        obj.style[param] = parameters[param];
      }
    }
    else if ( typeOf(parameters) == "string" )
    {
      if (obj.currentStyle) return obj.currentStyle[parameters];
  	   else if (window.getComputedStyle)
  		  return document.defaultView.getComputedStyle(obj,null).getPropertyValue(parameters);
    }
    else if ( typeOf(parameters) == "array" )
    {
      var arr_ret = new Array();
      for (var i=0;i<parameters.length;i++)
      {
        if (obj.currentStyle) arr_ret[parameters[i]] = obj.currentStyle[parameters[i]];
  	     else if (window.getComputedStyle)
  		    arr_ret[parameters[i]] = document.defaultView.getComputedStyle(obj,null).getPropertyValue(parameters[i]);         
      }
      return arr_ret;
    }
  };
	
	// Add text to object
  this.innerHTML = function( content, append )
  {
    if (!append) append = false;
    if (append) $.innerHTML += content;
    else $.innerHTML = content;
  };
  
  // Close ( show off ) object
  this.close = function ()
  {    
    if ( data.effects.display )
    {
      obj_eXtend.css({ display : 'none' });
      data.effects.display = false;
    }
  };
  
  /* [Open]
    @parameters displayMode : displayMode
  */
  this.open = function ( parameters )
  { 
    if ( !data.effects.display )
    {
      if (!parameters) parameters = false;
      var displayMode = (parameters['displayMode']) || 'block';
      
      obj_eXtend.css({ display : displayMode });
      data.effects.display = true;
    }
  };
  
  this.todoList = {
    arrObjSequence : [],
    checkingList : function(){
      if ( this.pid != -1 ) 
      {
        var temp = this.pid;
        this.pid = -1;
        obj_eXtend.todoList.arrObjSequence[temp].exec();
      }
      if ( this.callbackFn ) 
      {
        var temp = this.callbackFn;
        this.callbackFn = null;
        temp();
      }
    }
  };
   
  // Destroy eXtend object
  this.destroy = function ()
  {
    delete eXtend.Instances[obj_eXtend.istance_id];
    delete this;  // verificare lo stack
  };
  
  /***************************************************************************
    INIZIALIZZAZIONE - chiamata al costruttore  
  ***************************************************************************/
  this.eXtend( obj );
};

/*******************************************************************************
  METODI STATICI  
*******************************************************************************/
eXtend.Instances = [];

eXtend.utility = {  
  // by HTML.it
  // converte da decimale (0..255) a esadecimale (stringa a due caratteri)
  DecToHex  : function (n){
    hex=n.toString(16);
    if(hex.length==1) hex="0"+hex;
    return hex.toUpperCase();
  },
  
  // by HTML.it
  // converte da stringa esadecimale a numero decimale
  HexToDec  : function (s){
    return parseInt(s,16);
  },
  
  // by HTML.it
  // riceve un vettore rgb in decimale e lo converte in stringa esadecimale
  HEX : function (c){
    return ("#" + eXtend.utility.DecToHex(c[0])+ eXtend.utility.DecToHex(c[1]) + eXtend.utility.DecToHex(c[2]));
  },
  
  // by HTML.it
  // restituisce la conversione esadecimale sotto forma di array di interi
  RGB : function (c){
    var r=new Array(3);
    if(c.charAt(0)=="#") c=c.substr(1,6); //elimina il cancelletto
    for(i=0;i<3;i++)
    r[i]=eXtend.utility.HexToDec(c.substr(i*2,2));
    return r;
  },
  
  cross : {
    w3: function() {
      return !!(document.getElementById && document.createElement); }(),
    ie: function() {
      return !!window.ActiveX; }()
  },
  
  // typeof ottimizzata (torna direttamente anche tipo array e null) 
  typeOf : function ( value ) 
  {
    var s = typeof value;
    if (s === 'object') {
        if (value) {
            if (typeof value.length === 'number' &&
                    !(value.propertyIsEnumerable('length')) &&
                    typeof value.splice === 'function') {
                s = 'array';
            }
        } else {
            s = 'null';
        }
    }
    return s;
  }                                                                     
};

eXtend.obj = {};

/*******************************************************************************
  [eXtend.obj.Group OBJECT]  
*******************************************************************************/
eXtend.obj.Group = function ( arr_obj )
{
  this.arr_elm = new Array();
  
  // Closure
  var obj_Group = this;
  
  this.eXtendGroup = function ( arr_obj )
  {     
    var fn = function (obj){ this.arr_elm.push( $$( obj ) ) };
    arr_obj.each( fn, this );
  };
  
  
  /***************************************************************************
    METODI PUBBLICI  
  ***************************************************************************/
  
  this.closeAll = function ()
  { 
    var fn = function (){ this.close() };
    this.arr_elm.each( fn );
  };
  
  this.openAll = function ()
  { 
    var fn = function (){ this.open() };
    this.arr_elm.each( fn );  
  };
  
  this.openOnly = function ( elm )
  {
    var fn = function ()
    {
      if ( typeOf(elm) == 'string' )
      {
        if ( this.elm_id != elm ) this.close();
        else this.open();
      }
      else
      {
        if ( this.dom_elm !== elm ) this.close();
        else this.open();
      }
    };
    
    this.arr_elm.each( fn );
  };
  
  this.UI = {};
  
  this.UI.blink = function ( color , duration )
  {
    var fn = function (){ this.UI.blink( color , duration ) };
    obj_Group.arr_elm.each( fn );
  }; 
  
  this.UI.openAndFadeIn = function ( openParameters, fadeInParameters )
  {
    var fn = function (){ this.UI.openAndFadeIn( openParameters, fadeInParameters ) };
    obj_Group.arr_elm.each( fn );
  };
  
  this.UI.fadeOutAndClose = function ()
  {
    var fn = function (){ this.UI.fadeOutAndClose() };
    obj_Group.arr_elm.each( fn );
  };
  
  this.UI.reduceAndClose = function ()
  {
    var fn = function (){ this.UI.reduceAndClose() };
    obj_Group.arr_elm.each( fn );
  };
  
  //  chiamata al costruttore
  this.eXtendGroup( arr_obj ); 
};
/*******************************************************************************
  [END eXtend.obj.Group OBJECT]  
*******************************************************************************/

/*******************************************************************************
  [eXtend.obj.Gallery OBJECT]  
*******************************************************************************/
eXtend.obj.Gallery = function( selector,arr_image )
{ 
  this.slideshow = null; 
  this.arr_image = null;
  this.current_image = "";
  this.position_array = 0
  this.automatic = false; // OFF MODE
  
  var preload_image = null;
  
  // Closure
  var obj_Gallery = this;
    
  /* Costruttore Gallery */
  this.Gallery = function ( selector,arr_image )
  {
    // Garbage istanze
    //if(!Gallery.Instances) Gallery.Instances = new Array();
    //this.id = Gallery.Instances.length;
    //Gallery.Instances[this.id] = this;
    
    this.slideshow = $(selector);
    this.init ( arr_image );    
  };
  
  /* */
  this.init = function ( new_arr_image )
  {  

    this.arr_image = new_arr_image || null;
    this.current_image = "";
    this.position_array = 0;
    this.automatic = false; // OFF MODE
    this.lock = false;
    
    if ( new_arr_image != null )
    {
      preload_image = new Array();
      
      // Preload in cache arr_image (! da verificare)
      for(i=0;i<(this.arr_image['immagini'].length);i++)
      {
        preload_image[i] = new Image();
        preload_image[i].src = this.arr_image[i];
      }
      
      // Mi sposto subito sulla prima immagine  
      this.setImage ( 0 );
    }
  };
  
  this.Controller = {};
  
  /* Controller.ButtonsController */
  this.Controller.ButtonsController = function ()
  {  
    /* Attacco gestione eventi (...DA SISTEMARE!...) */
    if ( $('.controller_prev') ) 
      $('.controller_prev').onclick = function(){ obj_Gallery.prev_image(); };
    
    if ( $('.controller_next') )  
      $('.controller_next').onclick = function(){ obj_Gallery.next_image(); };
      
    if ( $('.controller_play') )  
      $('.controller_play').onclick = function(){ obj_Gallery.play(); };
  };
  
  /* Controller.Ring */
  this.Controller.Ring = function ( arrObjThumbs, arrThumbs )
  { 
    // Closure
    var objRing = this;
   
    this.arrObjThumbs = null;
    this.arrThumbs    = null;
    var preloadThumbs = null;
    
    this.init = function( arrObjThumbs, arrThumbs )
    {
      if ( (arrObjThumbs === undefined) || (arrObjThumbs === null) ) return false;
      if ( (arrThumbs === undefined) || (arrThumbs === null) ) return false;
      
      preloadThumbs = new Array();
      
      // Preload in cache arr_image (! da verificare)
      for(i=0;i<(arrThumbs.length);i++)
      {
        preloadThumbs[i] = new Image();
        preloadThumbs[i].src = arrThumbs[i];
      }
      
      this.arrObjThumbs = arrObjThumbs;
      this.arrThumbs    = arrThumbs;
    };
    
    this.godx = function ()
    {
      // Incremento indice di posizionamento
      obj_Gallery.position_array++;
      
      var k = 0;  // scostamento
      
      if(obj_Gallery.position_array >= this.arrThumbs.length)
      {
        obj_Gallery.position_array = 0;
      }
      
      var tmp = obj_Gallery.position_array;
      
      for(i=0;i<this.arrObjThumbs.length;i++)
      {
        if( (obj_Gallery.position_array + k) > (this.arrThumbs.length-1) )
        {
          obj_Gallery.position_array = 0;  // array ad anello
          k                          = 0;  // azzero scostamento
        }
        
        this.arrObjThumbs[i].src = this.arrThumbs[obj_Gallery.position_array + k];
        this.arrObjThumbs[i].alt = (obj_Gallery.position_array + k);
        
        k++;  // incremento scostamento  
      }
      
      obj_Gallery.position_array = tmp;
    };
    
    this.gosx = function ()
    {
      // Incremento indice di posizionamento
      obj_Gallery.position_array--;
      var k = 0;  // scostamento
      
      if(obj_Gallery.position_array < 0)
      {
        obj_Gallery.position_array = (this.arrThumbs.length-1);
      }
      
      var tmp = obj_Gallery.position_array;
      
      for(i=0;i<this.arrObjThumbs.length;i++)
      {
        if( (obj_Gallery.position_array + k) > (this.arrThumbs.length-1) )
        {
          obj_Gallery.position_array = 0;  // array ad anello
          k                          = 0;  // azzero scostamento 
        }
        
        this.arrObjThumbs[i].src = this.arrThumbs[obj_Gallery.position_array + k];
        this.arrObjThumbs[i].alt = (obj_Gallery.position_array + k);
        
        k++;  // incremento scostamento  
      }
      
      obj_Gallery.position_array = tmp;
    }; 
    
    // Chiamata Inizializzazione
    this.init( arrObjThumbs, arrThumbs );
  };
  
  /* */
  this.get_current_image = function ()
  {  
    return (this.current_image);
  };
  
  /* */
  this.setImage = function ( index )
  {  
    if( (!this.lock) && (this.arr_image['immagini'][index]) )
    {
      this.lock = true;
      
      this.position_array = index;
      this.current_image = this.arr_image['immagini'][this.position_array];
      
      // Avvio swopImage e rimozione lock
      var callbackFn = function(){ this.lock = false }.bind( this );
      this.slideshow.fn.UI.swopImage(this.current_image,callbackFn);
    }  
  };
  
  /* */  
  this.next_image = function()
  { 
    if(!this.lock)
    {
      this.lock = true;
      
      if( this.position_array < this.arr_image['immagini'].length - 1 )
      {
        this.position_array++;
        this.current_image = this.arr_image['immagini'][this.position_array];
      }
      else
      {
        this.position_array = 0;
        this.current_image = this.arr_image['immagini'][this.position_array];
      }
      
      // Avvio swopImage e rimozione lock
      var callbackFn = function(){ this.lock = false }.bind( this );
      this.slideshow.fn.UI.swopImage(this.current_image,callbackFn);
    }
  };
  
  /* */
  this.prev_image = function()
  { 
    if(!this.lock)
    {
      this.lock = true;
      
      if( this.position_array > 0 )
      {
        this.position_array--;
        this.current_image = this.arr_image['immagini'][this.position_array];
      }
      else
      {
        this.position_array = this.arr_image['immagini'].length - 1;
        this.current_image = this.arr_image['immagini'][this.position_array];
      }
      
      // Avvio swopImage e rimozione lock
      var callbackFn = function(){ this.lock = false }.bind( this );
      this.slideshow.fn.UI.swopImage(this.current_image,callbackFn);
    }
  };
  
  /* */
  this.automatic_slide = function()
  {
    if ( this.automatic )
    {
      if( this.position_array > 0 )
      {
        this.position_array--;
        this.current_image = this.arr_image['immagini'][this.position_array];
      }
      else
      {
        this.position_array = this.arr_image['immagini'].length - 1;
        this.current_image = this.arr_image['immagini'][this.position_array];
      }
      
      // Avvio swopImage e rimozione lock 
      var callbackFn2 = function(){ this.automatic_slide() }.bind( this );
      var callbackFn1 = function(){ this.slideshow.fn.UI.quiet({time:3000,cbFn:callbackFn2}) }.bind( this );
      this.slideshow.fn.UI.swopImage(this.current_image,callbackFn1);
    }
  };
  
  /* */
  this.play = function()
  { 
    if ( !this.automatic )
    {
      this.automatic = true;
      this.lock = true;
      $('.controller_play').src = $('.controller_play').src.replace("play","stop");
      this.automatic_slide();
    }
    else
    {
      $('.controller_play').src = $('.controller_play').src.replace("stop","play");
      this.automatic = false;
      this.lock = false;
    } 
  };
  
  /* Richiamo il costruttore */
  this.Gallery( selector,arr_image );
}
/*******************************************************************************
  [END eXtend.obj.Gallery OBJECT]  
*******************************************************************************/

/*******************************************************************************
  [END EXTEND OBJECT]  
*******************************************************************************/


/*******************************************************************************
  [SEQUENCE OBJECT]  
*******************************************************************************/
Sequence = function( arr_func )
{
  // Definizione di proprietà
  this.arr_func = null;
  this.position_array = -1;
  this.evalMode = true;
  this.loop = false;
  
  // Definizione del metodo costruttore 
  this.Sequence = function( arr_func )
  {
    this.arr_func = arr_func;
    this.position_array  =  -1;
  }
  
  /***************************************************************************
    METODI PUBBLICI  
  ***************************************************************************/
  //  
  this.exec = function( useEval )
  { 
    if ( this.arr_func!=null )
    {
      useEval = (useEval == undefined ) ? this.evalMode : useEval;
    
      if( this.position_array < this.arr_func.length - 1 )
      {
        this.exec_next_func( useEval );
        return true;
      }
      else
      {
        //this.arr_func = null;
        this.position_array  =  -1;
        
        if ( this.loop ) 
        { 
          this.exec_next_func( useEval ) 
        }
        else
        {
          return false;
        }
      }
    }
    else
    {
      return false;
    } 
  }
  
  //  
  this.exec_next_func = function( useEval )
  { 
    this.position_array++;
    
    //lancia la nuova funzione ..
    if ( useEval )
    {
      eval( this.arr_func[this.position_array] );
    } 
    else
    {
      this.arr_func[this.position_array].call();
    }
    
    return true;
  }
  
  //  
  this.set_position_array = function( i )
  { 
    if ( i < this.arr_func.length )
    {
      this.position_array = i;
      return true;
    }
    else
    {
      return false;
    }
  }
  
  //  
  this.set_parameters = function( parameters )
  { 
    if ( parameters )
    {
      for (param in parameters)
      {
        switch( param ) 
        {
          case 'evalMode':  
            this.evalMode = parameters[param];
            break;
          case 'loop':  
            this.loop = parameters[param];
            break;   
        }
      }
    }
  }
    
  //  
  this.set_arr_func = function( arr_func )
  { 
    this.arr_func = arr_func;
    this.position_array  =  -1;
  }
  
  /* Richiamo del costruttore */
  this.Sequence( arr_func );
};
/*******************************************************************************
  [END SEQUENCE OBJECT]  
*******************************************************************************/
})();