if(typeof alvine == 'undefined') alvine = new Object();
alvine_object_createObjectPath(alvine, 'session.effects');

//Fade
function effects_fade(obj, endOpacity, eventName, speed, angle){
  obj = element_isObject(obj);
  if(!obj) return false;
  
  element_buildUniqueObjectID(obj);
  
  tmpEffect = new APP_EFFECT('fade');
  var effectID = tmpEffect.effectID;
  
  alvine_object_createObjectPath(obj, 'effects.'+effectID);

  obj.effects[effectID] = tmpEffect;
  
  var opacity = element_getOpacity(obj);
  
  if(!isDefined(obj.effect_initValues)){
    obj.effect_initValues = new Array();
    obj.effect_initValues.push(opacity);
    element_resetOpacity(obj);
  }
  
  endOpacity  = (!isNull(endOpacity))?endOpacity:opacity;

  //Object needs to tell current values
  obj.effect_getCurrentValues = function(){
    var opacity = element_getOpacity(this);
    return Array(opacity.toString());
  };
  
  //optionally set initial Values
  obj.effect_init = function(){
    if(isNull(this.effect_initValues[0])) return true;
    element_setOpacity(this, this.effect_initValues[0]);
    
    return true;
  }
  
  //Object do effect
  obj.effect_doEffect = function(values, effectID){

    var done = new Array();

    for(var i in values){
      done[i] = false;
      if(!isNull(values[i])){
        element_setOpacity(this, values[i]);
        
        if(values[i] == this.effects[effectID].targetValues[i]) done[i] = true;

      } else {
        done[i] = true;
      }
    }

    if(!done[0]) return true;
    
    this.effect_killInterval(this.effects[effectID].intervalID);
    
    
//document.title = 'done';
    return effectID;
  };
  
  //Add Object to effect and announce Finishing-Values
  var tmpTargetValues = new Array();
  tmpTargetValues.push(endOpacity);
  obj.effects[effectID].addObjects(obj, null, tmpTargetValues, speed, angle, eventName);
  
  return obj;
}

//Rollout
function effects_rollout(obj, endWidth, endHeight, eventName, speed, angle, center){
  obj = element_isObject(obj);
  if(!obj) return false;
  
  element_buildUniqueObjectID(obj);
  
  tmpEffect = new APP_EFFECT('rollout');
  var effectID = tmpEffect.effectID;
  
  alvine_object_createObjectPath(obj, 'effects.'+effectID);
  
  if(!isDefined(obj.effect_initValues)){
    obj.effect_initValues = new Array();
    obj.effect_initValues.push(element_getWidth(obj));
    element_resetWidth(obj);
    obj.effect_initValues.push(element_getHeight(obj));
    element_resetHeight(obj);
  }
  
  obj.effects[effectID] = tmpEffect;
  obj.options_center = (center===true)?true:false;
  
  var size = element_getSize(obj);
  endWidth  = (!isNull(endWidth))?endWidth:size.width;
  endHeight = (!isNull(endHeight))?endHeight:size.height;
  
  //optionally set initial Values
  obj.effect_init = function(){
    if(isDefined(this.effect_initValues)){
      element_setWidth(this, this.effect_initValues[0]);
      element_setHeight(this, this.effect_initValues[1]);
    }    
    return true;
  }
  
  //Object needs to tell current values
  obj.effect_getCurrentValues = function(){
    var size = element_getSize(this);
    return Array(size.width, size.height);
  };
  
  //Object do effect
  obj.effect_doEffect = function(values, effectID){

    var done = new Array();

    for(var i in values){
      done[i] = false;
      if(!isNull(values[i])){
        if(i==0){
          element_setWidth(this, values[i]);
          if(this.options_center) element_centerX(this);
        } else {
          element_setHeight(this, values[i]);
          if(this.options_center) element_centerY(this);
        }
        
        if(values[i] == this.effects[effectID].targetValues[i]) done[i] = true;
        
      } else {
        done[i] = true;
      }
    }

    if(!done[0] || !done[1]) return true;
    
    this.effect_killInterval(this.effects[effectID].intervalID);
    
    
//document.title = 'done';
    return true;
  };
  
  //Add Object to effect and announce Finishing-Values
  var tmpTargetValues = new Array();
  tmpTargetValues.push(endWidth);
  tmpTargetValues.push(endHeight);
  obj.effects[effectID].addObjects(obj, null, tmpTargetValues, speed, angle, eventName);
  
  return obj;
}

