  --
  -- AnimatedVehicleNew
  -- Class for all AnimatedVehicles
  --
  -- @author  Stefan Geiger
  -- @date  16/10/09
  --
  -- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.
  
 AnimatedVehicleNew = {};
  
  function AnimatedVehicleNew.prerequisitesPresent(specializations)
      return true;
  end;
  
  function AnimatedVehicleNew:load(xmlFile)
 
      self.playAnimation = SpecializationUtil.callSpecializationsFunction("playAnimation");
      self.stopAnimation = SpecializationUtil.callSpecializationsFunction("stopAnimation");
      self.getIsAnimationPlaying = AnimatedVehicleNew.getIsAnimationPlaying;
      self.getRealAnimationTime = AnimatedVehicleNew.getRealAnimationTime;
      self.getAnimationTime = AnimatedVehicleNew.getAnimationTime;
      self.getAnimationDuration = AnimatedVehicleNew.getAnimationDuration;
      self.setAnimationTime = SpecializationUtil.callSpecializationsFunction("setAnimationTime");
      self.setAnimationStopTime = SpecializationUtil.callSpecializationsFunction("setAnimationStopTime");
      self.setAnimationSpeed = SpecializationUtil.callSpecializationsFunction("setAnimationSpeed");
  
      self.animations = {};
  
      local i=0;
      while true do
          local key = string.format("vehicle.animations.animation(%d)", i);
          if not hasXMLProperty(xmlFile, key) then
              break;
          end;
  
          local name = getXMLString(xmlFile, key.."#name");
          if name ~= nil then
              local animation = {};
              animation.name = name;
              animation.parts = {};
              animation.currentTime = 0;
              animation.currentSpeed = 1;
  
              local partI = 0;
              while true do
                  local partKey = key..string.format(".part(%d)", partI);
                  if not hasXMLProperty(xmlFile, partKey) then
                      break;
                  end;
  
                  local node = Utils.indexToObject(self.components, getXMLString(xmlFile, partKey.."#node"));
                  local startTime = getXMLFloat(xmlFile, partKey.."#startTime");
                  local duration = getXMLFloat(xmlFile, partKey.."#duration");
                  local endTime = getXMLFloat(xmlFile, partKey.."#endTime");
                  local startRot = Utils.getRadiansFromString(getXMLString(xmlFile, partKey.."#startRot"), 3);
                  local endRot = Utils.getRadiansFromString(getXMLString(xmlFile, partKey.."#endRot"), 3);
                  local startTrans = Utils.getVectorNFromString(getXMLString(xmlFile, partKey.."#startTrans"), 3);
                  local endTrans = Utils.getVectorNFromString(getXMLString(xmlFile, partKey.."#endTrans"), 3);
                  local startScale = Utils.getVectorNFromString(getXMLString(xmlFile, partKey.."#startScale"), 3);
                  local endScale = Utils.getVectorNFromString(getXMLString(xmlFile, partKey.."#endScale"), 3);
				  
                  local hasRot = endRot ~= nil; --(startRot ~= nil and endRot ~= nil);
                  local hasTrans = endTrans ~= nil; --(startTrans ~= nil and endTrans ~= nil);
                  local hasScale = endScale ~= nil; --(startRot ~= nil and endRot ~= nil);
				  
                  if node ~= nil and startTime ~= nil and (duration ~= nil or endTime ~= nil) and (hasRot or hasTrans or hasScale) then
                      if endTime ~= nil then
                          duration = endTime - startTime;
                      end;
                      if hasRot and startRot == nil then
                          local x,y,z = getRotation(node);
                          startRot = {x,y,z};
                      end;
                      if hasTrans and startTrans == nil then
                          local x,y,z = getTranslation(node);
                          startTrans = {x,y,z};
                      end;
		              if hasScale and startScale == nil then
                          local x,y,z = getScale(node);
                          startScale = {x,y,z};
                      end;
                      local part = {};
                      part.node = node;
                      part.startTime = startTime*1000;
                      part.duration = duration*1000;
                      if hasRot then
                          part.startRot = startRot;
                         part.endRot = endRot;
                      end;
                      if hasTrans then
                          part.startTrans = startTrans;
                          part.endTrans = endTrans;
                      end;
                      if hasScale then
                          part.startScale = startScale;
                         part.endScale = endScale;
                      end;		
                      table.insert(animation.parts, part);
                  end;
                  partI = partI + 1;
              end;
  
              -- sort parts by start/end time
              animation.partsReverse = {};
              for i, part in ipairs(animation.parts) do
                  table.insert(animation.partsReverse, part);
              end;
              table.sort(animation.parts, AnimatedVehicleNew.animPartSorter);
              table.sort(animation.partsReverse, AnimatedVehicleNew.animPartSorterReverse);
  
              animation.currentPartIndex = 1;
              animation.duration = 0;
              for _, part in ipairs(animation.parts) do
                  animation.duration = math.max(animation.duration, part.startTime + part.duration);
              end;
  
              self.animations[name] = animation;
          end;
  
          i = i+1;
      end;
  
      self.activeAnimations = {};
  end;

  function AnimatedVehicleNew:delete()
  
  end;
  
  
  function AnimatedVehicleNew:readStream(streamId, connection)
      -- TODO
  end;
  
  function AnimatedVehicleNew:writeStream(streamId, connection)
      -- TODO
  end;
  
  function AnimatedVehicleNew:readUpdateStream(streamId, timestamp, connection)
      --[[if connection.isServer then
          local x=streamReadFloat32(streamId);
          local y=streamReadFloat32(streamId);
          local z=streamReadFloat32(streamId);
          local xrot=streamReadFloat32(streamId);
          local yrot=streamReadFloat32(streamId);
          local zrot=streamReadFloat32(streamId);
          AnimatedVehicleNew.setAnimPos(self, animTime);
      end;]]
  end;
  
  function AnimatedVehicleNew:writeUpdateStream(streamId, connection, dirtyMask)
      --[[if not connection.isServer then
          streamWriteFloat32(streamId, self.foldAnimTime);
      end;]]
  end;
  
  function AnimatedVehicleNew:mouseEvent(posX, posY, isDown, isUp, button)
  end;
  
  function AnimatedVehicleNew:keyEvent(unicode, sym, modifier, isDown)
  end;
 
  function AnimatedVehicleNew:update(dt)
      AnimatedVehicleNew.updateAnimations(self, dt)
  end;
  
  function AnimatedVehicleNew:updateTick(dt)
      -- TODO
  end;
  
  function AnimatedVehicleNew:draw()
  end;
  
  function AnimatedVehicleNew:onDetach()
  end;
  
  function AnimatedVehicleNew:onLeave()
  end;
  
  function AnimatedVehicleNew:onDeactivate()
  end;
  
  function AnimatedVehicleNew:onDeactivateSounds()
  end;
  
  function AnimatedVehicleNew:playAnimation(name, speed, animTime, noEventSend)
      local animation = self.animations[name];
      if animation ~= nil then
          if speed == nil then
              speed = animation.currentSpeed;
          end;
          if animTime == nil then
              if speed > 0 then
                  animTime = 0;
              else
                  animTime = 1;
              end;
          end;
          if noEventSend == nil or noEventSend == false then
              if g_server ~= nil then
                  g_server:broadcastEvent(AnimatedVehicleStartEvent:new(self, name, speed, animTime), nil, nil, self);
              else
                  g_client:getServerConnection():sendEvent(AnimatedVehicleStartEvent:new(self, name, speed, animTime));
              end;
          end;
  
          self.activeAnimations[name] = animation;
          animation.currentSpeed = speed;
          animation.currentTime = animTime*animation.duration;
          AnimatedVehicleNew.findCurrentPartIndex(animation);
          for k, part in ipairs(animation.parts) do
              part.curRot = nil;
              part.speedRot = nil;
              part.curTrans = nil;
              part.speedTrans = nil;
              part.curScale = nil;
              part.speedScale = nil;			  
          end;
      end;
  end;
  
