function PageTurn(bookDetails, control, spread, media_uri)
{
    this.bookDetails = bookDetails;
	this.maxNumPages = getNewPageObjects(bookDetails.backCoverImage, bookDetails.pageObjects);
    this.title = bookDetails.shortTitle;
    this.bookID = bookDetails.bookId;
    this.spread = spread;
    this.plugIn = control;      // Store the host plug-in
    this.currentDownload = 0;   // Current resource to be downloaded  
    
    if(this.spread == -1)
        this.addition = 3;
    else
        this.addition = 0;
    
    this.arrayOfOddPages = new Array();
    this.arrayOfEvenPages = new Array();
    
    //create NavigationManager
    this.navigationManager = new NavigationManager(this.plugIn, this.maxNumPages, bookDetails);
    
    // create PageGenerator
    this.pageGenerator = new PageGenerator(bookDetails, media_uri, spread);
    
    // begin downloading all assets
    this.downloadAssets();
}

function getTwoDigitInt(number)
{
  // if this number already has two digits, return the int part
  if ((number < 0) || (number >= 10))
    return Math.floor(number).toString();

  // otherwise, prepend zero
  return "0" + Math.floor(number);
}


PageTurn.prototype.downloadAssets = function()
{
    this.downloader = this.plugIn.createObject("Downloader");
    this.downloader.addEventListener("downloadProgressChanged", Silverlight.createDelegate(this, this.downloadProgressChanged));
    this.downloader.addEventListener("completed", Silverlight.createDelegate(this, this.downloadCompleted));
    this.downloader.addEventListener("downloadFailed", Silverlight.createDelegate(this, this.downloadFailed));
    this.downloader.open("GET", this.pageGenerator.resourceArray[this.currentDownload]);
    this.downloader.send();
    
    //show the loader.
    this.plugIn.content.findName("loadingHolder")["Visibility"] = "Visible";
    var progressText = this.plugIn.content.findName("loadingText");
    progressText.text = "loading... " + Math.round((((this.currentDownload + 1) / (this.maxNumPages + this.addition)) * 100)).toString() + "% completed";
    var progressRect = this.plugIn.content.findName("loadingBar");
    progressRect.width = ((this.currentDownload) / (this.maxNumPages + this.addition)) * 280;
}

PageTurn.prototype.downloadFailed = function(sender, args)
{
    alert("Download failed: Please check your internet connection and try again.");
}

PageTurn.prototype.downloadProgressChanged = function(sender, args)
{
    //var progressRect = this.plugIn.content.findName("progressRect");
    //progressRect.width = (sender.downloadProgress) * 450;
    if(Math.round((((this.currentDownload) / this.maxNumPages + this.addition) * 100)) <= 100)
    {
    var progressText = this.plugIn.content.findName("loadingText");
    progressText.text = "loading... " + Math.round((((this.currentDownload) / (this.maxNumPages + this.addition)) * 100)).toString() + "% completed";
    var progressRect = this.plugIn.content.findName("loadingBar");
    progressRect.width = ((this.currentDownload) / (this.maxNumPages + this.addition)) * 280;
    }
}

PageTurn.prototype.abortDownloader = function()
{
    this.downloader.abort();
}

PageTurn.prototype.downloadCompleted = function(sender, args)
{   
    var progressText = this.plugIn.content.findName("loadingText");
    progressText.text = "loading... " + Math.round((((this.currentDownload) / (this.maxNumPages + this.addition)) * 100)).toString() + "% completed";
    var progressRect = this.plugIn.content.findName("loadingBar");
    progressRect.width = ((this.currentDownload) / (this.maxNumPages + this.addition)) * 280;
    
    this.currentDownload++;
    
    if (this.currentDownload < this.pageGenerator.resourceArray.length)
    {
        this.downloader.open("GET", this.pageGenerator.resourceArray[this.currentDownload]);
        this.downloader.send();
    }
    else
    {
        var progressText = this.plugIn.content.findName("loadingText");
        progressText.text = "loading completed... opening book";
        var progressRect = this.plugIn.content.findName("loadingBar");
        progressRect.width = 280;

        // add pages and thumbnails
        this.addEvenPages();
        this.addOddPages();
        // initialize dragging elements
        if(this.spread == -1)
        {
        this.navigationManager.beginPageAnimation("showFold");
        this.navigationManager.jumpToPage(this.spread);
        }
    }
}

