///////////////////////////////////////////////////////////////////////////////
//
//  navigationManager.js
//
// 
// © 2007 Microsoft Corporation. All Rights Reserved.
//
// This file is licensed as part of the Silverlight 1.0 SDK, for details look here: http://go.microsoft.com/fwlink/?LinkID=89144&clcid=0x409
//
///////////////////////////////////////////////////////////////////////////////

// Controls the navigation between pages, and keeps up-to-date state
NavigationManager = function(plugIn, maxNumPages) {
    this.plugIn = plugIn;
    this.maxNumPages = maxNumPages;
    
    this.timer = this.plugIn.content.findname("timerStoryboard");
    this.timer.addEventListener("completed", Silverlight.createDelegate(this, this.onTick));
    
    // animation variables
    this.pageAnimationType = "none";
    this.pageAnimationDelta = 0;
    this.pageAnimationTarget = 0;
    
    // whether to track movement, and previous position if so
    this.trackMovement = false;
    this.previousMouseMovePosition = 0;
    
    this.currX1 = 1400;   
    this.nextOddPage = 1;
}

NavigationManager.prototype.beginPageAnimation = function(type)
{
  if (type == "showFold")
  {
    if (this.nextOddPage < this.maxNumPages)
    {
      this.pageAnimationType = "showFold";
      this.pageAnimationTarget = 1400;
      this.pageAnimationDelta = 5;
      this.timer.begin();
    }
  }
  if (type == "hideFold")
  {
    this.pageAnimationType = "hideFold";
    this.pageAnimationTarget = 1400;
    this.pageAnimationDelta = Math.abs((this.currX1 - this.pageAnimationTarget));
    this.timer.begin();
  }
  else if (type == "finishTurn")
  {
    if (this.nextOddPage < this.maxNumPages)
    {
      this.pageAnimationType = "finishTurn";
      this.pageAnimationDelta = 10;
      this.pageAnimationTarget = 740;
      this.timer.begin();
    }
  }
  else if (type == "none")
  {
    this.pageAnimationType = "none";
    this.pageAnimationDelta = 0;
    this.pageAnimationTarget = 0;
  }
}

// method that ensures animations maintain correct state once they complete
NavigationManager.prototype.onAnimationComplete = function(type)
{
  if (type == "showFold")
  {
    this.pageAnimationType = "none";
  }
  else if (type == "hideFold")
  {
    this.currX1 = 740;
    this.nextOddPage -= 2;
    this.pageAnimationType = "none";
  }
  else if (type == "finishTurn")
  {
    this.currX1 = 1400;
    this.nextOddPage += 2;
    this.pageAnimationType = "none";
    this.beginPageAnimation("showFold");
  }
}

NavigationManager.prototype.onTick = function(sender, eventArgs)
{
  // if we're animating
  if (this.pageAnimationType != "none")
  {
    // if we are done with the current animation
    if (this.currX1 - this.pageAnimationTarget == 0)
    {
      this.onAnimationComplete(this.pageAnimationType);
    }
    // if we are not done with the current animation
    else
    {
      // if we are within a delta of the target, draw one last frame with the final value
      if (Math.abs(this.currX1 - this.pageAnimationTarget) < this.pageAnimationDelta) { this.currX1 = this.pageAnimationTarget; }
      else if (this.currX1 < this.pageAnimationTarget) { this.currX1 += this.pageAnimationDelta; }
      else { this.currX1 -= this.pageAnimationDelta; }
      this.timer.begin();
    }

    // update the scene if possible
    if (this.nextOddPage < this.maxNumPages)
    {
      this.updateScene(this.nextOddPage, this.currX1 - 740);
    }
  }
}

NavigationManager.prototype.oddPageMouseDown = function(sender, eventArgs)
{
    sender.captureMouse();
    this.trackMovement = true;
    this.previousMouseMovePosition = eventArgs.getPosition(null).X + document.body.scrollLeft;

    // if user clicked on a page that has fully turned
    if ("page0"+getTwoDigitInt(this.nextOddPage) != sender.name)
    {
        if (this.nextOddPage < this.maxNumPages)
        {
            this.beginPageAnimation("hideFold");
        }
        else
        {
            this.onAnimationComplete("hideFold");
        }
    }
    else
    {
        this.pageAnimationType = "none";
    }
}   

NavigationManager.prototype.oddPageMouseUp = function(sender, eventArgs)
{
  sender.releaseMouseCapture();
  this.trackMovement = false;

  // if we are far enough to the left, finish the turn
  if (this.currX1 < 900)
  {
    this.beginPageAnimation("finishTurn");
  }
  // otherwise, go back to the folded position
  else
  {
    this.beginPageAnimation("showFold");
  }
}

