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


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

  alvine_object_createObjectPath(alvine, 'session.effects.'+obj.id+'.data.effects.'+effectID);

  var dataObj = alvine.session.effects[obj.id].data;

  dataObj.parentObject = obj;

  dataObj.callback = callback;

  dataObj.effects[effectID] = tmpEffect;

  var opacity = element_getOpacity(obj);

  if(!isDefined(dataObj.effect_initValues)){
    dataObj.effect_initValues = new Array();
    dataObj.effect_initValues.push(opacity);
    element_resetOpacity(obj);
  }
  
  endOpacity  = (!isNull(endOpacity))?endOpacity:opacity;

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

  //Object do effect
  dataObj.effect_doEffect = function(values, effectID){

    var done = new Array();

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

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

    if(!done[0]) return true;
    
    this.effects[effectID].stop();
    
    if(typeof this.callback != 'function') return true;

    this.callback();
    
    return effectID;
  };
  
  //Add Object to effect and announce Finishing-Values
  var tmpTargetValues = new Array();
  tmpTargetValues.push(endOpacity);
  dataObj.effects[effectID].addObjects(dataObj, null, tmpTargetValues, speed, angle, eventName);

  return dataObj;
}

//Rollout
function effects_rollout(obj, endWidth, endHeight, eventName, speed, angle, center, callback){
  obj = element_isObject(obj);
  if(!obj) return false;
  
  tmpEffect = new APP_EFFECT('rollout');
  var effectID = tmpEffect.effectID;
  
  alvine_object_createObjectPath(alvine, 'session.effects.'+obj.id+'.data.effects.'+effectID);

  var dataObj = alvine.session.effects[obj.id].data;
  dataObj.parentObject = obj;

  dataObj.callback = callback;

  dataObj.effects[effectID] = tmpEffect;

  if(!isDefined(dataObj.effect_initValues)){
    dataObj.effect_initValues = new Array();
    dataObj.effect_initValues.push(element_getWidth(dataObj.parentObject));
    element_resetWidth(dataObj.parentObject);
    dataObj.effect_initValues.push(element_getHeight(dataObj.parentObject));
    element_resetHeight(dataObj.parentObject);
  }
  
  dataObj.effects[effectID] = tmpEffect;
  dataObj.options_center = (center===true)?true:false;
  
  var size = element_getSize(dataObj.parentObject);
  endWidth  = (!isNull(endWidth))?endWidth:size.width;
  endHeight = (!isNull(endHeight))?endHeight:size.height;
  
  //optionally set initial Values
  dataObj.effect_init = function(){
    if(isDefined(this.effect_initValues)){
      element_setWidth(this.parentObject, this.effect_initValues[0]);
      element_setHeight(this.parentObject, this.effect_initValues[1]);
    }    
    return true;
  }
  
  //Object needs to tell current values
  dataObj.effect_getCurrentValues = function(){
    var size = element_getSize(this.parentObject);
    return Array(size.width, size.height);
  };

  //Object do effect
  dataObj.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.parentObject, values[i]);
          if(this.options_center) element_centerX(this.parentObject);
        } else {
          element_setHeight(this.parentObject, values[i]);
          if(this.options_center) element_centerY(this.parentObject);
        }
        
        if(values[i] == this.effects[effectID].targetValues[i]) done[i] = true;
        
      } else {
        done[i] = true;
      }
    }

    if(!done[0] || !done[1]) return true;

    this.effects[effectID].stop();
    
    if(typeof this.callback != 'function') return true;

    this.callback();

    return true;
  };
  
  //Add Object to effect and announce Finishing-Values
  var tmpTargetValues = new Array();
  tmpTargetValues.push(endWidth);
  tmpTargetValues.push(endHeight);
  dataObj.effects[effectID].addObjects(dataObj, null, tmpTargetValues, speed, angle, eventName);
  
  return dataObj;
}

