var pageVerts, bookVerts
var dragTimerID
var cornervisible = 0
var pagepos = 0;
var mousePos
var currentMousePos
var pageLeftPath
var Images = new Array()
var gradientImages = new Array()
var autoturn = 0
var skiphistory = false
var orientation = 0
var dragMode = 0
var currentPagePos
var mouseClickOffset
var enumCatalogueState = { loading: 0, ready: 1, busy: 3 }
var catalogueState = enumCatalogueState['loading']
var ox = (pageWidth - 1) / Math.sin(degrees * Math.PI / 180)
var oy = ox * Math.cos(degrees * Math.PI / 180)

function setOrientation(dir, v) {
  //Flips all objects within book area
  //Polygon textures have to be swapped when this happens so no visible change occurs
  //on the screen

  orientation = dir
  switch (renderMode) {
    case enumRenderMode['vml']:
      document.getElementById('VMLPageImageLeft').src = Images[2 + dir].src
      document.getElementById('VMLPageRightImageFill').src = Images[3 - dir].src
      document.getElementById('VMLnextPageRightImageFill').src = Images[(1 - dir) * 4 + (1 - dir)].src
      document.getElementById('VMLnextPageLeftImage').src = Images[(1 - dir) * 4 + dir].src
      document.getElementById('VMLPageLeftGradientFill').src = formatString(gradientUrlFormat, catalogueID, Number(dir))
      document.getElementById('VMLPageRightGradientFill').src = formatString(gradientUrlFormat, catalogueID, Number(!dir))

      document.getElementById('VMLPageImageLeft').style.flip = (dir == 0 ? '' : 'x')
      document.getElementById('VMLnextPageLeftImage').style.flip = (dir == 0 ? '' : 'x')
      document.getElementById('saucer').style.flip = (dir == 0 ? '' : 'x')

      document.getElementById('VMLPageRightImageFill').position = (dir == 0 ? '0,1' : '1,1')
      document.getElementById('VMLnextPageRightImageFill').position = (dir == 0 ? '1,1' : '0,1')
      document.getElementById('VMLPageRightGradientFill').position = (dir == 0 ? '0,1' : '1,1')

      document.getElementById('VMLPageRightGradient').coordorigin = (dir == 0 ? '1 1' : '-1 1')
      document.getElementById('VMLPageLeftGradient').coordorigin = (dir == 0 ? '1 1' : '-1 1')

      document.getElementById('VMLPageImageRight').coordorigin = (dir == 0 ? '1 1' : '-1 1')
      document.getElementById('VMLnextPageRightImage').coordorigin = (dir == 0 ? '1 1' : '-1 1')
      document.getElementById('VMLShadow').coordorigin = (dir == 0 ? '1 1' : '-1 1')
      document.getElementById('VMLTopMask').coordorigin = (dir == 0 ? '1 ' : '-1 ') + (-topspace * 2 + 1)

      if (dir == 0) {
        //forwards

        if (bookmode == 1) {
          if (currentpage == 0) {
            document.getElementById('VMLPageImageLeft').style.visibility = 'hidden'
            document.getElementById('VMLPageLeftGradient').style.visibility = 'hidden'
          } else {
            document.getElementById('VMLPageImageLeft').style.visibility = 'visible'
            document.getElementById('VMLPageLeftGradient').style.visibility = 'visible'
          }
          if (currentpage == pageCount - 2)
            document.getElementById('VMLnextPageRightImageFill').type = 'solid'
          else
            document.getElementById('VMLnextPageRightImageFill').type = 'tile'

          if (currentpage == pageCount)
            document.getElementById('VMLPageImageRight').style.visibility = 'hidden'
          else
            document.getElementById('VMLPageImageRight').style.visibility = 'visible'
        }

      } else {
        //backwards

        if (bookmode == 1) {
          if (currentpage == pageCount) {
            document.getElementById('VMLPageImageLeft').style.visibility = 'hidden'
            document.getElementById('VMLPageLeftGradient').style.visibility = 'hidden'
          } else {
            document.getElementById('VMLPageImageLeft').style.visibility = 'visible'
            document.getElementById('VMLPageLeftGradient').style.visibility = 'visible'
          }

          if (currentpage == 2)
            document.getElementById('VMLnextPageRightImageFill').type = 'solid'
          else
            document.getElementById('VMLnextPageRightImageFill').type = 'tile'

          if (currentpage == 0) {
            document.getElementById('VMLPageImageRight').style.visibility = 'hidden'
            document.getElementById('VMLPageRightGradient').style.visibility = 'hidden'
          } else {
            document.getElementById('VMLPageImageRight').style.visibility = 'visible'
            document.getElementById('VMLPageRightGradient').style.visibility = 'visible'
          }
        }
      }
      break;
    case enumRenderMode['svg']:

      document.getElementById('svgsaucer').setAttribute('transform', (dir == 0 ? '' : 'translate(' + 2 * pageWidth + ',0) scale(-1,1)'))

      document.getElementById('SVGPageImageLeft').setAttributeNS('http://www.w3.org/1999/xlink', 'href', Images[2 + dir].src)
      document.getElementById('SVGPageImageRight').setAttributeNS('http://www.w3.org/1999/xlink', 'href', Images[3 - dir].src)
      document.getElementById('SVGnextPageLeftImage').setAttributeNS('http://www.w3.org/1999/xlink', 'href', Images[(1 - dir) * 4 + dir].src)
      document.getElementById('SVGnextPageRightImage').setAttributeNS('http://www.w3.org/1999/xlink', 'href', Images[(1 - dir) * 4 + (1 - dir)].src)//

      document.getElementById('SVGPageRightGradient').setAttributeNS('http://www.w3.org/1999/xlink', 'href', gradientImages[Number(!dir)].src)
      document.getElementById('SVGPageLeftGradient').setAttributeNS('http://www.w3.org/1999/xlink', 'href', gradientImages[dir].src)


      document.getElementById('SVGPageImageLeft').setAttribute('transform', (dir == 0 ? '' : 'translate(' + pageWidth + ',0) scale(-1,1)'))
      document.getElementById('SVGPageImageRight').setAttribute('transform', (dir == 0 ? '' : 'translate(' + pageWidth * 3 + ',0) scale(-1,1)'))
      document.getElementById('SVGnextPageRightImage').setAttribute('transform', (dir == 0 ? '' : 'translate(' + pageWidth * 3 + ',0) scale(-1,1)'))

      document.getElementById('SVGPageRightGradient').setAttribute('transform', (dir == 0 ? '' : 'translate(' + (pageWidth * 2 + gradientWidth) + ',0) scale(-1,1)'))
      document.getElementById('SVGPageLeftGradient').setAttribute('transform', (dir == 0 ? '' : 'translate(' + (pageWidth * 2 - gradientWidth) + ',0) scale(-1,1)'))

      document.getElementById('SVGPageImageRightPoly').setAttribute('transform', (dir == 0 ? '' : 'translate(' + pageWidth * 3 + ',0) scale(-1,1)'))
      document.getElementById('SVGnextPageRightImagePoly').setAttribute('transform', (dir == 0 ? '' : 'translate(' + pageWidth * 3 + ',0) scale(-1,1)'))
      document.getElementById('SVGNoNextPageRightImage').setAttribute('transform', (dir == 0 ? '' : 'translate(' + pageWidth * 3 + ',0) scale(-1,1)'))
      document.getElementById('SVGTopMaskPoly').setAttribute('transform', (dir == 0 ? '' : 'translate(' + pageWidth * 2 + ',0) scale(-1,1)'))
      document.getElementById('SVGPageRightGradientPoly').setAttribute('transform', (dir == 0 ? '' : 'translate(' + (pageWidth * 2 + gradientWidth) + ',0) scale(-1,1)'))

      if (dir == 0) {
        //forwards

        if (bookmode == 1) {
          if (currentpage == 0) {
            document.getElementById('SVGPageImageLeft').style.visibility = 'hidden'
            document.getElementById('SVGPageLeftGradient').style.visibility = 'hidden'
          } else {
            document.getElementById('SVGPageImageLeft').style.visibility = 'visible'
            document.getElementById('SVGPageLeftGradient').style.visibility = 'visible'
          }
          if (currentpage == pageCount - 2) {
            document.getElementById('SVGnextPageRightImage').style.visibility = 'hidden'
            document.getElementById('SVGNoNextPageRightImage').style.visibility = 'visible'
          } else {
            document.getElementById('SVGnextPageRightImage').style.visibility = 'visible'
            document.getElementById('SVGNoNextPageRightImage').style.visibility = 'hidden'
          }

          if (currentpage == pageCount)
            document.getElementById('SVGPageImageRight').style.visibility = 'hidden'
          else
            document.getElementById('SVGPageImageRight').style.visibility = 'visible'
        }

      } else {
        //backwards

        if (bookmode == 1) {
          if (currentpage == pageCount) {
            document.getElementById('SVGPageImageLeft').style.visibility = 'hidden'
            document.getElementById('SVGPageLeftGradient').style.visibility = 'hidden'
          } else {
            document.getElementById('SVGPageImageLeft').style.visibility = 'visible'
            document.getElementById('SVGPageLeftGradient').style.visibility = 'visible'
          }
          if (currentpage == 2) {
            document.getElementById('SVGNoNextPageRightImage').style.visibility = 'visible'
            document.getElementById('SVGnextPageRightImage').style.visibility = 'hidden'
          } else {
            document.getElementById('SVGNoNextPageRightImage').style.visibility = 'hidden'
            document.getElementById('SVGnextPageRightImage').style.visibility = 'visible'
          }

          if (currentpage == 0) {
            document.getElementById('SVGPageImageRight').style.visibility = 'hidden'
            document.getElementById('SVGPageRightGradient').style.visibility = 'hidden'
          } else {
            document.getElementById('SVGPageImageRight').style.visibility = 'visible'
            document.getElementById('SVGPageRightGradient').style.visibility = 'visible'
          }
        }
      }
      break;
    case enumRenderMode['basic']:
      document.getElementById('BasicPageImageLeft').src = Images[2].src
      document.getElementById('BasicPageImageRight').src = Images[3].src
      if (currentpage == 0) {
        document.getElementById('BasicPageImageLeft').style.visibility = 'hidden'
      } else {
        document.getElementById('BasicPageImageLeft').style.visibility = 'visible'
      }

      if (currentpage == pageCount) {
        document.getElementById('BasicPageImageRight').style.visibility = 'hidden'
      } else {
        document.getElementById('BasicPageImageRight').style.visibility = 'visible'
      }

      break;
  }
}