function AnimatedVehicleNew:stopAnimation(name, noEventSend)
      if noEventSend == nil or noEventSend == false then
          if g_server ~= nil then
              g_server:broadcastEvent(AnimatedVehicleStopEvent:new(self, name), nil, nil, self);
          else
              g_client:getServerConnection():sendEvent(AnimatedVehicleStopEvent:new(self, name));
          end;
      end
      local animation = self.animations[name];
      if animation ~= nil then
          animation.stopTime = nil;
      end;
      self.activeAnimations[name] = nil;
end;
  
function AnimatedVehicleNew:getIsAnimationPlaying(name)
      return self.activeAnimations[name] ~= nil;
end;
  
function AnimatedVehicleNew:getRealAnimationTime(name)
      local animation = self.animations[name];
      if animation ~= nil then
          return animation.currentTime;
      end;
      return 0;
end;
  
function AnimatedVehicleNew:getAnimationTime(name)
      local animation = self.animations[name];
      if animation ~= nil then
          return animation.currentTime/animation.duration;
      end;
      return 0;
end;
  
function AnimatedVehicleNew:getAnimationDuration(name)
      local animation = self.animations[name];
      if animation ~= nil then
          return animation.duration;
      end;
      return 1;
end;
  
function AnimatedVehicleNew:setAnimationSpeed(name, speed)
      local animation = self.animations[name];
      if animation ~= nil then
          local speedReversed = false;
          if (animation.currentSpeed > 0) ~= (speed > 0) then
              speedReversed = true;
          end;
           animation.currentSpeed = speed;
          if self:getIsAnimationPlaying(name) and speedReversed then
              AnimatedVehicleNew.findCurrentPartIndex(animation);
              for k, part in ipairs(animation.parts) do
                  part.curRot = nil;
                  part.speedRot = nil;
                  part.curTrans = nil;
                  part.speedTrans = nil;
				  part.curScale = nil;
				  part.speedScale = nil;	
              end;
          end;
      end;