//create and add the pages on the left hand side of the book
PageTurn.prototype.addOddPages = function()
{
    //this is the template for all odd pages
    var oddStr =      "<Canvas x:Name='page0$0' xmlns='http://schemas.microsoft.com/client/2007' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>";
//    oddStr = oddStr + "        MouseLeftButtonDown='oddPageMouseDown' MouseLeftButtonUp='oddPageMouseUp' MouseMove='oddPageMouseMove'>";
    oddStr = oddStr + "  <Canvas.RenderTransform>";
    oddStr = oddStr + "    <TransformGroup>";
    oddStr = oddStr + "      <RotateTransform x:Name='page$0Rotate' CenterX='0' CenterY='570' Angle='0'/>";
    oddStr = oddStr + "      <TranslateTransform x:Name='page$0Translate' X='0' Y='0'/>";
    oddStr = oddStr + "    </TransformGroup>";
    oddStr = oddStr + "  </Canvas.RenderTransform>";
    oddStr = oddStr + "  <Canvas.Clip>";
    oddStr = oddStr + "    <PathGeometry>";
    oddStr = oddStr + "      <PathFigure>";
    oddStr = oddStr + "        <LineSegment Point='0,570'/>";
    oddStr = oddStr + "        <LineSegment x:Name='page$0Point1' Point='0, 570'/>";
    oddStr = oddStr + "        <LineSegment x:Name='page$0Point2' Point='0, 570'/>";
    oddStr = oddStr + "        <LineSegment x:Name='page$0Point3' Point='0, 570'/>";
    oddStr = oddStr + "        <LineSegment Point='0,570'/>";
    oddStr = oddStr + "      </PathFigure>";
    oddStr = oddStr + "    </PathGeometry>";
    oddStr = oddStr + "  </Canvas.Clip>";
    oddStr = oddStr + "  $1";
    //oddStr = oddStr + "  <InkPresenter x:Name='page$0ip' Width='420' Height='570' Canvas.Left='0' Canvas.Top='0' />";
    oddStr = oddStr + "  <Rectangle Height='1000' Width='20' Opacity='0.6' x:Name='page$0FoldShadow'>";
    oddStr = oddStr + "    <Rectangle.RenderTransform>";
    oddStr = oddStr + "      <TransformGroup>";
    oddStr = oddStr + "        <RotateTransform x:Name='page$0FoldShadowRotate' CenterX='0' CenterY='0' Angle='0'/>";
    oddStr = oddStr + "        <TranslateTransform x:Name='page$0FoldShadowTranslate' X='0' Y='0'/>";
    oddStr = oddStr + "      </TransformGroup>";
    oddStr = oddStr + "    </Rectangle.RenderTransform>";
    oddStr = oddStr + "    <Rectangle.Fill>";
    oddStr = oddStr + "      <LinearGradientBrush StartPoint='0,0' EndPoint='1,0'>";
    oddStr = oddStr + "        <GradientStop Color='#00000000' Offset='0'/>";
    oddStr = oddStr + "        <GradientStop Color='#FF000000' Offset='1'/>";
    oddStr = oddStr + "      </LinearGradientBrush>";
    oddStr = oddStr + "    </Rectangle.Fill>";
    oddStr = oddStr + "  </Rectangle>";
    oddStr = oddStr + "</Canvas>";

    // if maxNumPages is odd, we will ignore the last page, so last odd is two behind
    var _lastOdd;
    if (((this.maxNumPages/2) - Math.floor(this.maxNumPages/2)) == 0)
      _lastOdd = this.maxNumPages - 1;
    else
      _lastOdd = this.maxNumPages - 2;

    for (var i=1; i<=_lastOdd; i = i+2)
    {
    
      // $0: two digit index of this page
      var newOddPageStr = oddStr.replace(/\$0/g, getTwoDigitInt(i));
      newOddPageStr = newOddPageStr.replace(/\$1/g, this.pageGenerator.getPageString(i));
      var newOddPage = this.plugIn.content.createFromXaml(newOddPageStr);
      if(this.arrayOfOddPages.length == 0)
      {
        this.arrayOfOddPages[0] = newOddPage;
        }
        else{
        this.arrayOfOddPages[(this.arrayOfOddPages.length)] = newOddPage;//alert(this.arrayOfOddPages[(this.arrayOfOddPages.length - 1)]) ;
        }
        
      // hook up event handlers for the odd pages
      newOddPage.addEventListener("mouseLeftButtonDown", Silverlight.createDelegate(this.navigationManager, this.navigationManager.oddPageMouseDown));
      newOddPage.addEventListener("mouseLeftButtonUp", Silverlight.createDelegate(this.navigationManager, this.navigationManager.oddPageMouseUp));
      newOddPage.addEventListener("mouseMove", Silverlight.createDelegate(this.navigationManager, this.navigationManager.oddPageMouseMove));
      
      if(this.spread == -1) //load from the cover or p1
      {
          // add this odd page to the scene
          if(i <= 7)
          {
            this.plugIn.content.findName("oddPageCanvas").children.add(newOddPage);
          }
      }
    }
        
    this.plugIn.content.findName("bookLoadedStoryboard").Begin();
    //then hide the loader
    //this.plugIn.content.findName("loadingHolder")["Visibility"] = "Collapsed";
}