function addPageHistory(n) {
  //Checkpoints the book's state by changing the contents of a hidden iframe
  //This allows forwards and back buttons to work
  if (skiphistory) { skiphistory = false; return }

  try {
    var iframe = document.getElementById('historytracker')
    iframe.contentWindow.document.open()
    if (browser.browser == 'Opera') {
      iframe.contentWindow.document.write('<script>function x(){parent.historyChanged()}</script>')
      iframe.contentWindow.document.write('<img src="javascript:location.href=\'javascript:x();\';" alt="" style="position:absolute;left:-1px;top:-1px;opacity:0;width:0px;height:0px;">')
    }

    iframe.contentWindow.document.write('<div id="lastpage">' + n + '</div>')
    iframe.contentWindow.document.close()
  } catch (e) {
    return
  }
}

function currentImageLoaded() {

  if (Images[2].reallycomplete && Images[3].reallycomplete) {

    if (autoturn != 0) {
      for (var i = 0; i < Images.length; i++)
        if (!Images[i].reallycomplete)
          return
      catalogueState = enumCatalogueState['ready']
      if (autoturn == 1) pageNext_buttonclick()
      if (autoturn == -1) pagePrev_buttonclick()

    } else {
      switch (renderMode) {
        case enumRenderMode['vml']:
          document.getElementById('VMLPageImageLeft').src = Images[2].src
          document.getElementById('VMLPageRightImageFill').src = Images[3].src
          break;
        case enumRenderMode['svg']:
          document.getElementById('SVGPageImageLeft').setAttributeNS('http://www.w3.org/1999/xlink', 'href', Images[2].src)
          document.getElementById('SVGPageImageRight').setAttributeNS('http://www.w3.org/1999/xlink', 'href', Images[3].src)
          break;
        case enumRenderMode['basic']:
          document.getElementById('BasicPageImageLeft').src = Images[2].src
          document.getElementById('BasicPageImageRight').src = Images[3].src
          break;
      }
    }
  }
}