end;
  
function AnimatedVehicleNew:setAnimationStopTime(name, stopTime)
      local animation = self.animations[name];
      if animation ~= nil then
          animation.stopTime = stopTime*animation.duration;
      end;
end;
  
function AnimatedVehicleNew.animPartSorter(a, b)
      if a.startTime < b.startTime then
          return true;
      elseif a.startTime == b.startTime then
          return a.duration < b.duration;
      end;
      return false;
end;
  
  function AnimatedVehicleNew.animPartSorterReverse(a, b)
      local endTimeA = a.startTime+a.duration;
      local endTimeB = b.startTime+b.duration;
      if endTimeA > endTimeB then
          return true;
      elseif endTimeA == endTimeB then
          return a.startTime > b.startTime;
      end;
      return false;
  end;
  
function AnimatedVehicleNew.getMovedLimitedValue(currentValue, destValue, speed, dt)
      local limitF = math.min;
      -- we are moving towards -inf, we need to check for the maximum
      if destValue < currentValue then
          limitF = math.max;
     elseif destValue == currentValue then
          return currentValue;
      end;
      local ret = limitF(currentValue + speed * dt, destValue);
      return ret;
end;
  
function AnimatedVehicleNew.findCurrentPartIndex(animation)
      if animation.currentSpeed > 0 then
          -- find the first part that is being played at the current time
          animation.currentPartIndex = 1;
         for i, part in ipairs(animation.parts) do
              if part.startTime <= animation.currentTime then
                  animation.currentPartIndex = i;
                  break;
              end;
          end;
      else
          -- find the last part that is being played at the current time (the first in partsReverse)
          animation.currentPartIndex = 1;
         for i, part in ipairs(animation.partsReverse) do
              if part.startTime+part.duration >= animation.currentTime then
                  animation.currentPartIndex = i;
                  break;
              end;
          end;
      end;
 end;
  