NavigationManager.prototype.oddPageMouseMove = function(sender, eventArgs)
{
  // if we have an animation pending, don't animate
  if ((this.trackMovement) && (this.pageAnimationType == "none"))
  {
    var _currDelta = ((eventArgs.getPosition(null).x + document.body.scrollLeft) - this.previousMouseMovePosition)*1.05;
    this.previousMouseMovePosition = eventArgs.getPosition(null).x + document.body.scrollLeft;
    this.currX1 = Math.min(1400, Math.max(740, this.currX1 + _currDelta));
    this.updateScene(this.nextOddPage, this.currX1 - 740);
  }
  // if we are tracking movement but in the middle of an animation, update mouse position
  else if (this.trackMovement)
  {
    this.previousMouseMovePosition = eventArgs.getPosition(null).x + document.body.scrollLeft;
  }
}

NavigationManager.prototype.jumpToPage = function(newOddPage)
{
  // cancel all animations
  this.beginPageAnimation("none");

  // goal is this.nextOddPage == newOddPage + 2
  if (this.nextOddPage == newOddPage + 2)
    return;

  // if we need to go backwards
  if (this.nextOddPage > newOddPage + 2)
  {
    if (this.nextOddPage > this.maxNumPages)
      this.nextOddPage -= 2;

    while ((this.nextOddPage > newOddPage + 2) && (this.nextOddPage >= 1))
    {
      this.currX1 = 1400;
      this.updateScene(this.nextOddPage, this.currX1 - 740);
      this.nextOddPage -= 2;
    }

    // if our goal is a valid page
    if (this.nextOddPage >= 1)
    {
      this.currX1 = 1400;
      this.updateScene(this.nextOddPage, this.currX1 - 740);
    }
    else
    {
      this.nextOddPage = 1;
    }
    this.beginPageAnimation("showFold");
  }
  // if we need to go forward
  else
  {
    while ((this.nextOddPage < newOddPage + 2) && (this.nextOddPage < this.maxNumPages))
    {
      this.currX1 = 740;
      this.updateScene(this.nextOddPage, this.currX1 - 740);
      this.nextOddPage += 2;
    }

    // if our goal is a valid page
    if (this.nextOddPage < this.maxNumPages)
    {
      this.currX1 = 1400;
      this.updateScene(this.nextOddPage, this.currX1 - 740);
      this.beginPageAnimation("showFold");
    }
  }
}