function nextImageLoaded() {

  var dir = Number((this == Images[4]) || (this == Images[5]))

  if (Images[dir * 4].reallycomplete && Images[dir * 4 + 1].reallycomplete) {

    if (catalogueState == enumCatalogueState['busy']) catalogueState = enumCatalogueState['ready']

    if (autoturn == 0)
      pageMouseMove(null, true)

    if (dir != orientation) {
      switch (renderMode) {
        case enumRenderMode['vml']:
          document.getElementById('VMLnextPageLeftImage').src = Images[dir * 4 + (1 - dir)].src
          document.getElementById('VMLnextPageRightImageFill').src = Images[dir * 4 + dir].src

          break;
        case enumRenderMode['svg']:
          document.getElementById('SVGnextPageLeftImage').setAttributeNS('http://www.w3.org/1999/xlink', 'href', Images[dir * 4 + (1 - dir)].src)
          document.getElementById('SVGnextPageRightImage').setAttributeNS('http://www.w3.org/1999/xlink', 'href', Images[dir * 4 + dir].src)//
          break;
      }
      setPageTurnedPos(0)
    }

    if (autoturn != 0) {
      for (var i = 0; i < Images.length; i++)
        if (!Images[i].reallycomplete)
          return

      if (autoturn == 1) pageNext_buttonclick()
      if (autoturn == -1) pagePrev_buttonclick()
    }

  }

}


function ImageLoaded() {
  //complete is set to true after the onload event fires, therefore
  //must define our own complete flag

  this.reallycomplete = true

  if ((this == Images[2]) || (this == Images[3]))
    currentImageLoaded.call(this)
  else if (this == Images[0] || this == Images[1] || this == Images[4] || this == Images[5])
    nextImageLoaded.call(this)

  for (var i = 0; i < Images.length; i++)
    if (!Images[i].reallycomplete)
      return

  if (renderMode == enumRenderMode['svg'])
    for (var i = 0; i < gradientImages.length; i++)
      if (!gradientImages[i].reallycomplete)
        return

  if (catalogueState == enumCatalogueState['loading']) {
    initComplete()
  }
}

function loadImages(imagesToLoad) {
  //Given array of number (images to load) it loads
  //the images into an array. This is to preload images
  for (var i = 0; i < imagesToLoad.length; i++)
    Images[imagesToLoad[i]] = new Image()

  for (var i = 0; i < imagesToLoad.length; i++) {
    var pageNo

    if (bookmode == 0)
      pageNo = ((currentpage - 3 + imagesToLoad[i] + pageCount) % pageCount) + 1
    else
      pageNo = currentpage - 2 + imagesToLoad[i]

    if (pageNo > 0 && pageNo <= pageCount) {
      Images[imagesToLoad[i]].onload = ImageLoaded
      var ImagePageNo = PageLeadingZeroes(pageNo);
      Images[imagesToLoad[i]].src = formatString(imageUrlFormat, catalogueID, 0, ImagePageNo)
    } else
      ImageLoaded.call(Images[imagesToLoad[i]])
  }
}

function vmlPageLoad() {
  //sets up vml offscreen buffer and sets up window resize event to keep image above book in place

  //Even though, due to the html markup, filled already has a value or 1, norton antivirus will prevent the whole site from working unless
  //this is set.

  document.getElementById('VMLTopMask').Filled = 1;

  document.getElementById('VMLTopMaskFill').src = cleanURL(getCurrentStyle(document.getElementById('topspace')).backgroundImage)

  var i = elementPos(document.getElementById('container'))[0] - elementPos(document.getElementById('topspace'))[0]

  document.getElementById('VMLTopMaskFill').origin = ((1 + ((i - .5) / navWidth)) % 1) + ', ' + (1 - (.5 / navHeight))

  try {
    document.execCommand("BackgroundImageCache", false, true)
  } catch (e) { /*no problem*/ }


}

function svgPageLoad() {

  document.getElementById('SVGTopMask').setAttributeNS('http://www.w3.org/1999/xlink', 'href', cleanURL(getCurrentStyle(document.getElementById('topspace')).backgroundImage))
  var i = elementPos(document.getElementById('container'))[0] - elementPos(document.getElementById('topspace'))[0]

  document.getElementById('SVGTopMask').setAttribute('x', -i)

  //This prevents firefox from trying to center something with an even width, in an odd number of pixels
  if (window.addEventListener && document.createEvent && window.dispatchEvent) {
    window.addEventListener('resize', function () { document.documentElement.style.paddingRight = (document.documentElement.clientWidth & 1) ? '1px' : '0px' }, false)
    var evt = document.createEvent("HTMLEvents")
    evt.initEvent("resize", true, false)
    window.dispatchEvent(evt)
  }

  //Preload gradients - Required for firefox 3 to prevent flicker

  for (var i = 0; i < 2; i++)
    gradientImages[i] = new Image()

  for (var i = 0; i < 2; i++) {
    gradientImages[i].onload = ImageLoaded
    gradientImages[i].src = formatString(gradientUrlFormat, catalogueID, i) //calculate this first, otherwise firefox flickers
  }


}

function basicPageLoad() {
  //nothing to do here
}

function pageload() {

  bookVerts = new Object()

  bookVerts.topSpaceLeft = [0, -topspace]
  bookVerts.topSpaceRight = [bookWidth, -topspace]
  bookVerts.topLeft = [0, 0]
  bookVerts.topRight = [bookWidth, 0]
  bookVerts.bottomLeft = [0, bookheight]
  bookVerts.bottomRight = [bookWidth, bookheight]
  bookVerts.topMid = [pageWidth, 0]
  bookVerts.bottomMid = [pageWidth, bookheight]


  if (renderMode == enumRenderMode['vml'])
    vmlPageLoad()
  else if (renderMode == enumRenderMode['svg'])
    svgPageLoad()
  else if (renderMode == enumRenderMode['basic']) {
    basicPageLoad()
  }

  currentpage -= bookmode

  setPageTurnedPos(0)

  loadImages([0, 1, 2, 3, 4, 5])

//  initHotspots()

  if (browser.browser == 'IE') addPageHistory(currentpage)  //Internet explorer cannot go back to an empty document
  //but other browsers do
}