//Move
function effects_move(obj, endLeft, endTop, eventName, speed, angle, callback){
  obj = element_isObject(obj);
  if(!obj) return false;
  
  tmpEffect = new APP_EFFECT('move');
  var effectID = tmpEffect.effectID;
  
  alvine_object_createObjectPath(alvine, 'session.effects.'+obj.id+'.data.effects.'+effectID);

  var dataObj = alvine.session.effects[obj.id].data;
  dataObj.parentObject = obj;
  
  dataObj.callback = callback;

  dataObj.effects[effectID] = tmpEffect;
  
  var position = element_getPosition(obj);

  if(isNaN(endLeft) || endLeft==null) {
    endLeft  = position.x;
  }
  if(isNaN(endTop) || endTop==null) {
    endTop  = position.y;
  }
  
  if(!isDefined(dataObj.effect_initValues)){
    dataObj.effect_initValues = new Array();
    dataObj.effect_initValues.push(position.x);
    dataObj.effect_initValues.push(position.y);
  }
  
  //optionally set initial Values
  dataObj.effect_init = function(){
    if(isDefined(this.effect_initValues)){
      element_setLeft(this.parentObject, this.effect_initValues[0]);
      element_setTop(this.parentObject, this.effect_initValues[1]);
    }
    
    return true;
  }
  
  //Object needs to tell current values
  dataObj.effect_getCurrentValues = function(){
    var position = element_getPosition(this.parentObject);
    return Array(position.x, position.y);
  };

  //Object do effect
  dataObj.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.parentObject, values[i]);
        } else {
          element_setTop(this.parentObject, 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.effects[effectID].stop();

    if(typeof this.callback != 'function') return true;

    this.callback();

    return true;
  };
  
  //Add Object to effect and announce Finishing-Values
  var tmpTargetValues = new Array();
  tmpTargetValues.push(endLeft);
  tmpTargetValues.push(endTop);
  dataObj.effects[effectID].addObjects(dataObj, null, tmpTargetValues, speed, angle, eventName);
  
  return dataObj;
}


//EFFECT
function APP_EFFECT(effectType){

  this.effectType = (isDefined(effectType))?effectType:'rollout';
  this.effectID   = element_buildUniqueObjectID(this);

  this.targetObjects = new Array();

  if(typeof this.intervalList != 'object') this.intervalList = new Object();

  this['stop'] = function(killAll){
    if(killAll){
      for(var i in this.srcObject.effects){
        this.srcObject.effects[i].stop();
      }
    } else {
      if(this.intervalID){
        window.clearInterval(this.intervalID);
        this.intervalID = null;
      }
    }
    return true;
  };

  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();
    
    //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;
      }
    }
    this.targetValues = targetValues;
    
    obj.effect_calcNewValues      = this.calcNewValues;

    obj.effect_start = function(effectID){
      if(typeof this.effects[effectID] == 'undefined') return true;
      
      this.effects[effectID].start();
      return true;
    };

    obj.effect_killInterval       = function(){
      this.effects[effectID].stop();
      return true;
    };
    obj.effect_stop               = obj.effect_killInterval;

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

    return true;
  };

  this['start'] = function(){

    for(var i in this.targetObjects){
      var targetObject = this.targetObjects[i];
      var arrayObject  = alvine.session.effects[targetObject.id].data;
    
      this.initValues = new Array();
      this.initValues = arrayObject.effect_getCurrentValues();

      for(var j in this.targetValues){
        if(typeof arrayObject.effect_randomValues[j] == 'object'){
          var range = arrayObject.effect_randomValues[j];
          var randValue = js_rand(range[0], range[1]);

          this.targetValues[j] = randValue;
        }
      }
      
      this.stop(true);

      this.intervalID = window.setInterval('alvine.session.effects["'+targetObject.id+'"].data.effect_calcNewValues("'+this.effectID+'")', this.speed);
      
    }

    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;
  };
  
  

  
  return true;
}