function AnimatedVehicleNew.updateAnimations(self, dt)
      for name, anim in pairs(self.activeAnimations) do
          anim.currentTime = anim.currentTime + dt*anim.currentSpeed;
  
          local absSpeed = math.abs(anim.currentSpeed);
          local dtToUse = dt*absSpeed;
          local stopAnim = false;
          if anim.stopTime ~= nil then
              if anim.currentSpeed > 0 then
                  if anim.stopTime <= anim.currentTime then
                      dtToUse = dtToUse-(anim.currentTime-anim.stopTime);
                      anim.currentTime = anim.stopTime;
                      stopAnim = true;
                  end;
              else
                  if anim.stopTime >= anim.currentTime then
                      dtToUse = dtToUse-(anim.stopTime-anim.currentTime);
                      anim.currentTime = anim.stopTime;
                      stopAnim = true;
                  end;
              end;
          end;
  
          --if stopAnim then
          --    anim.stopTime = nil;
          --    self.activeAnimations[name] = nil;
          --else
  
          local numParts = table.getn(anim.parts)
          local parts = anim.parts;
          if anim.currentSpeed < 0 then
              parts = anim.partsReverse;
          end;
  
          if dtToUse > 0 then
              local hasChanged = false;
              local nothingToChangeYet = false;
              for i=anim.currentPartIndex, numParts do
                  local part = parts[i];
                  if anim.currentSpeed > 0 then
                      -- is this part not playing yet?
                      if part.startTime > anim.currentTime then
                          nothingToChangeYet = true;
                          break;
                      end;
                  else
                      -- is this part not playing yet?
                      if part.startTime + part.duration < anim.currentTime then
                          nothingToChangeYet = true;
                          break;
                      end;
                  end;
  
                  local hasPartChanged = false;
                  -- update the part
                  if part.startRot ~= nil then
                      if part.curRot == nil then
                          local x,y,z = getRotation(part.node);
                          part.curRot = {x,y,z};
                          if anim.currentSpeed > 0 then
                              local duration = math.max(part.startTime+part.duration - anim.currentTime, 0.001); --part.startTime + math.max(part.duration - anim.currentTime, 0);
                              part.speedRot = {(part.endRot[1]-x)/duration, (part.endRot[2]-y)/duration, (part.endRot[3]-z)/duration};
                          else
                              local duration = math.max(anim.currentTime - part.startTime, 0.001);
                              part.speedRot = {(part.startRot[1]-x)/duration, (part.startRot[2]-y)/duration, (part.startRot[3]-z)/duration};
                          end;
                      end;
                      local destRot = part.endRot;
                      if anim.currentSpeed < 0 then
                          destRot = part.startRot;
                      end;
                      local hasRotChanged = false;
                      for i=1, 3 do
                          local newRot = AnimatedVehicleNew.getMovedLimitedValue(part.curRot[i], destRot[i], part.speedRot[i], dtToUse);
                          if part.curRot[i] ~= newRot then
                              hasRotChanged = true;
                              part.curRot[i] = newRot;
                          end;
                      end;
                      --print("set rotation "..part.curRot[1] .." ".. part.curRot[2] .." ".. part.curRot[3] .. " dest: "..destRot[1] .." ".. destRot[2] .." ".. destRot[3]);
                      if hasRotChanged then
                          setRotation(part.node, part.curRot[1], part.curRot[2], part.curRot[3]);
                          hasPartChanged = true;
                      end;
                  end;
                  if part.startTrans ~= nil then
                      if part.curTrans == nil then
                           local x,y,z = getTranslation(part.node);
                          part.curTrans = {x,y,z};
                           if anim.currentSpeed > 0 then
                              local duration = math.max(part.startTime+part.duration - anim.currentTime, 0.001);
                              part.speedTrans = {(part.endTrans[1]-x)/duration, (part.endTrans[2]-y)/duration, (part.endTrans[3]-z)/duration};
                          else
                              local duration = math.max(anim.currentTime - part.startTime, 0.001);
                              part.speedTrans = {(part.startTrans[1]-x)/duration, (part.startTrans[2]-y)/duration, (part.startTrans[3]-z)/duration};
                          end;
                      end;
                      local destTrans = part.endTrans;
                      if anim.currentSpeed < 0 then
                          destTrans = part.startTrans;
                      end;
                      local hasTransChanged = false;
                      for i=1, 3 do
                          local newTrans = AnimatedVehicleNew.getMovedLimitedValue(part.curTrans[i], destTrans[i], part.speedTrans[i], dtToUse);
                          if newTrans ~= part.curTrans[i] then
                             hasTransChanged = true;
                              part.curTrans[i] = newTrans;
                          end;
                      end;
                      if hasTransChanged then
                          setTranslation(part.node, part.curTrans[1], part.curTrans[2], part.curTrans[3]);
                         hasPartChanged = true;
                      end;
                  end;
                  if part.startScale ~= nil then
                      if part.curScale == nil then
                          local x,y,z = getScale(part.node);
                          part.curScale = {x,y,z};
                          if anim.currentSpeed > 0 then
                              local duration = math.max(part.startTime+part.duration - anim.currentTime, 0.001); --part.startTime + math.max(part.duration - anim.currentTime, 0);
                              part.speedScale = {(part.endScale[1]-x)/duration, (part.endScale[2]-y)/duration, (part.endScale[3]-z)/duration};
                          else
                              local duration = math.max(anim.currentTime - part.startTime, 0.001);
                              part.speedScale = {(part.startScale[1]-x)/duration, (part.startScale[2]-y)/duration, (part.startScale[3]-z)/duration};
                          end;
                      end;
                      local destScale = part.endScale;
                      if anim.currentSpeed < 0 then
                          destScale = part.startScale;
                      end;
                      local hasScaleChanged = false;
                      for i=1, 3 do
                          local newScale = AnimatedVehicleNew.getMovedLimitedValue(part.curScale[i], destScale[i], part.speedScale[i], dtToUse);
                          if part.curScale[i] ~= newScale then
                              hasScaleChanged = true;
                              part.curScale[i] = newScale;
                          end;
                      end;
                      --print("set rotation "..part.curScale[1] .." ".. part.curScale[2] .." ".. part.curScale[3] .. " dest: "..destScale[1] .." ".. destScale[2] .." ".. destScale[3]);
                      if hasScaleChanged then
                          setScale(part.node, part.curScale[1], part.curScale[2], part.curScale[3]);
                          hasPartChanged = true;
                      end;
                  end;				 
                  if hasPartChanged then
                      if self.setMovingToolDirty ~= nil then
                          self:setMovingToolDirty(part.node);
                      end;
                      hasChanged = true;
                  end;
                  
                  if anim.currentSpeed > 0 then
                      -- is this part finished?
                      if part.startTime + part.duration < anim.currentTime then
                         part.curRot = nil;
                          part.speedRot = nil;
                          part.curTrans = nil;
                          part.speedTrans = nil;
						  part.curScale = nil;
						  part.speedScale = nil;					
                         --print("finished: "..anim.currentPartIndex);
                          anim.currentPartIndex = anim.currentPartIndex+1;
                      end;
                  else
                      -- is this part finished?
                      if part.startTime > anim.currentTime then
                          part.curRot = nil;
                          part.speedRot = nil;
                          part.curTrans = nil;
                          part.speedTrans = nil;
						  part.curScale = nil;
						  part.speedScale = nil;							  
                          --print("finished: "..anim.currentPartIndex.. " "..name);
                          anim.currentPartIndex = anim.currentPartIndex+1;
                      end;
                  end;
              end;
              if not nothingToChangeYet and not hasChanged and ((anim.currentSpeed > 0 and anim.currentPartIndex == numParts) or (anim.currentSpeed < 0 and anim.currentPartIndex == 1)) then
                  -- end the animation
                  if anim.currentSpeed > 0 then
                      anim.currentTime = anim.duration;
                  else
                      anim.currentTime = 0;
                  end
                  anim.currentPartIndex = 0;
              end;
          end;
          if stopAnim or anim.currentPartIndex > numParts or anim.currentPartIndex < 1 then
              anim.currentTime = math.min(math.max(anim.currentTime, 0), anim.duration);
              anim.stopTime = nil;
              self.activeAnimations[name] = nil;
          end;
      end;
end;