function initComplete() {
  setOrientation(orientation)

  if (renderMode == enumRenderMode['vml'])
    document.getElementById('VMLbookdiv').style.display = 'block'
  else if (renderMode == enumRenderMode['svg'])
    document.getElementById('svgelement').style.display = 'block'

  animate('LoadingFadeOut', 100, 0, 300,
                function (n) {
                  document.getElementById('loadingsplash').style.opacity = n / 100;
                  document.getElementById('loadingsplash').style.filter = 'alpha(opacity=' + n + ')'
                }, function () { document.getElementById('loadingsplash').style.display = 'none' }, true)

  catalogueState = enumCatalogueState['ready']

}

function retreatPage() {
  Images[5] = Images[3]
  Images[4] = Images[2]
  Images[3] = Images[1]
  Images[2] = Images[0]
  currentpage = (currentpage - 3) % pageCount + 1  //allows book to wrap round
  setOrientation(currentpage == 0 ? 0 : 1)
  setPageTurnedPos(0)
  addPageHistory(currentpage)
  loadImages([0, 1])
}


function advancePage() {
  document.getElementById('instructions').style.display = 'none'
  Images[0] = Images[2]
  Images[1] = Images[3]
  Images[2] = Images[4]
  Images[3] = Images[5]
  currentpage = (currentpage + 1) % pageCount + 1  //allows book to wrap round
  setOrientation(currentpage == pageCount ? 1 : 0)
  setPageTurnedPos(0)
  addPageHistory(currentpage)
  loadImages([4, 5])
}

function pageNext_buttonclick() {
  if (catalogueState != enumCatalogueState['ready']) return
  autoturn = 0
  if (orientation != 0) setOrientation(0)
  if ((bookmode == 1) && (currentpage + 2 > pageCount)) return
  catalogueState = enumCatalogueState['busy']
  if (renderMode == enumRenderMode['basic']) {
    advancePage();
  } else
    animate('PageAnimation', pagepos, 100, pageTurnTime, function (n) { setPageTurnedPos(n) }, advancePage, false)
  return false;
}

function pagePrev_buttonclick() {

  if (catalogueState != enumCatalogueState['ready']) return
  autoturn = 0
  if ((bookmode == 1) && (currentpage - 2 < 0)) return
  if (orientation != 1) setOrientation(1)
  catalogueState = enumCatalogueState['busy']
  if (renderMode == enumRenderMode['basic']) {
    retreatPage();
  } else
    animate('PageAnimation', pagepos, 100, pageTurnTime, function (n) { setPageTurnedPos(n) }, retreatPage, false)
}


function setPageTurnedPos(n) {
  if (n > 100) { n = 100 }
  pagepos = n

  x = ox * Math.sin((n / 100 - 0.5) * degrees * Math.PI / 90) + pageWidth
  y = ox * Math.cos((n / 100 - 0.5) * degrees * Math.PI / 90) - oy

  var nextimgx = 2 * pageWidth - x - 1
  var nextimgy = bookheight - y - 1

  if (orientation == 1) nextimgx = bookWidth - nextimgx

  setPageTurned(nextimgx, nextimgy)
}


