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
}
