import _ from 'lodash'
/* eslint-disable
    node/handle-callback-err,
    max-len,
    new-cap,
    no-return-assign,
    no-sequences,
    no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
 * decaffeinate suggestions:
 * DS101: Remove unnecessary use of Array.from
 * DS102: Remove unnecessary code created because of implicit returns
 * DS103: Rewrite code to no longer use __guard__
 * DS104: Avoid inline assignments
 * DS207: Consider shorter variations of null checks
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 */
import App from '../../../base'
import { captureMessage } from '../../../infrastructure/error-reporter'
import pdfTextLayer from './pdfTextLayer'
import pdfAnnotations from './pdfAnnotations'
import pdfHighlights from './pdfHighlights'
import pdfRenderer from './pdfRenderer'
import pdfPage from './pdfPage'
import pdfSpinner from './pdfSpinner'
App.controller('pdfViewerController', function(
  $scope,
  $q,
  $timeout,
  PDFRenderer,
  $element,
  pdfHighlights,
  pdfSpinner
) {
  this.load = function() {
    // $scope.pages = []

    // Ensure previous document is torn down before loading the next one (to
    // prevent race conditions)
    const documentTearDown =
      $scope.document != null ? $scope.document.destroy() : Promise.resolve()

    return documentTearDown.then(() => {
      $scope.loadCount = $scope.loadCount != null ? $scope.loadCount + 1 : 1
      // TODO need a proper url manipulation library to add to query string
      let url = $scope.pdfSrc
      // add 'pdfng=true' to show that we are using the angular pdfjs viewer
      const queryStringExists = /\?/.test(url)
      url = url + (!queryStringExists ? '?' : '&') + 'pdfng=true'
      // for isolated compiles, load the pdf on-demand because nobody will overwrite it
      const onDemandLoading = true
      $scope.document = new PDFRenderer(url, {
        scale: 1,
        disableAutoFetch: onDemandLoading ? true : undefined,
        navigateFn(ref) {
          // this function captures clicks on the annotation links
          $scope.navigateTo = ref
          return $scope.$apply()
        },
        progressCallback(progress) {
          return $scope.$emit('progress', progress)
        },
        loadedCallback() {
          return $scope.$emit('loaded')
        },
        errorCallback(error) {
          // MissingPDFException is "expected" as the pdf file can be on a
          // CLSI server that has been cycled out.
          // Currently, there is NO error handling to handle this situation,
          // but we plan to add this in the future
          // (https://github.com/overleaf/issues/issues/2985) and this error
          // is causing noise in Sentry so ignore it
          if (!error || error.name !== 'MissingPDFException') {
            captureMessage(`pdfng error ${error}`)
          }
          return $scope.$emit('pdf:error', error)
        },
        pageSizeChangeCallback(pageNum, deltaH) {
          return $scope.$broadcast('pdf:page:size-change', pageNum, deltaH)
        }
      })

      // we will have all the main information needed to start display
      // after the following promise is resolved
      $scope.loaded = $q
        .all({
          numPages: $scope.document.getNumPages(),
          // get size of first page as default @ scale 1
          pdfViewport: $scope.document.getPdfViewport(1, 1)
        })
        .then(function(result) {
          $scope.pdfViewport = result.pdfViewport
          $scope.pdfPageSize = [
            result.pdfViewport.height,
            result.pdfViewport.width
          ]
          // console.log 'resolved q.all, page size is', result
          $scope.$emit('loaded')
          return ($scope.numPages = result.numPages)
        })
        .catch(function(error) {
          $scope.$emit('pdf:error', error)
          return $q.reject(error)
        })

      return $scope.loaded
    })
  }

  this.setScale = (scale, containerHeight, containerWidth) =>
    $scope.loaded
      .then(function() {
        let numScale
        if (scale == null) {
          scale = {}
        }
        if (containerHeight === 0 || containerWidth === 0) {
          numScale = 1
        } else if (scale.scaleMode === 'scale_mode_fit_width') {
          // TODO make this dynamic
          numScale = (containerWidth - 40) / $scope.pdfPageSize[1]
        } else if (scale.scaleMode === 'scale_mode_fit_height') {
          // TODO magic numbers for jquery ui layout
          numScale = (containerHeight - 20) / $scope.pdfPageSize[0]
        } else if (scale.scaleMode === 'scale_mode_value') {
          numScale = scale.scale
        } else if (scale.scaleMode === 'scale_mode_auto') {
          // TODO
        } else {
          scale.scaleMode = 'scale_mode_fit_width'
          numScale = (containerWidth - 40) / $scope.pdfPageSize[1]
        }
        // TODO
        $scope.scale.scale = numScale
        $scope.document.setScale(numScale)
        return ($scope.defaultPageSize = [
          numScale * $scope.pdfPageSize[0],
          numScale * $scope.pdfPageSize[1]
        ])
      })
      // console.log 'in setScale result', $scope.scale.scale, $scope.defaultPageSize
      .catch(function(error) {
        $scope.$emit('pdf:error', error)
        return $q.reject(error)
      })

  this.redraw = function(position) {
    // console.log 'in redraw'
    // console.log 'reseting pages array for', $scope.numPages
    $scope.pages = __range__(0, $scope.numPages - 1, true).map(i => ({
      pageNum: i + 1
    }))
    if (position != null && position.page != null) {
      // console.log 'position is', position.page, position.offset
      // console.log 'setting current page', position.page
      let pagenum = position.page
      if (pagenum > $scope.numPages - 1) {
        pagenum = $scope.numPages - 1
      }
      $scope.pages[pagenum].current = true
      return ($scope.pages[pagenum].position = position)
    }
  }

  this.zoomIn = function() {
    // console.log 'zoom in'
    const newScale = $scope.scale.scale * 1.2
    return ($scope.forceScale = {
      scaleMode: 'scale_mode_value',
      scale: newScale
    })
  }

  this.zoomOut = function() {
    // console.log 'zoom out'
    const newScale = $scope.scale.scale / 1.2
    return ($scope.forceScale = {
      scaleMode: 'scale_mode_value',
      scale: newScale
    })
  }

  this.fitWidth = () =>
    // console.log 'fit width'
    ($scope.forceScale = { scaleMode: 'scale_mode_fit_width' })

  this.fitHeight = () =>
    // console.log 'fit height'
    ($scope.forceScale = { scaleMode: 'scale_mode_fit_height' })

  this.checkPosition = () =>
    // console.log 'check position'
    ($scope.forceCheck = ($scope.forceCheck || 0) + 1)

  this.showRandomHighlights = () =>
    // console.log 'show highlights'
    ($scope.highlights = [
      {
        page: 3,
        h: 100,
        v: 100,
        height: 30,
        width: 200
      }
    ])

  // we work with (pagenumber, % of height down page from top)
  // pdfListView works with (pagenumber, vertical position up page from
  // bottom measured in pts)

  this.getPdfPosition = function() {
    // console.log 'in getPdfPosition'
    let canvasOffset, pdfOffset, viewport
    let topPageIdx = 0
    let topPage = $scope.pages[0]
    // find first visible page
    const visible = $scope.pages.some(function(page, i) {
      if (page.visible) {
        let ref
        return ([topPageIdx, topPage] = Array.from((ref = [i, page]))), ref
      }
    })
    if (visible && topPage.element != null) {
      // console.log 'found it', topPageIdx
    } else {
      // console.log 'CANNOT FIND TOP PAGE'
      return
    }

    // console.log 'top page is', topPage.pageNum, topPage.elemTop, topPage.elemBottom, topPage
    const { top } = topPage.element.offset()
    const bottom = top + topPage.element.innerHeight()
    const viewportTop = $element.offset().top
    const viewportBottom = viewportTop + $element.height()
    const topVisible = top >= viewportTop && top < viewportBottom
    const someContentVisible = top < viewportTop && bottom > viewportTop
    // console.log 'in PdfListView', top, topVisible, someContentVisible, viewportTop
    if (topVisible) {
      canvasOffset = 0
    } else if (someContentVisible) {
      canvasOffset = viewportTop - top
    } else {
      canvasOffset = null
    }
    // console.log 'pdfListview position = ', canvasOffset
    // instead of using promise, check if size is known and revert to
    // default otherwise
    // console.log 'looking up viewport', topPage.viewport, $scope.pdfViewport
    if (topPage.viewport) {
      ;({ viewport } = topPage)
      pdfOffset = viewport.convertToPdfPoint(0, canvasOffset)
    } else {
      // console.log 'WARNING: had to default to global page size'
      viewport = $scope.pdfViewport
      const scaledOffset = canvasOffset / $scope.scale.scale
      pdfOffset = viewport.convertToPdfPoint(0, scaledOffset)
    }
    // console.log 'converted to offset = ', pdfOffset
    const newPosition = {
      page: topPageIdx,
      offset: { top: pdfOffset[1], left: 0 },
      pageSize: { height: viewport.viewBox[3], width: viewport.viewBox[2] }
    }
    return newPosition
  }

  this.computeOffset = function(page, position) {
    // console.log 'computing offset for', page, position
    const { element } = page
    // console.log 'element =', $(element), 'parent =', $(element).parent()
    const t1 = __guard__($(element).offset(), x => x.top)
    const t2 = __guard__(
      $(element)
        .parent()
        .offset(),
      x1 => x1.top
    )
    if (!(t1 != null && t2 != null)) {
      return $q((resolve, reject) => reject('elements destroyed'))
    }
    const pageTop =
      $(element).offset().top -
      $(element)
        .parent()
        .offset().top
    // console.log('top of page scroll is', pageTop, 'vs', page.elemTop)
    // console.log('inner height is', $(element).innerHeight())
    const currentScroll = $(element)
      .parent()
      .scrollTop()
    const { offset } = position
    // convert offset to pixels
    return $scope.document
      .getPdfViewport(page.pageNum)
      .then(function(viewport) {
        page.viewport = viewport
        const pageOffset = viewport.convertToViewportPoint(
          offset.left,
          offset.top
        )
        // if the passed-in position doesn't have the page height/width add them now
        if (position.pageSize == null) {
          position.pageSize = {
            height: viewport.viewBox[3],
            width: viewport.viewBox[2]
          }
        }
        // console.log 'addition offset =', pageOffset
        // console.log 'total', pageTop + pageOffset[1]
        return Math.round(pageTop + pageOffset[1] + currentScroll)
      }) // # 10 is margin
  }

  this.setPdfPosition = function(page, position) {
    // console.log 'required pdf Position is', position
    return this.computeOffset(page, position).then(function(offset) {
      return $scope.$apply(() => {
        $scope.pleaseScrollTo = offset
        $scope.position = position
      })
    })
  }
  return this
})