// @oddPageNumber: number of the odd page that is currently the next
// @x1: point where the bottom edges of the odd and even pages intersect, in even page coordinates.  Ranges from 0 to 700.
NavigationManager.prototype.updateScene = function(oddPageNumber, x1)
{
  // variables related to odd page
  var oddPoint1 = this.plugIn.content.findName("page" + getTwoDigitInt(oddPageNumber) + "Point1");
  var oddPoint2 = this.plugIn.content.findName("page" + getTwoDigitInt(oddPageNumber) + "Point2");
  var oddPoint3 = this.plugIn.content.findName("page" + getTwoDigitInt(oddPageNumber) + "Point3");
  var oddRotate = this.plugIn.content.findName("page" + getTwoDigitInt(oddPageNumber) + "Rotate");
  var oddTranslate = this.plugIn.content.findName("page" + getTwoDigitInt(oddPageNumber) + "Translate");
  var foldShadow = this.plugIn.content.findName("page" + getTwoDigitInt(oddPageNumber) + "FoldShadow");
  var foldShadowRotate = this.plugIn.content.findName("page" + getTwoDigitInt(oddPageNumber) + "FoldShadowRotate");
  var foldShadowTranslate = this.plugIn.content.findName("page" + getTwoDigitInt(oddPageNumber) + "FoldShadowTranslate");
  var shadowBehindPage01 = this.plugIn.content.findName("shadowBehindPage01");

  // variables related to the even page
  var evenPoint1 = this.plugIn.content.findName("page" + getTwoDigitInt(oddPageNumber-1) + "Point1");
  var evenPoint2 = this.plugIn.content.findName("page" + getTwoDigitInt(oddPageNumber-1) + "Point2");
  var evenPoint3 = this.plugIn.content.findName("page" + getTwoDigitInt(oddPageNumber-1) + "Point3");
  var shadowOnEvenPage = this.plugIn.content.findName("shadowOnEvenPage");

  // _alpha: angle between horizontal axis and bottom edge of odd page.
  //         this can be any function of x1.
  var _alpha = 90/700*x1;

  // update point 1 of even page
  evenPoint1.point = x1 + ",950";
  var shadowStr = x1 + ",950 ";
  shadowStr += Math.min((x1 + 30), 700)  + ",950 ";

  // _leftEdgeAngle: angle between horizontal axis and left edge of odd page
  var _leftEdgeAngle = 90 - _alpha;
  var _bottomLeftCornerX = x1 - Math.cos(_alpha*Math.PI/180) * (700 - x1);
  var _bottomLeftCornerY = Math.sin(_alpha*Math.PI/180) * (700 - x1);

  // update odd page's rotate and translate transform
  oddRotate.angle = _alpha;
  oddTranslate.x = 700 + _bottomLeftCornerX;
  oddTranslate.y = (-1) * _bottomLeftCornerY;

  // how much of the odd page's left edge can be seen
  var _visibleLeftEdgeHeight = (700 - _bottomLeftCornerX) / Math.cos(_leftEdgeAngle*Math.PI/180);

  // if the top left corner can be seen
  if (_visibleLeftEdgeHeight >= 950)
  {
    // height between top left corner of the odd page and top edge of the even page
    var _topLeftCornerY = _bottomLeftCornerY + Math.sin(_leftEdgeAngle*Math.PI/180)*950;

    // _visibleTopEdgeWidth: width of top edge of odd page that is visible
    var _visibleTopEdgeWidth;
    // _x2: x coordinate of the point where top edges of odd and even pages intersect
    var _x2;

    if (_topLeftCornerY > 950)
    {
      _visibleTopEdgeWidth = (_topLeftCornerY - 950) / Math.sin(_alpha*Math.PI/180);
      _x2 = _bottomLeftCornerX + Math.cos(_leftEdgeAngle*Math.PI/180)* 950 + (_topLeftCornerY - 950)/Math.tan(_alpha*Math.PI/180);
    }
    else
    {
      _visibleTopEdgeWidth = 700;
      _x2 = 0;
    }

    oddPoint1.point = "0, 0";
    oddPoint2.point = _visibleTopEdgeWidth + ", 0";

    // update foldShadow properties
    var _foldAngle = 90 - (180/Math.PI)*Math.atan(950/(700 - x1 - _visibleTopEdgeWidth));
    foldShadowRotate.angle = (-1) * _foldAngle;

    // need to adjust the position of the foldShadow so that it covers the entire folded edge
    var _foldShadowAdjustment = 40;
    foldShadowTranslate.x = _visibleTopEdgeWidth - 20 * Math.cos(_foldAngle*Math.PI/180) - _foldShadowAdjustment*Math.cos((90 - _foldAngle)*Math.PI/180);
    foldShadowTranslate.y =  20 * Math.sin(_foldAngle*Math.PI/180) - _foldShadowAdjustment*Math.sin((90 - _foldAngle)*Math.PI/180);;

    evenPoint2.point = _x2 + ",0";
    evenPoint3.point = _x2 + ",0";

    shadowStr += Math.min((_x2+10), 700) + ",0 " + _x2 + ",0";

  }
  // if the top left corner cannot be seen
  else
  {
    // update points of the odd page, which are both the same
    oddPoint1.point = "0, " + (950 - _visibleLeftEdgeHeight);
    oddPoint2.point = "0, " + (950 - _visibleLeftEdgeHeight);

    // update points of the even page
    var _y2 = 950 - _bottomLeftCornerY - (700 - _bottomLeftCornerX) * Math.tan(_leftEdgeAngle*Math.PI/180);
    evenPoint2.point = "700," + _y2 ;
    evenPoint3.point = "700,0";

    // update shadow string on top of the even page
    shadowStr += "700," + _y2 + " 700," + _y2;

    // update foldShadow properties
    var _foldAngle;
    if (x1 != 700)
    {
        _foldAngle = 90 - (180/Math.PI)*Math.atan(_visibleLeftEdgeHeight/(700 - x1));
    }
    else
    {
        //the arctangent of infinity is 90
        _foldAngle = 0;
    }

    foldShadowRotate.angle = (-1) * _foldAngle;
    foldShadowTranslate.x = (-1) * 20 * Math.cos(_foldAngle*Math.PI/180) ;
    foldShadowTranslate.y =  (950 - _visibleLeftEdgeHeight) +  20 * Math.sin(_foldAngle*Math.PI/180) ;
  }

  oddPoint3.point = (700 - x1) + ", 950";
  shadowOnEvenPage.points = shadowStr;

  if (x1 < 15)
  {
    shadowOnEvenPage.opacity = 0.25*(x1/15);
    //foldShadow.opacity = 0.6*(x1/15);
    if (oddPageNumber > 1) {  shadowBehindPage01.opacity = 0.8; }
    else {  shadowBehindPage01.opacity = 0.8 - 0.8*(x1/15); }
  }
  else
  {
    shadowOnEvenPage.opacity = 0.25;
    //foldShadow.opacity = 0.6;
    if (oddPageNumber > 1) {  shadowBehindPage01.opacity = 0.8; }
    else {  shadowBehindPage01.opacity = 0; }
  }
}