//effect-scripts
function effects_slideEffect(srcObject, slideObject, timeout, slideBorder, srcEvent){
  srcObject   = (srcObject)?element_isObject(srcObject):false;
  slideObject = element_isObject(slideObject);
  if(!slideObject) return;

  srcObject.slideObj = slideObject;

  slideBorder = (typeof slideBorder == 'undefined')?'top':slideBorder;
  var slideBorderOffset = slideBorder.split(':');
  slideBorder = slideBorderOffset[0];
  
  slideBorderOffset = (typeof slideBorderOffset[1] != 'undefined')?slideBorderOffset[1]:0;

  srcEvent    = (typeof srcEvent == 'undefined')?'onclick':srcEvent;

  slideObject.timeout = (typeof timeout=='undefined')?0:timeout;

  slideObject.initSize = element_getSize(slideObject);

  var viewPort = (slideObject.parentNode.tagName.toString().toLowerCase()!='body')?element_getSize(slideObject.parentNode):alvine_getViewport();

  slideObject.targetPosition = {x:0,y:0};
  var newLeft, newTop;
  switch(slideBorder){
    case 'top':
      slideBorderOffset = (slideBorderOffset>0)?(slideObject.initSize.height-slideBorderOffset):0;
      newTop = (slideObject.initSize.height*(-1));
      element_setTop(slideObject, newTop);            
      slideObject.initPosition = element_getPosition(slideObject);      
      if(slideObject.initPosition.x<0 || slideObject.initPosition.x>viewPort.width){
        slideObject.initPosition.x = 0;
        element_setLeft(slideObject, slideObject.initPosition.x);
      }
      slideObject.targetPosition.x = slideObject.initPosition.x;
      slideObject.targetPosition.y = (0 - slideBorderOffset);
      break;
    case 'right':
      slideBorderOffset = (slideBorderOffset>0)?(slideObject.initSize.width-slideBorderOffset):0;
      newLeft = viewPort.width;      
      element_setLeft(slideObject, newLeft);
      slideObject.initPosition = element_getPosition(slideObject);
      slideObject.targetPosition.x = ((newLeft-slideObject.initSize.width) + slideBorderOffset);
      if(slideObject.initPosition.y<0 || slideObject.initPosition.y>viewPort.height){
        slideObject.initPosition.y = 0;
        element_setTop(slideObject, slideObject.initPosition.y);
      }
      slideObject.targetPosition.y = slideObject.initPosition.y;
      break;
    case 'bottom':
      slideBorderOffset = (slideBorderOffset>0)?(slideObject.initSize.height-slideBorderOffset):0;
      newTop = viewPort.height;      
      element_setTop(slideObject, newTop);
      slideObject.initPosition = element_getPosition(slideObject);
      if(slideObject.initPosition.x<0 || slideObject.initPosition.x>viewPort.width){
        slideObject.initPosition.x = 0;
        element_setLeft(slideObject, slideObject.initPosition.x);
      }
      slideObject.targetPosition.x = slideObject.initPosition.x;
      slideObject.targetPosition.y = ((newTop-slideObject.initSize.height) + slideBorderOffset);
      break;
    case 'left':
      slideBorderOffset = (slideBorderOffset>0)?(slideObject.initSize.width-slideBorderOffset):0;
      newLeft = (slideObject.initSize.width*(-1));
      element_setLeft(slideObject, newLeft);
      slideObject.initPosition = element_getPosition(slideObject);      
      slideObject.targetPosition.x = (0 - slideBorderOffset);
      if(slideObject.initPosition.y<0 || slideObject.initPosition.y>viewPort.height){
        slideObject.initPosition.y = 0;
        element_setTop(slideObject, slideObject.initPosition.y);
      }
      slideObject.targetPosition.y = slideObject.initPosition.y;
      break;
  }
  

  slideObject.effectChain = function(){
    var cb = function(){
      var obj = this.parentObject;
      if(obj.timeout==0) return;

      window.setTimeout("effects_move('"+ obj.id +"', '"+ obj.initPosition.x+"', '"+ obj.initPosition.y +"', 'now', 12, 18)", obj.timeout);
      return ;
    };
    effects_move(this, this.targetPosition.x, this.targetPosition.y, 'now', 12, 18, cb);

    return;
  };

  if(srcObject){
    srcObject[srcEvent] = function(ev){
      if(!ev) ev = window.event;
      this.slideObj.effectChain();
    };
  } else {
    slideObject.effectChain();
  }

  slideObject.hide = function(){
     effects_move(this, this.initPosition.x, this.initPosition.y, 'now', 12, 18);
  }
}


/*****************
* Dynamic folding
******************/

function effects_arrangeFoldingStructure(obj){
  obj = element_isObject(obj);
  if(!obj) return null;

  obj.alvine_currentFoldStatus = 'folded';
  obj.alvine_newFoldStatus = 'unfolded';

  effects_buildFoldingStructure(obj);
  effects_activateFoldingStructure(obj);

  return true;
}

function effects_buildFoldingStructure(obj, level){
  obj = element_isObject(obj);
  if(!obj) return null;

  level = (typeof level == 'undefined')?0:level;

  for(var i in obj.childNodes){
    var cObj = obj.childNodes[i];
    cObj = element_isObject(cObj);
    if(!cObj) continue;
    if(typeof cObj != 'object') continue;
    if(typeof cObj.id == 'undefined') continue;

    var classNames = cObj.className.split(' ');

    var listKey = '';
    for(var j in classNames){
      var cClassName = classNames[j];
      if(cClassName.indexOf('listKey', 0)!=0) continue;
      listKey = cClassName.substr(7).toLowerCase();
      break;
    }
    if(listKey == '') continue;

    /////code
    cObj.alvine_parentObj = obj;
    if(typeof obj.alvine_children == 'undefined') obj.alvine_children = new Object();
    if(typeof obj.alvine_children[listKey] == 'undefined') obj.alvine_children[listKey] = new Object();
    obj.alvine_children[listKey][cObj.id] = cObj;
    cObj.alvine_masterObj = (typeof obj.alvine_masterObj == 'undefined')?obj:obj.alvine_masterObj;
    if(listKey=='folderswitch'){
      if(typeof cObj.alvine_masterObj.alvine_masterChildren == 'undefined') cObj.alvine_masterObj.alvine_masterChildren = new Object();
      if(typeof cObj.alvine_masterObj.alvine_masterChildren.folderswitch == 'undefined') cObj.alvine_masterObj.alvine_masterChildren.folderswitch = new Object();
      cObj.alvine_masterObj.alvine_masterChildren.folderswitch[cObj.id] = cObj;
    }
    ///code

    if(typeof cObj.hasChildNodes == 'function' && !cObj.hasChildNodes()) continue;
    effects_buildFoldingStructure(cObj, (level+1));

  }

  return true;
}