//Move
function effects_move(obj, endLeft, endTop, eventName, speed, angle){
  obj = element_isObject(obj);
  if(!obj) return false;
  
  element_buildUniqueObjectID(obj);
  
  tmpEffect = new APP_EFFECT('move');
  var effectID = tmpEffect.effectID;
  
  alvine_object_createObjectPath(obj, 'effects.'+effectID);
  
  obj.effects[effectID] = tmpEffect;
  
  var position = element_getPosition(obj);
  endLeft  = (!isNull(endLeft))?endLeft:position.x;
  endTop   = (!isNull(endTop))?endTop:position.y;
  
  if(!isDefined(obj.effect_initValues)){
    obj.effect_initValues = new Array();
    obj.effect_initValues.push(position.x);
    obj.effect_initValues.push(position.y);
  }
  
  //optionally set initial Values
  obj.effect_init = function(){
    if(isDefined(this.effect_initValues)){
      element_setLeft(this, this.effect_initValues[0]);
      element_setTop(this, this.effect_initValues[1]);
    }
    
    return true;
  }
  
  //Object needs to tell current values
  obj.effect_getCurrentValues = function(){
    var position = element_getPosition(this);
    return Array(position.x, position.y);
  };
  
  //Object do effect
  obj.effect_doEffect = function(values, effectID){

    var done = new Array();

    for(var i in values){
      done[i] = false;
      if(!isNull(values[i])){
        if(i==0){
          element_setLeft(this, values[i]);
        } else {
          element_setTop(this, values[i]);
        }
        if(values[i] == this.effects[effectID].targetValues[i]) done[i] = true;
      } else {
        done[i] = true;
      }
    }

    if(!done[0] || !done[1]) return true;
    
    this.effect_killInterval(this.effects[effectID].intervalID);
    
    
//document.title = 'done';
    return true;
  };
  
  //Add Object to effect and announce Finishing-Values
  var tmpTargetValues = new Array();
  tmpTargetValues.push(endLeft);
  tmpTargetValues.push(endTop);
  obj.effects[effectID].addObjects(obj, null, tmpTargetValues, speed, angle, eventName);
  
  return obj;
}