export default App.directive('pdfViewer', ($q, $timeout, pdfSpinner) => ({
  controller: 'pdfViewerController',
  controllerAs: 'ctrl',
  scope: {
    pdfSrc: '=',
    highlights: '=',
    position: '=',
    scale: '=',
    pleaseJumpTo: '='
  },
  template: `\
<div data-pdf-page class='pdf-page-container page-container' ng-repeat='page in pages'></div>\
`,
  link(scope, element, attrs, ctrl) {
    // console.log 'in pdfViewer element is', element
    // console.log 'attrs', attrs
    const spinner = new pdfSpinner()
    let layoutReady = $q.defer()
    layoutReady.notify('waiting for layout')
    layoutReady.promise.then(function() {})
    // console.log 'layoutReady was resolved'

    const renderVisiblePages = function() {
      const visiblePages = getVisiblePages()
      const pages = getExtraPages(visiblePages)
      return scope.document.renderPages(pages)
    }

    var getVisiblePages = function() {
      const top = element[0].scrollTop
      const bottom = top + element[0].clientHeight
      const visiblePages = _.filter(scope.pages, function(page) {
        if (page.element == null) {
          return false
        }
        const pageElement = page.element[0]
        const pageTop = pageElement.offsetTop
        const pageBottom = pageTop + pageElement.clientHeight
        page.visible = pageTop < bottom && pageBottom > top
        return page.visible
      })
      return visiblePages
    }

    var getExtraPages = function(visiblePages) {
      const extra = []
      if (visiblePages.length > 0) {
        const firstVisiblePage = visiblePages[0].pageNum
        const firstVisiblePageIdx = firstVisiblePage - 1
        const len = visiblePages.length
        const lastVisiblePage = visiblePages[len - 1].pageNum
        const lastVisiblePageIdx = lastVisiblePage - 1
        // first page after
        if (lastVisiblePageIdx + 1 < scope.pages.length) {
          extra.push(scope.pages[lastVisiblePageIdx + 1])
        }
        // page before
        if (firstVisiblePageIdx > 0) {
          extra.push(scope.pages[firstVisiblePageIdx - 1])
        }
        // second page after
        if (lastVisiblePageIdx + 2 < scope.pages.length) {
          extra.push(scope.pages[lastVisiblePageIdx + 2])
        }
      }
      return visiblePages.concat(extra)
    }

    let rescaleTimer = null
    const queueRescale = function(scale) {
      // console.log 'call to queueRescale'
      if (rescaleTimer != null || layoutTimer != null || elementTimer != null) {
        return
      }
      // console.log 'adding to rescale queue'
      return (rescaleTimer = setTimeout(function() {
        doRescale(scale)
        return (rescaleTimer = null)
      }, 0))
    }

    let spinnerTimer = null
    var doRescale = function(scale) {
      // console.log 'doRescale', scale
      if (scale == null) {
        return
      }
      const origposition = angular.copy(scope.position)
      // console.log 'origposition', origposition

      if (spinnerTimer == null) {
        spinnerTimer = setTimeout(function() {
          spinner.add(element)
          return (spinnerTimer = null)
        }, 100)
      }
      return layoutReady.promise.then(function(parentSize) {
        const [h, w] = Array.from(parentSize)
        // console.log 'in promise', h, w
        return ctrl
          .setScale(scale, h, w)
          .then(() =>
            // console.log 'in setscale then', scale, h, w
            scope.$evalAsync(function() {
              if (spinnerTimer) {
                clearTimeout(spinnerTimer)
              } else {
                spinner.remove(element)
              }
              // stop displaying the text layer
              element.removeClass('pdfjs-viewer-show-text')
              ctrl.redraw(origposition)
              $timeout(renderVisiblePages)
              return (scope.loadSuccess = true)
            })
          )
          .catch(error => scope.$emit('pdf:error', error))
      })
    }

    var elementTimer = null
    var updateLayout = function() {
      // if element is zero-sized keep checking until it is ready
      // console.log 'checking element ready', element.height(), element.width()
      if (element.height() === 0 || element.width() === 0) {
        if (elementTimer != null) {
          return
        }
        return (elementTimer = setTimeout(function() {
          elementTimer = null
          return updateLayout()
        }, 1000))
      } else {
        scope.parentSize = [element.innerHeight(), element.innerWidth()]
        // console.log 'resolving layoutReady with', scope.parentSize
        return $timeout(function() {
          layoutReady.resolve(scope.parentSize)
          return scope.$emit('flash-controls')
        })
      }
    }

    var layoutTimer = null
    const queueLayout = function() {
      // console.log 'call to queue layout'
      if (layoutTimer != null) {
        return
      }
      // console.log 'added to queue layoyt'
      layoutReady = $q.defer()
      return (layoutTimer = setTimeout(function() {
        // console.log 'calling update layout'
        updateLayout()
        // console.log 'setting layout timer to null'
        return (layoutTimer = null)
      }, 0))
    }

    queueLayout()

    // scope.$on 'layout:pdf:view', (e, args) ->
    //	console.log 'pdf view change', element, e, args
    //	queueLayout()

    scope.$on('layout:main:resize', () =>
      // console.log 'GOT LAYOUT-MAIN-RESIZE EVENT'
      queueLayout()
    )

    scope.$on('layout:pdf:resize', () =>
      // FIXME we get this event twice
      // also we need to start a new layout when we get it
      // console.log 'GOT LAYOUT-PDF-RESIZE EVENT'
      queueLayout()
    )

    scope.$on('pdf:error', function(event, error) {
      if (error.name === 'RenderingCancelledException') {
        return
      }
      // check if too many retries or file is missing
      const message = (error != null ? error.message : undefined) || error
      if (
        scope.loadCount > 3 ||
        /^Missing PDF/i.test(message) ||
        /^loading/i.test(message)
      ) {
        scope.$emit('pdf:error:display')
        return
      }
      if (scope.loadSuccess) {
        return ctrl
          .load()
          .then(
            () =>
              // trigger a redraw
              (scope.scale = angular.copy(scope.scale))
          )
          .catch(error => scope.$emit('pdf:error:display'))
      } else {
        scope.$emit('pdf:error:display')
      }
    })

    scope.$on('pdf:page:size-change', function(event, pageNum, delta) {
      // console.log 'page size change event', pageNum, delta
      const origposition = angular.copy(scope.position)
      // console.log 'orig position', JSON.stringify(origposition)
      if (
        origposition != null &&
        pageNum - 1 < origposition.page &&
        delta !== 0
      ) {
        const currentScrollTop = element.scrollTop()
        // console.log 'adjusting scroll from', currentScrollTop, 'by', delta
        scope.adjustingScroll = true
        return element.scrollTop(currentScrollTop + delta)
      }
    })

    element.on('mousedown', function(e) {
      // We're checking that the event target isn't the directive root element
      // to make sure that the click was within a PDF page - no point in showing
      // the text layer when the click is outside.
      // If the user clicks a PDF page, the mousedown target will be the canvas
      // element (or the text layer one). Alternatively, if the event target is
      // the root element, we can assume that the user has clicked either the
      // grey background area or the scrollbars.
      if (e.target !== element[0] && !_hasSelection()) {
        element.addClass('pdfjs-viewer-show-text')
        return _setMouseUpHandler()
      }
    })

    let mouseUpHandler = null // keep track of the handler to avoid adding multiple times

    var _setMouseUpHandler = function() {
      if (mouseUpHandler == null) {
        return (mouseUpHandler = $(document.body).one(
          'mouseup',
          _handleSelectionMouseUp
        ))
      }
    }

    var _handleSelectionMouseUp = function() {
      mouseUpHandler = null // reset handler, has now fired
      window.setTimeout(function() {
        const removedClass = _removeClassIfNoSelection()
        // if we still have a selection we need to keep the handler going
        if (!removedClass) {
          return _setMouseUpHandler()
        }
      }, 10)
      return true
    }

    var _removeClassIfNoSelection = function() {
      if (_hasSelection()) {
        return false // didn't remove the text layer
      } else {
        element.removeClass('pdfjs-viewer-show-text')
        return true
      }
    }

    var _hasSelection = function() {
      const selection =
        typeof window.getSelection === 'function'
          ? window.getSelection()
          : undefined
      // check the selection collapsed state in preference to
      // using selection.toString() as the latter is "" when
      // the selection is hidden (e.g. while viewing logs)
      return (
        selection != null &&
        _isSelectionWithinPDF(selection) &&
        !selection.isCollapsed
      )
    }

    var _isSelectionWithinPDF = function(selection) {
      if (selection.rangeCount === 0) {
        return false
      }
      const selectionAncestorNode = selection.getRangeAt(0)
        .commonAncestorContainer
      return (
        element.find(selectionAncestorNode).length > 0 ||
        element.is(selectionAncestorNode)
      )
    }

    element.on('scroll', function() {
      // console.log 'scroll event', element.scrollTop(), 'adjusting?', scope.adjustingScroll
      // scope.scrollPosition = element.scrollTop()
      if (scope.adjustingScroll) {
        renderVisiblePages()
        scope.adjustingScroll = false
        return
      }
      if (scope.scrollHandlerTimeout) {
        clearTimeout(scope.scrollHandlerTimeout)
      }
      return (scope.scrollHandlerTimeout = setTimeout(scrollHandler, 25))
    })

    var scrollHandler = function() {
      renderVisiblePages()
      const newPosition = ctrl.getPdfPosition()
      if (newPosition != null) {
        scope.position = newPosition
      }
      return (scope.scrollHandlerTimeout = null)
    }

    scope.$watch('pdfSrc', function(newVal, oldVal) {
      // console.log 'loading pdf', newVal, oldVal
      if (newVal == null) {
        return
      }
      scope.loadCount = 0 // new pdf, so reset load count
      scope.loadSuccess = false
      return ctrl
        .load()
        .then(
          () =>
            // trigger a redraw
            (scope.scale = angular.copy(scope.scale))
        )
        .catch(error => scope.$emit('pdf:error', error))
    })

    scope.$watch('scale', function(newVal, oldVal) {
      // no need to set scale when initialising, done in pdfSrc
      if (newVal === oldVal) {
        return
      }
      // console.log 'XXX calling Setscale in scale watch'
      return queueRescale(newVal)
    })

    scope.$watch('forceScale', function(newVal, oldVal) {
      // console.log 'got change in numscale watcher', newVal, oldVal
      if (newVal == null) {
        return
      }
      return queueRescale(newVal)
    })

    //				scope.$watch 'position', (newVal, oldVal) ->
    //					console.log 'got change in position watcher', newVal, oldVal

    scope.$watch('forceCheck', function(newVal, oldVal) {
      // console.log 'forceCheck', newVal, oldVal
      if (newVal == null) {
        return
      }
      scope.adjustingScroll = true // temporarily disable scroll
      return queueRescale(scope.scale)
    })

    scope.$watch(
      'parentSize',
      function(newVal, oldVal) {
        // console.log 'XXX in parentSize watch', newVal, oldVal
        // if newVal == oldVal
        // 	console.log 'returning because old and new are the same'
        // 	return
        // return unless oldVal?
        // console.log 'XXX calling setScale in parentSize watcher'
        if (newVal == null) {
          return
        }
        return queueRescale(scope.scale)
      },
      true
    )

    // scope.$watch 'elementWidth', (newVal, oldVal) ->
    // 	console.log '*** watch INTERVAL element width is', newVal, oldVal

    scope.$watch('pleaseScrollTo', function(newVal, oldVal) {
      // console.log 'got request to ScrollTo', newVal, 'oldVal', oldVal
      if (newVal == null) {
        return
      }
      scope.adjustingScroll = true // temporarily disable scroll
      // handler while we reposition
      $(element).scrollTop(newVal)
      return (scope.pleaseScrollTo = undefined)
    })

    scope.$watch('pleaseJumpTo', function(newPosition, oldPosition) {
      // console.log 'in pleaseJumpTo', newPosition, oldPosition
      if (newPosition == null) {
        return
      }
      return ctrl.setPdfPosition(scope.pages[newPosition.page - 1], newPosition)
    })

    scope.$watch('navigateTo', function(newVal, oldVal) {
      if (newVal == null) {
        return
      }
      // console.log 'got request to navigate to', newVal, 'oldVal', oldVal
      scope.navigateTo = undefined
      // console.log 'navigate to', newVal
      // console.log 'look up page num'
      return scope.document.getDestination(newVal.dest).then(r =>
        // console.log 'need to go to', r
        // console.log 'page ref is', r[0]
        scope.document.getPageIndex(r[0]).then(function(pidx) {
          // console.log 'page num is', pidx
          const page = scope.pages[pidx]
          return scope.document
            .getPdfViewport(page.pageNum)
            .then(function(viewport) {
              // console.log 'got viewport', viewport
              const coords = viewport.convertToViewportPoint(r[2], r[3])
              // console.log	'viewport position', coords
              // console.log 'r is', r, 'r[1]', r[1], 'r[1].name', r[1].name
              if (r[1].name === 'XYZ') {
                // console.log 'XYZ:', r[2], r[3]
                const newPosition = {
                  page: pidx,
                  offset: { top: r[3], left: r[2] }
                }
                return ctrl.setPdfPosition(scope.pages[pidx], newPosition)
              }
            })
        })
      )
    }) // XXX?

    scope.$watch('highlights', function(areas) {
      // console.log 'got HIGHLIGHTS in pdfViewer', areas
      if (areas == null) {
        return
      }
      // console.log 'areas are', areas
      const highlights = Array.from(areas || []).map(area => ({
        page: area.page - 1,
        highlight: {
          left: area.h,
          top: area.v,
          height: area.height,
          width: area.width
        }
      }))
      // console.log 'highlights', highlights

      if (!highlights.length) {
        return
      }

      scope.$broadcast('pdf:highlights', areas)

      const first = highlights[0]

      // switching between split and full pdf views can cause
      // highlights to appear before rendering
      if (!scope.pages) {
        return // ignore highlight scroll if still rendering
      }

      const pageNum =
        scope.pages[first.page] != null
          ? scope.pages[first.page].pageNum
          : undefined

      if (pageNum == null) {
        return // ignore highlight scroll if page not found
      }

      // use a visual offset of 72pt to match the offset in PdfController syncToCode
      return scope.document.getPdfViewport(pageNum).then(function(viewport) {
        const position = {
          page: first.page,
          offset: {
            left: first.highlight.left,
            top:
              viewport.viewBox[3] -
              first.highlight.top +
              first.highlight.height +
              72
          }
        }
        return ctrl.setPdfPosition(scope.pages[first.page], position)
      })
    })

    return scope.$on('$destroy', function() {
      // console.log 'handle pdfng directive destroy'
      if (elementTimer != null) {
        clearTimeout(elementTimer)
      }
      if (layoutTimer != null) {
        clearTimeout(layoutTimer)
      }
      if (rescaleTimer != null) {
        clearTimeout(rescaleTimer)
      }
      if (spinnerTimer != null) {
        return clearTimeout(spinnerTimer)
      }
    })
  }
}))

function __range__(left, right, inclusive) {
  let range = []
  let ascending = left < right
  let end = !inclusive ? right : ascending ? right + 1 : right - 1
  for (let i = left; ascending ? i < end : i > end; ascending ? i++ : i--) {
    range.push(i)
  }
  return range
}
function __guard__(value, transform) {
  return typeof value !== 'undefined' && value !== null
    ? transform(value)
    : undefined
}