function effects_activateFoldingStructure(obj){

  if(typeof obj.alvine_children == 'undefined') return null;
  for(var type in obj.alvine_children){
    var cType = obj.alvine_children[type];

    for(var id in cType){
      var cChild = cType[id];

      switch(type){
        case 'childrenfolder':
          break;
        case 'childpanel':
          break;
        case 'folderswitch':
          if(typeof obj.alvine_children.childrenfolder == 'undefined') break;

          cChild.alvine_toggleStatus = function(status){
            status = (typeof status != 'undefined' && status == 'unfolded')?'unfolded':'folded';
            this.alvine_currentFoldStatus = status;

            for(var i in this.alvine_parentObj.alvine_children.childrenfolder){
              var cFolder = this.alvine_parentObj.alvine_children.childrenfolder[i];
              if(typeof cFolder.alvine_initSize == 'undefined') cFolder.alvine_initSize = element_getSize(cFolder);
              if(this.alvine_currentFoldStatus=='unfolded'){
                //element_setHeight(cFolder, cFolder.alvine_initSize.height);
                element_setHeight(cFolder, 'auto');
                element_replaceClassName(this, ' folded', ' unfolded');
              } else if(this.alvine_currentFoldStatus=='folded'){
                element_setHeight(cFolder, 0);
                element_replaceClassName(this, ' unfolded', ' folded');
              }
            }
            this.alvine_newFoldStatus = (this.alvine_currentFoldStatus == 'folded')?'unfolded':'folded';
          };

          cChild.alvine_toggleStatus('folded');

          cChild.onclick = function(ev){
            if(!ev) ev = window.event;
            
            this.alvine_toggleStatus(this.alvine_newFoldStatus);

            return object_preventDefaultEventBehaviour(ev);
          };

          break;
        case 'datailfolder':
          break;
      }

      effects_activateFoldingStructure(cChild);

    }
  }
  return true;
}

function effects_toggleFoldingStatusAll(obj, status){
  obj = element_isObject(obj);

  status = (typeof status != 'undefined' && status == 'unfolded')?'unfolded':'folded';
  if(!obj) return status;
  obj.alvine_currentFoldStatus = status;
  if(typeof obj.alvine_masterChildren == 'undefined') return null;

  var children;
  var cFolder;

  if(typeof obj.alvine_masterChildren.folderswitch != 'undefined'){
    children = obj.alvine_masterChildren.folderswitch;

    for(var fid in children){
      cFolder = children[fid];
      cFolder.alvine_toggleStatus(obj.alvine_currentFoldStatus);
    }
  }

  obj.alvine_newFoldStatus = (obj.alvine_currentFoldStatus == 'folded')?'unfolded':'folded';
  return obj.alvine_newFoldStatus;
}
function effects_initToggleListFoldingButton(obj, listObj){
  obj = element_isObject(obj);
  if(!obj) return false;
  if(typeof obj.alvine_initDone != 'undefined' && obj.alvine_initDone == true) return true;
  obj.alvine_initDone = true;

  listObj = element_isObject(listObj);
  if(!listObj) return false;

  obj.alvine_listObj = listObj;

  event_add(obj, 'click', effects_handleListFoldingToggleClick, true);

  return true;
}

function effects_handleListFoldingToggleClick(ev){
  if(!ev) ev = window.event;

  effects_toggleFoldingStatusAll(this.alvine_listObj, this.alvine_listObj.alvine_newFoldStatus);

  element_replaceClassName(this, this.alvine_listObj.alvine_newFoldStatus, this.alvine_listObj.alvine_currentFoldStatus);

  this.alvine_oldStatus = this.alvine_newStatus;

}