//EFFECT
function APP_EFFECT(effectType){

  this.effectType = (isDefined(effectType))?effectType:'rollout';
  this.effectID   = element_buildUniqueObjectID(this.effectType);
  
  alvine.session.effects[this.effectID] = new Object();
  alvine.session.effects[this.effectID]['targetObjects'] = new Array();
  
  this['addObjects'] = function(obj, effectID, targetValues, speed, angle, eventName){
    obj = element_isObject(obj);
    if(!obj) return false;
    
    effectID = (isNull(effectID))?this.effectID:effectID;
    this.speed = (isNull(speed))?75:speed;
    this.angle = (isNull(angle))?17:angle;

    //get maximal values
    if(!isDefined(obj.effect_originValues)) obj.effect_originValues = obj.effect_getCurrentValues();
    obj.effect_randomValues     = new Array();
    
    alvine_object_createObjectPath(obj, 'effects.'+effectID+'.targetValues');
    //is value set to 'origin' fallback to originValues
    for(var i in targetValues){
      var commandParts = targetValues[i].toString().split(':');
      switch(commandParts[0]){
        case 'origin':
          targetValues[i] = obj.effect_originValues[i];
          break;
        case 'init':
          targetValues[i] = obj.effect_initValues[i];
          break;
        case 'rand':
          var range = commandParts[1].split(',');
          
          for(var j in range){
            range[j] = element_recalcValue2px(range[j], obj.effect_originValues[i]);
          }
          obj.effect_randomValues[i] = range;
          break;
        default:

          targetValues[i] = element_recalcValue2px(targetValues[i], obj.effect_originValues[i]);

          break;
      }
    }
    obj.effects[effectID].targetValues = targetValues;

    obj.effects_currentIntervalID = null;
    
    obj.effect_calcNewValues      = this.calcNewValues;
    obj.effect_killInterval       = this.killInterval;

    alvine.session.effects[this.effectID].targetObjects.push(obj);
    
    alvine.session.effects[effectID]['srcObject'] = obj;
    
    //set initial values
    if(!obj.effect_initDone) obj.effect_init();
    obj.effect_initDone = true;
    
    obj.effects[effectID].eventName = (!isNull(eventName))?eventName:'now';
    if(obj.effects[effectID].eventName == 'now'){
      alvine.session.effects[effectID].srcObject.effects[effectID].start();
    } else {
      event_add(obj, obj.effects[effectID].eventName, 'alvine.session.effects["'+effectID+'"].srcObject.effects["'+effectID+'"].start()', speed, angle);
    }

    return true;
  };
  
  this['start'] = function(ev){
    if(!ev) ev = window.event;
    
    for(var i in alvine.session.effects[this.effectID].targetObjects){
      var targetObject = alvine.session.effects[this.effectID].targetObjects[i];
      var effectObject = targetObject.effects[this.effectID];
      
      alvine.session.effects[this.effectID].targetObjects[i].effects[this.effectID].initValues = new Array();
      alvine.session.effects[this.effectID].targetObjects[i].effects[this.effectID].initValues = targetObject.effect_getCurrentValues();

      this.intervalID = window.setInterval('alvine.session.effects["'+this.effectID+'"].targetObjects['+i+'].effect_calcNewValues("'+this.effectID+'")', this.speed);

      //is value set to 'origin' fallback to originValues
      for(var j in effectObject.targetValues){
        
        if(typeof targetObject.effect_randomValues[j] == 'object'){
          var range = targetObject.effect_randomValues[j];
          var randValue = js_rand(range[0], range[1]);

          alvine.session.effects[this.effectID].targetObjects[i].effects[this.effectID].targetValues[j] = randValue;
        }
      }
      
      if(!isNull(alvine.session.effects[this.effectID].targetObjects[i].effects_currentIntervalID)){
        alvine.session.effects[this.effectID].targetObjects[i].effect_killInterval(alvine.session.effects[this.effectID].targetObjects[i].effects_currentIntervalID);
      }
      alvine.session.effects[this.effectID].targetObjects[i].effects_currentIntervalID = this.intervalID;
    }

    return true;
  };
  
  this['calcNewValues'] = function(effectID){
    
    var currentValues = this.effect_getCurrentValues();

    for(var i in currentValues){

      if(isNull(currentValues[i])) continue;
      
      currentValues[i] = parseInt(currentValues[i]);
      
      var strt = parseInt(this.effects[effectID].initValues[i]);
      var dest = parseInt(this.effects[effectID].targetValues[i]);

      if(currentValues[i] == dest) continue;

      if(strt<dest){
        distance = (currentValues[i]<(dest/2))?currentValues[i]:(dest-currentValues[i]);        
      } else {
        distance = (currentValues[i]>(strt/2))?(strt-currentValues[i]):currentValues[i];
      }

      distance = (distance<0)?(distance*(-1)):distance;
      distance = (distance==0)?1:distance;

      var factor = Math.ceil(js_acceleration(distance, this.effects[effectID].angle));

      if(strt<dest){
        if((currentValues[i]+factor)<=dest){
          currentValues[i]+= factor;
        } else {
          currentValues[i] = dest;
        }
      } else {
        if((currentValues[i]-factor)>=dest){
          currentValues[i]-= factor;
        } else {
          currentValues[i] = dest;
        }
      }

      //currentValues[i] = currentValues[i];
    }

    this.effect_doEffect(currentValues, effectID);

    return true;
  };
  
  this['killInterval'] = function(intervalID){
    window.clearInterval(intervalID);
    return true;
  };
  
  return true;
}