function setPageTurned(nextimgx, nextimgy) {

  nextimgx = Math.round(nextimgx)
  nextimgy = Math.round(nextimgy)

  pageVerts = new Object()

  if (orientation == 1) nextimgx = bookWidth - nextimgx

  var pageAngle = 2 * calcAngle(nextimgx, nextimgy, bookWidth, bookheight) - 3 * Math.PI // this angle ensures a line of symmetry

  //constrain page so that is doesn't 'tear off'

  if (Math.sqrt(Math.pow(nextimgx - pageWidth, 2) + Math.pow(nextimgy - bookheight, 2)) > pageWidth) {
    var n = calcAngle(pageWidth, bookheight, nextimgx, nextimgy) - Math.PI / 2
    pageAngle = 2 * calcAngle(pageWidth - pageWidth * Math.cos(n), bookheight - pageWidth * Math.sin(n), bookWidth, bookheight) - 3 * Math.PI
    nextimgx = pageWidth - pageWidth * Math.cos(n)
    nextimgy = bookheight - pageWidth * Math.sin(n)
  }

  if (nextimgx + bookheight * Math.sin(pageAngle) < bookWidth && Math.sqrt(Math.pow(nextimgx - pageWidth + bookheight * Math.sin(pageAngle), 2) + Math.pow(nextimgy - bookheight * Math.cos(pageAngle), 2)) > pageWidth) {
    var n = calcAngle(nextimgx + bookheight * Math.sin(pageAngle), nextimgy - bookheight * Math.cos(pageAngle), pageWidth, 0)
    pageAngle = 2 * calcAngle(pageWidth + pageWidth * Math.sin(n), -pageWidth * Math.cos(n), bookWidth, 0) - 3 * Math.PI

    if (pageAngle / 2 + Math.PI < calcAngle(bookVerts.bottomRight[0], bookVerts.bottomRight[1], bookVerts.topMid[0], bookVerts.topMid[1])) {
      pageAngle = (calcAngle(bookVerts.bottomRight[0], bookVerts.bottomRight[1], bookVerts.topMid[0], bookVerts.topMid[1]) - Math.PI) * 2
      n = pageAngle + 3 * Math.PI / 2 + .0001 //Seems to be a slight error (precision?) in calculations but this is on the safe side
    }

    nextimgx = pageWidth + pageWidth * Math.sin(n) - bookheight * Math.sin(pageAngle)
    nextimgy = -pageWidth * Math.cos(n) + bookheight * Math.cos(pageAngle)
  }

  pageVerts.bottomLeft = [nextimgx, nextimgy]
  pageVerts.bottomRight = [nextimgx + pageWidth * Math.cos(pageAngle), nextimgy + pageWidth * Math.sin(pageAngle)]
  pageVerts.topLeft = [nextimgx + bookheight * Math.sin(pageAngle), nextimgy - bookheight * Math.cos(pageAngle)]
  pageVerts.topRight = [nextimgx + bookheight * Math.sin(pageAngle) + pageWidth * Math.cos(pageAngle), nextimgy - bookheight * Math.cos(pageAngle) + pageWidth * Math.sin(pageAngle)]


  var shadowPath = new pathBuilder()
  var maskPath = new pathBuilder()
  var currentPagePath = new pathBuilder()
  var nextPagePath = new pathBuilder()
  pageLeftPath = new pathBuilder()

  var intersectionLeftPageTopBook = lineIntersect(pageVerts.bottomLeft, pageVerts.topLeft, bookVerts.topLeft, bookVerts.topRight)
  var intersectionLeftPageRightBook = lineIntersect(pageVerts.topLeft, pageVerts.bottomLeft, bookVerts.topRight, bookVerts.bottomRight)
  var intersectionTopPageTopBook = lineIntersect(pageVerts.topLeft, pageVerts.topRight, bookVerts.topLeft, bookVerts.topRight)
  var intersectionLeftPageBottomBook = lineIntersect(pageVerts.bottomLeft, pageVerts.topLeft, bookVerts.bottomLeft, bookVerts.bottomRight)
  var intersectionLeftPageMidBook = lineIntersect(pageVerts.bottomLeft, pageVerts.topLeft, bookVerts.bottomMid, bookVerts.topMid)
  var intersectionBottomPageMidBook = lineIntersect(pageVerts.bottomLeft, pageVerts.bottomRight, bookVerts.bottomMid, bookVerts.topMid)
  var intersectionTopPageMidBook = lineIntersect(pageVerts.topLeft, pageVerts.topRight, bookVerts.bottomMid, bookVerts.topMid)
  var intersectionBottomPageTopBook = lineIntersect(pageVerts.bottomLeft, pageVerts.bottomRight, bookVerts.topLeft, bookVerts.topRight)
  var intersectionLeftPageLeftTopSpace = lineIntersect(pageVerts.bottomLeft, pageVerts.topLeft, bookVerts.topLeft, bookVerts.topSpaceLeft)
  //The next 2 are not strictly speaking intersections the whole of the time    
  var intersectionBottomPageBottomBook = [Math.round(bookVerts.bottomRight[0] - Math.sqrt(Math.pow(nextimgx - bookVerts.bottomRight[0], 2) + Math.pow(nextimgy - bookVerts.bottomRight[1], 2)) / 2 / Math.cos(pageAngle / 2)), bookVerts.bottomRight[1]]
  var intersectionTopPageTopBook = [Math.round(bookVerts.bottomRight[0] - Math.sqrt(Math.pow(pageVerts.topLeft[0] - bookVerts.topRight[0], 2) + Math.pow(pageVerts.topLeft[1] - bookVerts.topRight[1], 2)) / 2 / Math.cos(pageAngle / 2)), bookVerts.topRight[1]]

  if (pageVerts.topLeft[0] > bookVerts.topRight[0]) intersectionTopPageTopBook = null

  //next page

  if (intersectionBottomPageBottomBook) {
    nextPagePath.addVert(intersectionBottomPageBottomBook)
    nextPagePath.addVert(bookVerts.bottomRight)
  }
  else {
    nextPagePath.addVert(intersectionLeftPageRightBook)
  }

  if (intersectionTopPageTopBook) {
    nextPagePath.addVert(bookVerts.topRight)
    nextPagePath.addVert(intersectionTopPageTopBook)
  }
  else {
    nextPagePath.addVert(intersectionLeftPageRightBook)
  }

  //current page

  if (intersectionLeftPageRightBook) {
    currentPagePath.addVert(intersectionLeftPageRightBook)
    currentPagePath.addVert(bookVerts.topRight)
  } else if (intersectionLeftPageTopBook)
    currentPagePath.addVert(intersectionLeftPageTopBook)
  else
    currentPagePath.addVert(intersectionTopPageTopBook)


  currentPagePath.addVert(bookVerts.topLeft)
  currentPagePath.addVert(bookVerts.bottomLeft)

  if (intersectionLeftPageBottomBook)
    currentPagePath.addVert(intersectionLeftPageBottomBook)
  else if (intersectionBottomPageBottomBook)
    currentPagePath.addVert(intersectionBottomPageBottomBook)
  else {
    currentPagePath.addVert(intersectionLeftPageRightBook)
    currentPagePath.addVert(bookVerts.bottomRight)
  }

  if (pageAngle > 0)
    currentPagePath.addVert(pageVerts.bottomLeft)
  else
    currentPagePath.addVert(pageVerts.topLeft)

  currentPagePath.points = clipPoly(currentPagePath.points, bookVerts.topMid, bookVerts.bottomRight)

  //top section

  maskPath.addVert(bookVerts.topLeft)
  maskPath.addVert(bookVerts.topSpaceLeft)
  maskPath.addVert(bookVerts.topSpaceRight)

  if (intersectionLeftPageLeftTopSpace)
    maskPath.addVert(intersectionLeftPageLeftTopSpace)
  else {
    maskPath.addVert(bookVerts.topRight)
  }

  if (intersectionTopPageTopBook && pageVerts.topLeft[1] < 0) {
    maskPath.addVert(intersectionTopPageTopBook)
    maskPath.addVert(pageVerts.topLeft)
  }

  if (intersectionLeftPageTopBook)
    maskPath.addVert(intersectionLeftPageTopBook)

  if (intersectionBottomPageTopBook && pageVerts.bottomLeft[1] < 0) {
    maskPath.addVert(pageVerts.bottomLeft)
    maskPath.addVert(intersectionBottomPageTopBook)
  }

  maskPath.points = clipPoly(maskPath.points, bookVerts.topSpaceLeft, bookVerts.topRight)

  //shadow path

  if (intersectionBottomPageBottomBook) {
    shadowPath.addVert(intersectionBottomPageBottomBook)
    shadowPath.addVert([intersectionBottomPageBottomBook[0] + 30, intersectionBottomPageBottomBook[1]])
  }
  else {
    shadowPath.addVert(intersectionLeftPageRightBook)
    shadowPath.addVert([intersectionLeftPageRightBook[0] + 30, intersectionLeftPageRightBook[1]])
  }

  if (intersectionTopPageTopBook) {
    shadowPath.addVert([intersectionTopPageTopBook[0] + 15, intersectionTopPageTopBook[1]])
    shadowPath.addVert(intersectionTopPageTopBook)
  }
  else {
    shadowPath.addVert(intersectionLeftPageRightBook)
  }

  n = 100 * Math.sqrt(Math.pow((pageVerts.bottomLeft[0] + pageVerts.topLeft[0] - bookVerts.bottomRight[0] - bookVerts.topRight[0]) / 2, 2) + Math.pow((pageVerts.bottomLeft[1] + pageVerts.topLeft[1] - bookVerts.bottomRight[1] - bookVerts.topRight[1]) / 2, 2)) / bookWidth

  if (renderMode == enumRenderMode['vml']) {
    document.getElementById('VMLnextPageLeftImage').style.left = Math.floor((nextimgx + pageVerts.topRight[0] - pageWidth) / 2) + 'px'
    document.getElementById('VMLnextPageLeftImage').style.top = Math.floor((nextimgy + pageVerts.topRight[1] - bookheight) / 2) + 'px'
    document.getElementById('VMLnextPageLeftImage').style.rotation = (orientation == 0 ? 1 : -1) * pageAngle * 180 / Math.PI + 'deg'

    ncpx = Math.ceil(Math.sin(pageAngle / 2) * (gradientHeight / 2) - Math.cos(pageAngle / 2) * (gradientWidth / 2) - (gradientWidth / 2) + orientation)
    ncpy = Math.ceil(-Math.cos(pageAngle / 2) * (gradientHeight / 2) - Math.sin(pageAngle / 2) * (gradientWidth / 2) - (gradientHeight / 2))

    document.getElementById('VMLnextPageLeftGradient').style.left = Math.floor(intersectionBottomPageBottomBook[0] + ncpx) + 'px'
    document.getElementById('VMLnextPageLeftGradient').style.top = Math.floor(bookheight + ncpy) + 'px'
    document.getElementById('VMLnextPageLeftGradient').style.rotation = pageAngle * 90 / Math.PI + 'deg';

    if (n > 90)
      document.getElementById('VMLShadowFill').opacity = (100 - n) * shadowopacity / 10
    else
      document.getElementById('VMLShadowFill').opacity = shadowopacity
    document.getElementById('VMLShadow').path = shadowPath
    document.getElementById('VMLnextPageRightImage').path = nextPagePath
    document.getElementById('VMLPageImageRight').path = currentPagePath

    document.getElementById('VMLPageRightImageFill').position.y = (pageAngle < 0 ? 0 : 1)

    if (((currentpage != 2 && orientation == 1) || (currentpage != pageCount - 2 && orientation == 0)) && currentPagePath.points.length > 0) {
      currentPagePath.points[currentPagePath.points.length] = currentPagePath.points[0]
      currentPagePath.points = currentPagePath.points.concat(nextPagePath.points)
      currentPagePath.points[currentPagePath.points.length] = nextPagePath.points[0]
    }

    currentPagePath.points = clipPoly(currentPagePath.points, bookVerts.topMid, [bookVerts.bottomMid[0] + gradientWidth, bookVerts.bottomMid[1]])

    document.getElementById('VMLPageRightGradient').path = currentPagePath
    document.getElementById('VMLTopMask').path = maskPath

    document.getElementById('saucer').style.flip = (orientation == 0 ? '' : 'x')  //This, incredibly prevents flicker

  } else if (renderMode == enumRenderMode['svg']) {
    document.getElementById('SVGnextPageLeftImage').setAttribute('x', Math.round(nextimgx + bookheight * Math.sin(pageAngle)))
    document.getElementById('SVGnextPageLeftImage').setAttribute('y', Math.round(nextimgy - bookheight * Math.cos(pageAngle)))

    if (orientation == 0)
      document.getElementById('SVGnextPageLeftImage').setAttribute('transform', 'rotate(' + pageAngle * 180 / Math.PI + ' ' + Math.round(nextimgx + bookheight * Math.sin(pageAngle)) + ' ' + Math.round(nextimgy - bookheight * Math.cos(pageAngle)) + ')')
    else
      document.getElementById('SVGnextPageLeftImage').setAttribute('transform', 'rotate(' + pageAngle * 180 / Math.PI + ' ' + Math.round(nextimgx + bookheight * Math.sin(pageAngle)) + ' ' + Math.round(nextimgy - bookheight * Math.cos(pageAngle)) + ') translate(' + Math.round(pageWidth + 2 * (nextimgx + bookheight * Math.sin(pageAngle))) + ',0) scale(-1 1)')

    document.getElementById('SVGnextPageLeftGradient').setAttribute('x', Math.round(intersectionBottomPageBottomBook[0] - gradientWidth))
    document.getElementById('SVGnextPageLeftGradient').setAttribute('y', bookheight - gradientHeight)
    document.getElementById('SVGnextPageLeftGradient').setAttribute('transform', 'rotate(' + pageAngle * 90 / Math.PI + ' ' + Math.round(intersectionBottomPageBottomBook[0]) + ' ' + bookheight + ')')

    if (n > 90)
      document.getElementById('SVGShadow').setAttribute('fill-opacity', (100 - n) * shadowopacity / 10)
    else
      document.getElementById('SVGShadow').setAttribute('fill-opacity', shadowopacity)
    document.getElementById('SVGShadow').setAttribute('points', shadowPath)
    document.getElementById('SVGnextPageRightImagePoly').setAttribute('points', nextPagePath)
    document.getElementById('SVGPageImageRightPoly').setAttribute('points', currentPagePath)



    if ((currentpage != 2 && orientation == 1) || (currentpage != pageCount - 2 && orientation == 0)) {
      if (currentPagePath.points.length > 0) {
        currentPagePath.points[currentPagePath.points.length] = currentPagePath.points[0]
        currentPagePath.points = currentPagePath.points.concat(nextPagePath.points)
        currentPagePath.points[currentPagePath.points.length] = nextPagePath.points[0]
      } else {
        currentPagePath = nextPagePath
      }
    }

    document.getElementById('SVGPageRightGradientPoly').setAttribute('points', currentPagePath)
    document.getElementById('SVGTopMaskPoly').setAttribute('points', maskPath)
  }
}

