// Copyright (c) 2008 FlexiGuided GmbH, Berlin

function getAbsoluteLeft(elem) {
  var result = 0;
  while (elem) {
    result += elem.offsetLeft;
    elem = elem.offsetParent;
  }
  return result;
}
function getAbsoluteTop(elem) {
  var result = 0;
  while (elem) {
    result += elem.offsetTop;
    elem = elem.offsetParent;
  }
  return result;
}

// mechanisch
//phyMass       = 0.12;
//phyFriction   = 0.8;
//phySpring     = 25.0;
//phyTime       = 0.4;

// aggressiv
//phyMass       = 0.10;
//phyFriction   = 0.75;
//phySpring     = 25.0;
//phyTime       = 0.25;

// langsam
//phyMass       = 0.20;
//phyFriction   = 1.5;
//phySpring     = 30.0;
//phyTime       = 0.5;

// abgestimmt
//phyMass       = 0.05;
//phyFriction   = 1.0;
//phySpring     = 30.0;
//phyTime       = 0.20;

phyMass       = 0.10;
phyFriction   = 0.8;
phySpring     = 35.0;
phyTime       = 0.30;

phyFrameRate  = 25;
phyCalcCycles = 4;

phyResolution = phyFrameRate * phyCalcCycles
allPhySprings = [];

function PhySpring() {
  this.active         = false;
  this.position       = 0;
  this.impulse        = 0;
  this.anchorPosition = 0;
  this.targetPosition = 0;
  this.changed = function() {};
  allPhySprings[allPhySprings.length] = this;
}

springIntervalLate = 0;

window.setInterval(
  function(late) {
    if (allPhySprings.length == 0) return;
    var cycles = phyCalcCycles;
    if (late) {
      springIntervalLate += late;
      while (springIntervalLate > (1000 / phyResolution)) {
        springIntervalLate -= 1000 / phyResolution;
        cycles += phyCalcCycles;
      }
    }
    var springIndex;
    for (springIndex=0; springIndex<allPhySprings.length; springIndex++) {
      var spring = allPhySprings[springIndex];
      if (spring.anchorPosition != spring.targetPosition) {
        spring.active = true;
      }
      if (spring.active) {
        var cycle;
        for (cycle = 0; cycle < cycles; cycle++) {
          if (spring.targetPosition > spring.anchorPosition) {
            spring.anchorPosition += (1 / phyTime) / phyResolution;
            if (spring.anchorPosition > spring.targetPosition) {
              spring.anchorPosition = spring.targetPosition;
            }
          } else if (spring.targetPosition < spring.anchorPosition) {
            spring.anchorPosition -= (1 / phyTime) / phyResolution;
            if (spring.anchorPosition < spring.targetPosition) {
              spring.anchorPosition = spring.targetPosition;
            }
          }
          spring.position += spring.impulse / phyResolution;
          spring.impulse  -= (
            phyFriction/phyMass * spring.impulse +
            phySpring/phyMass * (spring.position - spring.anchorPosition)
          ) / phyResolution;
        }
        if (
          spring.anchorPosition == spring.targetPosition &&
          Math.abs(spring.position - spring.anchorPosition) < 0.0001 &&
          Math.abs(spring.impulse) / phyMass < 0.001
        ) {
          spring.position = spring.anchorPosition;
          spring.impulse  = 0;
          spring.active   = false;
        }
        spring.changed();
      }
    }
  },
  1000 / phyFrameRate
)

function dynamicZoom(image, options) {
  var spring = new PhySpring();
  var was_active = false;
  var absLeft;
  var absTop;
  var initialWidth  = image.clientWidth;
  var initialHeight = image.clientHeight;
  if (image.parentNode.tagName == "DIV") {
    image.parentNode.style.width  = initialWidth;
    image.parentNode.style.height = initialHeight;
  }
  image.onmouseover = function() { spring.targetPosition = 1; }
  image.onmouseout  = function() { spring.targetPosition = 0; }
  spring.changed = function() {
    var is_active = spring.active || (spring.targetPosition != 0);
    if (is_active && !was_active) {
      was_active = true;
      absLeft = getAbsoluteLeft(image);
      absTop  = getAbsoluteTop(image);
      image.style.position = "absolute";
      image.style.left = absLeft;
      image.style.top  = absTop;
    } else if (was_active && !is_active) {
      was_active = false;
      image.style.position = "static";
      image.style.left = null;
      image.style.top  = null;
    }
    if (is_active) {
      var newWidth = initialWidth * (
        1 + (options.factor - 1) * spring.position
      );
      var newHeight = initialHeight * (
        1 + (options.factor - 1) * spring.position
      );
      if (options.left != undefined && options.right == undefined) {
        image.style.left = Math.round(
          absLeft - spring.position * options.left
        );
      } else if (options.right != undefined && options.left == undefined) {
        image.style.left = Math.round(
          absLeft + initialWidth - newWidth
          + spring.position * options.right
        );
      } else {
        image.style.left = Math.round(
          absLeft - (newWidth - initialWidth) / 2
        );
      }
      if (options.top != undefined && options.bottom == undefined) {
        image.style.top = Math.round(
          absTop - spring.position * options.top
        );
      } else if (options.bottom != undefined && options.top == undefined) {
        image.style.top = Math.round(
          absTop + initialHeight - newHeight
          + spring.position * options.bottom
        );
      } else {
        image.style.top = Math.round(
          absTop - (newHeight - initialHeight) / 2
        );
      }
      image.style.width  = Math.round(newWidth);
      image.style.height = Math.round(newHeight);
    }
  }
}