//create and add the pages on the right hand side of the book
PageTurn.prototype.addEvenPages = function()
{ 
    //this is the template for all even pages
    var evenStr =    "<Canvas x:Name='page0$0' xmlns='http://schemas.microsoft.com/client/2007' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>";
    evenStr = evenStr + "  <Canvas.Clip>";
    evenStr = evenStr + "    <PathGeometry>";
    evenStr = evenStr + "      <PathFigure>";
    evenStr = evenStr + "        <LineSegment Point='0,0'/>";
    evenStr = evenStr + "        <LineSegment Point='0, 570'/>";
    evenStr = evenStr + "        <LineSegment x:Name='page$0Point1' Point='420, 570'/>";
    evenStr = evenStr + "        <LineSegment x:Name='page$0Point2' Point='420, 570'/>";
    evenStr = evenStr + "        <LineSegment x:Name='page$0Point3' Point='420, 0'/>";
    evenStr = evenStr + "        <LineSegment Point='0,0'/>";
    evenStr = evenStr + "      </PathFigure>";
    evenStr = evenStr + "    </PathGeometry>";
    evenStr = evenStr + "  </Canvas.Clip>";
    //evenStr = evenStr + "  <Image Source='assets/page$0.jpg'/>";
    evenStr = evenStr + "  $1";
    //evenStr = evenStr + "  <InkPresenter x:Name='page$0ip' Width='420' Height='570' Canvas.Left='0' Canvas.Top='0'/>";
    evenStr = evenStr + "  $2";
    evenStr = evenStr + "</Canvas>";
    
    var foldShadowStr = "  <Rectangle Height='570' Width='30' Opacity='0.2'>";
    foldShadowStr +=    "    <Rectangle.Fill>";
    foldShadowStr +=    "      <LinearGradientBrush StartPoint='0,0' EndPoint='1,0'>";
    foldShadowStr +=    "        <GradientStop Color='#BBFFFFFF' Offset='0'/>";
    foldShadowStr +=    "        <GradientStop Color='#00FFFFFF' Offset='1'/>";
    foldShadowStr +=    "      </LinearGradientBrush>";
    foldShadowStr +=    "    </Rectangle.Fill>";
    foldShadowStr +=    "  </Rectangle>";

    // if maxNumPages is odd, we will ignore the last page, so last odd is two behind
    var _lastEven;
    if (((this.maxNumPages/2) - Math.floor(this.maxNumPages/2)) == 0)
      _lastEven = this.maxNumPages;
    else
      _lastEven = this.maxNumPages - 1;

    for (var i=_lastEven; i>=0; i = i-2)
    {
      // $0: index of this page
      var newEvenPageStr = evenStr.replace(/\$0/g, getTwoDigitInt(i));
      newEvenPageStr = newEvenPageStr.replace(/\$1/g, this.pageGenerator.getPageString(i));
      if (i == 0)
        newEvenPageStr = newEvenPageStr.replace(/\$2/g, "");
      else
        newEvenPageStr = newEvenPageStr.replace(/\$2/g, foldShadowStr);
        
      var newEvenPage = this.plugIn.content.createFromXaml(newEvenPageStr);
        if(this.arrayOfEvenPages.length == 0)
        this.arrayOfEvenPages[0] = newEvenPage;
        else
        this.arrayOfEvenPages[this.arrayOfEvenPages.length] = newEvenPage;
        
      newEvenPage.addEventListener("mouseLeftButtonDown", Silverlight.createDelegate(this.navigationManager, this.navigationManager.evenPageMouseDown));
      newEvenPage.addEventListener("mouseLeftButtonUp", Silverlight.createDelegate(this.navigationManager, this.navigationManager.evenPageMouseUp));
      newEvenPage.addEventListener("mouseMove", Silverlight.createDelegate(this.navigationManager, this.navigationManager.evenPageMouseMove));
      
      if(this.spread == -1) //load from the cover or p1
      {
          // add this odd page to the scene
          if(i <= 7)
          {
          this.plugIn.content.findName("evenPageCanvas").children.add(newEvenPage);
          }
      }
      
      }
      this.arrayOfEvenPages.reverse();
}
      