function pageMouseMove(e, reset) {
  if (bookmode == 0 && pageCount < 3) return;
  if (catalogueState != enumCatalogueState['ready']) { return }

  e = window.event || e

  if (e) currentMousePos = cursorPos(e)
  if (!currentMousePos) return

  var pageElementPosition = elementPos(document.getElementById('container'))

  var x = currentMousePos[0] - pageElementPosition[0]
  var y = currentMousePos[1] - pageElementPosition[1]

  if ((x >= 0) && (x < bookWidth) && (y >= 0) && (y < bookheight)) {
    if (x >= pageWidth) {
      //its on the right
      if (currentpage != pageCount && Images[4].reallycomplete && Images[5].reallycomplete) {
        if ((cornervisible != 1) || reset) {
          if (cornervisible == 0) {
            setOrientation(0)
            animate('PageAnimation', pagepos, 10, 200, function (n) { setPageTurnedPos(n) }, function (n) { }, true)
          } else {
            animate('PageAnimation', pagepos, 0, 200, function (n) { setPageTurnedPos(n) }, function (n) { setOrientation(0); animate('PageAnimation', 0, 10, 200, function (n) { setPageTurnedPos(n) }, function (n) { }, true) }, true)
          }
          cornervisible = 1
        }
        return
      }
    } else {
      //its on the left
      if (currentpage != 0 && Images[0].reallycomplete && Images[1].reallycomplete) {
        if ((cornervisible != -1) || reset) {
          if (cornervisible == 0) {
            setOrientation(1)
            animate('PageAnimation', pagepos, 10, 200, function (n) { setPageTurnedPos(n) }, function (n) { }, true)
          } else {
            animate('PageAnimation', pagepos, 0, 200, function (n) { setPageTurnedPos(n) }, function (n) { setOrientation(1); animate('PageAnimation', pagepos, 10, 200, function (n) { setPageTurnedPos(n) }, function (n) { }, true) }, true)
          }
          cornervisible = -1
        }
        return
      }
    }
  }

  if ((cornervisible != 0) || reset) {
    cornervisible = 0
    animate('PageAnimation', pagepos, 0, 200, function (n) { setPageTurnedPos(n) }, function (n) { }, true)
  }
}

function nextpagemousedown(e) {
  if (bookmode == 0 && pageCount < 3) return;
  if (catalogueState != enumCatalogueState['ready']) return

  //if (dragTimerID)
  //    return //drag already initiated, must be second click

  e = e || window.event

  if (e.preventDefault)
    e.preventDefault() //Stop things from being selected

  dragMode = 0

  mousePos = cursorPos(e)

  mouseClickOffset = [mousePos[0] - orientation * bookWidth + ((orientation * 2) - 1) * pageVerts.bottomLeft[0], mousePos[1] - pageVerts.bottomLeft[1] - topspace]

  currentPagePos = [currentMousePos[0] - mouseClickOffset[0], currentMousePos[1] - (mouseClickOffset[1] + topspace)]

  catalogueState = enumCatalogueState['busy']

  dragTimerID = setInterval('updatePagePos()', animinterval)

}

function updatePagePos() {
  if (dragMode == 1) {

    var desiredPos = [currentMousePos[0] - mouseClickOffset[0], currentMousePos[1] - (mouseClickOffset[1] + topspace)]
    currentPagePos = [currentPagePos[0] - (currentPagePos[0] - desiredPos[0]) / 2, currentPagePos[1] - (currentPagePos[1] - desiredPos[1]) / 2]
    setPageTurned(currentPagePos[0], currentPagePos[1])
  }
}


function bodyMouseMove(e) {

  e = e || window.event
  currentMousePos = cursorPos(e)

  if ('PageAnimation' in animationArray) return
  if (mousePos) {
    if (Math.pow(currentMousePos[0] - mousePos[0], 2) + Math.pow(currentMousePos[1] - mousePos[1], 2) > 9) dragMode = 1

    if (browser.browser == 'Firefox' && dragTimerID && dragMode == 1) {
      //firefox 2.0 ignores timers whilst mouse is being moved, so timer can't be used
      updatePagePos()
    }
  }
}

function bodyMouseUp(e) {
  if (!dragTimerID) return

  clearInterval(dragTimerID)

  catalogueState = enumCatalogueState['ready']
  dragTimerID = null
  e = e || window.event

  if (dragMode == 1) {

    var i = (pageVerts.bottomLeft[0] + pageVerts.topLeft[0]) / 2 - pageWidth

    tmpx = orientation * bookWidth - ((orientation * 2) - 1) * pageVerts.bottomLeft[0]
    tmpy = pageVerts.bottomLeft[1]

    if (orientation == 0)
      if (i < 0) // more than halfway
        animate('PageAnimation', 0, 1, 200, function (n) { setPageTurned((1 - n) * tmpx + n * bookVerts.bottomLeft[0], (1 - n) * tmpy + n * bookVerts.bottomLeft[1]) }, advancePage, false)
      else
        animate('PageAnimation', 0, 1, 200, function (n) { setPageTurned((1 - n) * tmpx + n * bookVerts.bottomRight[0], (1 - n) * tmpy + n * bookVerts.bottomRight[1]) }, function () { pagepos = 0; cornervisible = 0; pageMouseMove(null, true) }, false)
    else
      if (i < 0) // more than halfway
        animate('PageAnimation', 0, 1, 200, function (n) { setPageTurned((1 - n) * tmpx + n * bookVerts.bottomRight[0], (1 - n) * tmpy + n * bookVerts.bottomRight[1]) }, retreatPage, false)
      else
        animate('PageAnimation', 0, 1, 200, function (n) { setPageTurned((1 - n) * tmpx + n * bookVerts.bottomLeft[0], (1 - n) * tmpy + n * bookVerts.bottomLeft[1]) }, function () { pagepos = 0; cornervisible = 0; pageMouseMove(null, true) }, false)
  } else {
    if (orientation == 0)
      pageNext_buttonclick()
    else
      pagePrev_buttonclick()
  }
  return false
}


function safariEventCancel(event) {
  //To fix a bug in safari
  event.stopPropagation()
}

function bodyMouseDown(e) {
  e = e || window.event
  if (e.preventDefault)
    e.preventDefault()

  if (browser.browser.toLowerCase().indexOf('safari') != -1) {
    //Bug in safari 3.1. Should be fixed in future versions because I submitted a bug and it
    //appears to have been fixed

    if (document.getElementById('ZoomPanel').style.display == 'block') return;

    var pageElementPosition = elementPos(document.getElementById('container'))
    currentMousePos = cursorPos(e)

    var x = orientation * bookWidth - (orientation * 2 - 1) * (currentMousePos[0] - pageElementPosition[0])
    var y = currentMousePos[1] - pageElementPosition[1]
    document.getElementById('container').removeEventListener('click', safariEventCancel, true)
    if (!ptInRegion([bookVerts.topLeft, bookVerts.topRight, bookVerts.bottomRight, bookVerts.bottomLeft], [x, y])) return;
    if (ptInRegion([bookVerts.topLeft, bookVerts.topMid, bookVerts.bottomMid, bookVerts.bottomLeft], [x, y])) return;
    if (ptInRegion(pointArrayFromString(document.getElementById('SVGPageImageRightPoly').getAttribute('points')), [x, y])) return;

    document.getElementById('container').addEventListener('click', safariEventCancel, true)

    if (ptInRegion(pointArrayFromString(document.getElementById('SVGnextPageRightImagePoly').getAttribute('points')), [x, y])) return;

    nextpagemousedown(e);
  }
}


function gotoPage(n) {
  n = Math.floor(n / 2) * 2
  if (n != currentpage) {
    if ((currentpage == pageCount || n < currentpage) && (bookmode == 1)) {//we'll do a previous page click for this
      catalogueState = enumCatalogueState['busy']
      setOrientation(1)
      currentpage = ((n + 1 + pageCount) % pageCount) + 1

      if (renderMode == enumRenderMode['vml']) {
        if (currentpage == 2)
          document.getElementById('VMLnextPageRightImageFill').type = 'solid'
        else
          document.getElementById('VMLnextPageRightImageFill').type = 'tile'
      } else if (renderMode == enumRenderMode['svg']) {
        if (currentpage == 2) {
          document.getElementById('SVGNoNextPageRightImage').style.visibility = 'visible'
          document.getElementById('SVGnextPageRightImage').style.visibility = 'hidden'
        } else {
          document.getElementById('SVGNoNextPageRightImage').style.visibility = 'hidden'
          document.getElementById('SVGnextPageRightImage').style.visibility = 'visible'
        }
      }

      autoturn = -1
      loadImages([0, 1, 2, 3])
    } else {

      setOrientation(0)
      catalogueState = enumCatalogueState['busy']
      currentpage = ((n - 2 + pageCount) % pageCount)

      if (renderMode == enumRenderMode['vml']) {
        if (currentpage == pageCount - 2)
          document.getElementById('VMLnextPageRightImageFill').type = 'solid'
        else
          document.getElementById('VMLnextPageRightImageFill').type = 'tile'
      } else if (renderMode == enumRenderMode['svg']) {
        if (currentpage == pageCount - 2) {
          document.getElementById('SVGnextPageRightImage').style.visibility = 'hidden'
          document.getElementById('SVGNoNextPageRightImage').style.visibility = 'visible'
        } else {
          document.getElementById('SVGnextPageRightImage').style.visibility = 'visible'
          document.getElementById('SVGNoNextPageRightImage').style.visibility = 'hidden'
        }
      }

      autoturn = 1
      loadImages([2, 3, 4, 5])
    }
  } else {
    skiphistory = false;
  }
}

function historyChanged() {
  if (catalogueState != enumCatalogueState['ready']) { return }

  var iframe = document.getElementById('historytracker')
  var pagediv = iframe.contentWindow.document.getElementById('lastpage')
  if (pagediv) {
    if (parseInt(pagediv.innerHTML) != currentpage) {
      skiphistory = true
      if (('PageAnimation' in animationArray)) delete animationArray['PageAnimation']
      gotoPage(parseInt(pagediv.innerHTML), true)
    }
  } else {
    if (currentpage - Math.floor(currentpage / 2) * 2 != currentpage) {
      skiphistory = true
      if (('PageAnimation' in animationArray)) delete animationArray['PageAnimation']
      gotoPage(currentpage - Math.floor(currentpage / 2) * 2)
    }
  }
}

function toggleCategories() {
  if (document.getElementById('categoriesPanel').style.display == 'block')
    closeCategories()
  else
    openCategories()
}

function openCategories() {
  var categories = document.getElementById('categoriesPanel')
  categories.style.filter = 'alpha(opacity=0)'
  categories.style.opacity = '0'
  categories.style.display = 'block'
  animate('CategoriesFade', 0, 100, 300, function (n) { document.getElementById('categoriesPanel').style.opacity = n / 100; document.getElementById('categoriesPanel').style.filter = 'alpha(opacity=' + n + ')' }, function () { }, true)
  document.getElementById('goto').className = 'navlinks goto gotoselected'
}

function closeCategories() {
  var categories = document.getElementById('categoriesPanel')
  categories.style.display = 'none'
  document.getElementById('goto').className = 'navlinks goto'
}

function highlightShopFromHome() {
  var hlDiv = document.getElementById('shopfromhome')
  var strBackgroundColour = getCurrentStyle(hlDiv).backgroundColor
  var fromRGB = new Array()

  if (strBackgroundColour.substr(0, 3) == 'rgb') {
    matches = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/.exec(strBackgroundColour)
    fromRGB.push(parseInt(matches[1]))
    fromRGB.push(parseInt(matches[2]))
    fromRGB.push(parseInt(matches[3]))
  } else if (strBackgroundColour.charAt(0) == '#') {
    matches = /^#(\w{2})(\w{2})(\w{2})$/.exec(strBackgroundColour)
    fromRGB.push(parseInt(matches[1], 16))
    fromRGB.push(parseInt(matches[2], 16))
    fromRGB.push(parseInt(matches[3], 16))
  } else
    return //unable to parse colour so do nothing

  toRGB = [255, 255, 140] //yellow
  //toRGB = [Math.random()*255,Math.random()*255,Math.random()*255] //yellow

  animate('ShopFromHomeHighLight', 0, 1, 2000, function (n) {
    var pos = Math.abs((n - Math.floor(n)) * 2 - 1)
    var currRGB = new Array()
    currRGB = [Math.round(pos * fromRGB[0] + (1 - pos) * toRGB[0]),
                Math.round(pos * fromRGB[1] + (1 - pos) * toRGB[1]),
                Math.round(pos * fromRGB[2] + (1 - pos) * toRGB[2])]

    document.getElementById('shopfromhome').style.backgroundColor = 'rgb(' + currRGB + ')'
  }, function () { }, false)

}


