declare var PDFJS: any;
import Emitter, { IEmitter } from './Emitter';
import * as Hammer from 'hammerjs';
import { UAParser as ua } from 'ua-parser-js';
import { IStorageService } from './Storage';
import { IIPPConfig } from './Config';
import Promise from 'promise';
// import { PDFJS } from 'pdfjs-dist'
import Helpers, { IHelpers } from './Helpers';

const helpers: IHelpers = new Helpers();

// Main/public page service
let storage: IStorageService, config: IIPPConfig;

class PdfWrap {
  constructor(
    // interval: any,
    ippStorage: any,
    ippConf: any
  ) {
    storage = ippStorage;
    config = ippConf;

    return Pdf;
  }
}

export default PdfWrap;

export interface IPdf extends IEmitter {
  ON_LOADING: string;
  ON_LOADED: string;
  fit: string;
  destroy(): void;
  render(data: any): Promise<void>;
  setFit(dimension: string): void;
  page(direction: any): void;
}

export class Pdf extends Emitter implements IPdf {
  // public static $inject: string[] = [
  //     "$timeout",
  //     "$interval",
  //     "$q",
  //     "ippStorageService",
  //     "CONFIG",
  // ];

  public get ON_LOADING(): string {
    return 'loading';
  }
  public get ON_LOADED(): string {
    return 'loaded';
  }
  public get ON_FOCUS(): string {
    return 'focus';
  }

  public data: any = [];
  public rendering: boolean = false;

  // public canvasId: string = "pdfCanvas";
  public annotationId: string = 'pdfAnnotations';
  public containerEl: any;
  public canvasEl: any;
  public annotationsEl: any;

  public fileUrl!: string;

  public pdfObj: any;
  public pdfLink: any;
  public pdfPages: number = 1;
  public pdfPage: number = 1;

  private _fit: string = 'contain';

  private touch: boolean = false;
  private hammer!: HammerManager;
  private scale: number = 1;
  private ratio: number = 1;
  private ratioScale: number = 1;

  private containerBounds: any;
  private canvasBounds: any;

  public scrollbars: any = {
    width: 8,
    inset: false,
    scrolling: false,
    x: {
      size: 0,
      offset: 0,
      offsetPercent: 0,
      label: 'width',
      style: 'margin-left',
      show: false,
      anchor: 'left',
      track: undefined,
      handle: undefined
    },
    y: {
      size: 0,
      offset: 0,
      offsetPercent: 0,
      label: 'height',
      style: 'margin-top',
      show: false,
      anchor: 'top',
      track: undefined,
      handle: undefined
    }
  };

  constructor(public container: string) {
    super();
    this.destroy();
    let parser: any = new ua();
    let parseResult: IUAParser.IResult = parser.getResult();
    this.touch = parseResult.device && (parseResult.device.type === 'tablet' || parseResult.device.type === 'mobile');
    this.pdfLink = new PdfLink();
    this.pdfLink.register((name: string, value: any) => {
      console.log('pdf', name, value);
      if (name === this.pdfLink.ON_GOTO_PAGE) {
        this.pdfPage = value;
        this.renderPdf();
      }
    });
    if (typeof container === 'string') {
      this.containerEl = document.getElementById(container);
    } else {
      this.containerEl = container;
    }
    this.containerEl.style['overflow'] = this.touch ? 'auto' : 'hidden';
    this.containerEl.style['text-align'] = 'center';

    // create pdf canvas
    this.canvasEl = document.createElement('canvas');

    // create anotations layer
    this.annotationsEl = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    this.annotationsEl.style['position'] = 'absolute';
    this.annotationsEl.style['z-index'] = '1';
    this.annotationsEl.style['left'] = '0';
    this.annotationsEl.style['top'] = '0';
    // this.annotationsEl.style["width"] = "100%";

    this.containerEl.appendChild(this.canvasEl);
    this.containerEl.appendChild(this.annotationsEl);
    this.ratio = window.devicePixelRatio;
    this.scale = this.ratio;
    this.ratioScale = this.scale;
    if (this.touch) {
      this.setupTouch();
    } else {
      this.containerEl.addEventListener('wheel', this.onWheelEvent, false);
      window.addEventListener('mouseup', this.onMouseUp, false);
      window.addEventListener('mousedown', this.onMouseDown, false);
      window.addEventListener('mousemove', this.onMouseMove, false);
      window.addEventListener('keydown', this.onKeydown, false);
      this.createScrollbars();
    }
    window.addEventListener('resize', this.onResizeEvent);
    return;
  }

  get fit(): string {
    return this._fit;
  }

  set fit(value: string) {
    if (['scroll', 'width', 'height', 'contain'].indexOf(value) === -1) {
      return;
    }
    this._fit = value;
  }

  public destroy() {
    if (!this.containerEl) {
      return;
    }
    document.removeEventListener('resize', this.onResizeEvent);
    this.containerEl.innerHTML = '';
    if (this.hammer) {
      this.hammer.destroy();
    } else {
      this.containerEl.removeEventListener('wheel', this.onWheelEvent, false);
      window.removeEventListener('mouseup', this.onMouseUp, false);
      window.removeEventListener('mousedown', this.onMouseDown, false);
      window.removeEventListener('mousemove', this.onMouseMove, false);
      window.removeEventListener('keydown', this.onKeydown, false);
    }
  }

  public render(data: any): Promise<void> {
    let p: Promise<any> = new Promise((resolve, reject) => {
      // check if we a url
      this.data = data;
      if (!this.data || !this.data[0] || !this.data[0][0]) {
        reject(false);
        return;
      }

      // get url
      this.fileUrl = this.handleURL(this.data[0][0].formatted_value || this.data[0][0].value);

      // start render
      this.rendering = true;

      // setup httpHeaders
      let headers: any = {};

      if (this.fileUrl.indexOf('ipushpull.') >= 0) {
        headers = {
          Authorization: 'Bearer ' + storage.persistent.get('access_token'),
          'x-ipp-client': config.api_key
        };
      }

      if (!this.fileUrl) {
        reject({ message: 'File not found' });
        return;
      }

      // load pdf into memory
      let loading = PDFJS.getDocument(
        {
          url: this.fileUrl,
          httpHeaders: headers
        },
        undefined,
        undefined,
        (result: any) => {
          this.emit(this.ON_LOADING, result);
        }
      );
      loading.then(
        (pdf: any) => {
          this.pdfObj = pdf;
          this.pdfLink.setDocument(pdf);
          this.pdfPages = pdf.numPages;
          this.renderPdf();
          resolve(true);
        },
        (err: any) => {
          reject(err);
        }
      );
    });
    return p;
  }

  public setFit(dimension: string) {
    if (['scroll', 'width', 'height', 'contain'].indexOf(dimension) === -1) {
      return;
    }
    this.fit = dimension;
    if (dimension === 'scroll') {
      this.canvasEl.style['width'] = 'auto';
      this.canvasEl.style['height'] = 'auto';
    } else if (dimension === 'width') {
      this.canvasEl.style['width'] = '100%';
      this.canvasEl.style['height'] = 'auto';
    } else if (dimension === 'height') {
      this.canvasEl.style['width'] = 'auto';
      this.canvasEl.style['height'] = '100%';
    } else if (dimension === 'contain') {
      let containerBounds = this.containerEl.getBoundingClientRect();
      let canvasBounds = this.canvasEl.getBoundingClientRect();
      let canvasProp: any = this.canvasEl.width / this.canvasEl.height;
      let containerProp: any = containerBounds.width / containerBounds.height;

      if (canvasProp > containerProp) {
        this.canvasEl.style['width'] = '100%';
        this.canvasEl.style['height'] = 'auto';
      } else {
        this.canvasEl.style['width'] = 'auto';
        this.canvasEl.style['height'] = '100%';
      }
    }
    this.containerEl.scrollLeft = 0;
    this.containerEl.scrollTop = 0;
    this.resetScrollbars();
    this.setAnnotationsBounds();
    this.updateScrollbars();
  }

  public page(direction: any) {
    if (direction === 'next') {
      this.pdfPage++;
    } else if (direction === 'prev') {
      this.pdfPage--;
    } else {
      this.pdfPage = parseInt(direction, 10);
    }
    this.setPage();
  }

  private onResizeEvent: any = () => {
    // this.setFit(this.fit);
    this.setAnnotationsBounds();
    this.updateScrollbars();
    this.setFit(this.fit);
  };

  private onWheelEvent: any = (evt: any) => {
    if (this.fit === 'contain') return;
    if (this.fit === 'width' && this.containerBounds.height > this.canvasBounds.height) return;
    if (this.fit === 'height' && this.containerBounds.width > this.canvasBounds.width) return;
    let offset = Math.abs(evt.deltaY) >= 100 ? Math.round(Math.abs(evt.deltaY) / 5) : 20;
    let direction = evt.deltaY > 0 ? 1 : -1;
    offset *= direction;
    let axis = 'y';
    if (
      this.canvasBounds.height <= this.containerBounds.height &&
      this.canvasBounds.width > this.containerBounds.width
    ) {
      axis = 'x';
    }
    console.log(axis, offset);
    this.moveScrollbarTrack(axis, offset);
  };

  private onMouseUp: any = () => {
    console.log('onMouseUp');
    this.scrollbars.scrolling = false;
    ['x', 'y'].forEach(axis => {
      this.scrollbars[axis].drag = false;
    });
  };

  private onMouseDown: any = (evt: any) => {
    let scrollHandle = false;
    ['x', 'y'].forEach(axis => {
      if (this.scrollbars[axis].handle === evt.target) scrollHandle = true;
    });
    if (scrollHandle) return;
    if (helpers.isTarget(this.containerEl, evt.target)) {
      this.emit(this.ON_FOCUS);
    }
  };

  private onKeydown: any = (evt: KeyboardEvent) => {
    switch (evt.keyCode) {
      // left
      case 37:
        this.page('prev');
        break;
      // right
      case 39:
        this.page('next');
        break;
    }
  };

  private onMouseMove: any = (evt: any) => {
    ['x', 'y'].forEach(axis => {
      if (!this.scrollbars[axis].drag || !this.scrollbars.scrolling) {
        return;
      }

      // check if handle has reached limits
      let offset = evt[axis] - this.scrollbars[axis].start;
      this.moveScrollbarTrack(axis, offset);
      this.scrollbars[axis].start = evt[axis];
    });
  };

  private resetScrollbars(): void {
    ['x', 'y'].forEach(axis => {
      let anchor = this.scrollbars[axis].anchor;
      this.scrollbars[axis].offset = 0;
      this.scrollbars[axis].size = 0;
      this.scrollbars[axis].show = false;
      this.canvasEl.style[this.scrollbars[axis].style] = `0px`;
      this.annotationsEl.style[this.scrollbars[axis].style] = `0px`;
      if (this.scrollbars[axis].handle) {
        this.scrollbars[axis].handle.style[anchor] = `0px`;
      }
    });
  }

  private moveScrollbarTrack(axis: string, offset: number): void {
    this.scrollbars[axis].offset += offset;
    // check if handle has reached limits
    let dimension = this.scrollbars[axis].label;
    let canvasSize = this.canvasBounds[dimension];
    // let size = this.containerBounds[dimension] * (this.containerBounds[dimension] / canvasSize);
    let distance = this.containerBounds[dimension] - this.scrollbars[axis].size;
    // let offset = evt[axis] - this.scrollbars[axis].start + this.scrollbars[axis].offset;
    if (this.scrollbars[axis].offset > distance) {
      this.scrollbars[axis].offset = distance;
    } else if (this.scrollbars[axis].offset < 0) {
      this.scrollbars[axis].offset = 0;
    }

    // new index based on how far scroll has moved
    let anchor = this.scrollbars[axis].anchor;
    this.scrollbars[axis].handle.style[anchor] = `${this.scrollbars[axis].offset}px`;

    let offsetPercent = this.scrollbars[axis].offset / (this.containerBounds[dimension] - this.scrollbars[axis].size);
    let offsetDistance = (this.containerBounds[dimension] - this.canvasBounds[dimension]) * offsetPercent;
    this.scrollbars[axis].offsetPercent = offsetPercent;

    this.canvasEl.style[this.scrollbars[axis].style] = `${offsetDistance}px`;
    this.annotationsEl.style[this.scrollbars[axis].style] = `${offsetDistance}px`;
  }

  private createScrollbars() {
    ['x', 'y'].forEach(axis => {
      let anchor = this.scrollbars[axis].anchor;

      this.scrollbars[axis].track = document.createElement('div');
      this.scrollbars[axis].handle = document.createElement('div');

      // setup track
      this.scrollbars[axis].track.style['position'] = 'absolute';
      this.scrollbars[axis].track.style['z-index'] = 10;
      this.scrollbars[axis].track.style['display'] = 'none';
      this.scrollbars[axis].track.className = 'track';

      // setup handle
      this.scrollbars[axis].handle.style['position'] = 'absolute';
      this.scrollbars[axis].handle.style['z-index'] = 1;
      this.scrollbars[axis].handle.style['left'] = 0;
      this.scrollbars[axis].handle.style['top'] = 0;
      this.scrollbars[axis].handle.className = 'handle';
      this.scrollbars[axis].handle.addEventListener(
        'mousedown',
        (evt: any) => {
          console.log('mousedown');
          this.scrollbars.scrolling = true;
          this.scrollbars[axis].start = evt[axis];
          this.scrollbars[axis].drag = true;
          this.scrollbars[axis].offset = parseInt(this.scrollbars[axis].handle.style[anchor], 10);
          // evt.stopPropagation();
          evt.preventDefault();
        },
        false
      );
      // this.scrollbars[axis].handle.addEventListener("mouseenter", (evt: any) => {
      //     this.scrollbars[axis].pressed = true;
      //     evt.stopPropagation();
      // }, false);

      if (axis === 'x') {
        this.scrollbars[axis].track.style['left'] = 0;
        this.scrollbars[axis].track.style['bottom'] = 0;
        this.scrollbars[axis].track.style['right'] = 0;
        this.scrollbars[axis].track.style['height'] = `${this.scrollbars.width}px`;
        this.scrollbars[axis].handle.style['height'] = `${this.scrollbars.width}px`;
      } else {
        this.scrollbars[axis].track.style['top'] = 0;
        this.scrollbars[axis].track.style['right'] = 0;
        this.scrollbars[axis].track.style['bottom'] = 0;
        this.scrollbars[axis].track.style['width'] = `${this.scrollbars.width}px`;
        this.scrollbars[axis].handle.style['width'] = `${this.scrollbars.width}px`;
      }

      this.scrollbars[axis].track.appendChild(this.scrollbars[axis].handle);
      this.containerEl.appendChild(this.scrollbars[axis].track);
    });
  }

  private updateScrollbars() {
    if (this.touch) {
      return;
    }
    ['x', 'y'].forEach(axis => {
      // let offset = this.offsets[axis].index / this.offsets[axis].max * (canvasSize - size);
      // let anchor = this.scrollbars[axis].anchor;
      // this.scrollbars[axis].handle.style[anchor] = `${offset}px`;
      let dimension = this.scrollbars[axis].label;
      if (this.containerBounds[dimension] >= this.canvasBounds[dimension]) {
        this.scrollbars[axis].track.style.display = 'none';
        return;
      }

      let canvasSize = this.canvasBounds[dimension];
      let size = this.containerBounds[dimension] * (this.containerBounds[dimension] / canvasSize);
      this.scrollbars[axis].handle.style[dimension] = `${size}px`;
      this.scrollbars[axis].size = size;

      let anchor = this.scrollbars[axis].anchor;
      let offsetPercent = this.scrollbars[axis].offsetPercent;
      let offsetDistance = (this.containerBounds[dimension] - size) * offsetPercent;

      this.scrollbars[axis].handle.style[anchor] = `${offsetDistance}px`;

      this.scrollbars[axis].track.style.display = 'block';

      offsetDistance = (this.containerBounds[dimension] - this.canvasBounds[dimension]) * offsetPercent;

      this.canvasEl.style[this.scrollbars[axis].style] = `${offsetDistance}px`;
      this.annotationsEl.style[this.scrollbars[axis].style] = `${offsetDistance}px`;
    });
  }

  private setAnnotationsBounds() {
    this.containerBounds = this.containerEl.getBoundingClientRect();
    this.canvasBounds = this.canvasEl.getBoundingClientRect();
    // let width = this.canvasEl.style.width || `${canvasBounds.width}px`;
    // if (width === "auto" && this.canvasEl.style.height === "100%" || this.fit === "scroll") {
    //     this.annotationsEl.style.left = `${(canvasBounds.left - containerBounds.left)}px`;
    // } else {
    //     this.annotationsEl.style.left = `0px`;
    // }
    this.annotationsEl.style.left = `${this.canvasBounds.left - this.containerBounds.left}px`;
    this.annotationsEl.style.width = `${this.canvasBounds.width}px`;
    this.annotationsEl.style.height = `${this.canvasBounds.height}px`;
  }

  private setupTouch() {
    this.hammer = new Hammer.default(this.containerEl);
    let pan: any = new Hammer.Pan();
    let pinch: any = new Hammer.Pinch();
    this.hammer.add([pan, pinch]);

    let width: any;
    this.hammer.on('pinchstart', (evt: any) => {
      let rect = this.canvasEl.getBoundingClientRect();
      width = rect.width;
      this.fit = 'scroll';
      this.canvasEl.style.width = `${width}px`;
      this.canvasEl.style.height = `auto`;
    });
    this.hammer.on('pinchmove', (evt: any) => {
      console.log(evt);
      this.canvasEl.style.width = `${width * evt.scale}px`;
      this.setAnnotationsBounds();
    });
    this.hammer.on('pinchend', (evt: any) => {});

    let offsets = { x: 0, y: 0, left: this.containerEl.scrollLeft, top: this.containerEl.scrollTop };
    this.hammer.on('panstart', (evt: any) => {
      offsets.x = evt.center.x;
      offsets.y = evt.center.y;
      offsets.left = this.containerEl.scrollLeft;
      offsets.top = this.containerEl.scrollTop;
    });
    this.hammer.on('panmove', (evt: any) => {
      this.containerEl.scrollTop = offsets.top + offsets.y - evt.center.y;
      this.containerEl.scrollLeft = offsets.left + offsets.x - evt.center.x;
    });
    this.hammer.on('panend', (evt: any) => {});
  }

  private setPage() {
    if (this.pdfPage > this.pdfPages) {
      this.pdfPage = 1;
    } else if (this.pdfPage <= 0) {
      this.pdfPage = this.pdfPages;
    }
    this.renderPdf();
  }

  private renderPdf(): Promise<void> {
    let p: Promise<any> = new Promise((resolve, reject) => {
      // get page
      this.pdfObj.getPage(this.pdfPage).then(
        (page: any) => {
          // get size of pdf
          let viewport: any = page.getViewport(2);

          // setup canvas
          let context: any = this.canvasEl.getContext('2d');
          this.canvasEl.height = viewport.height;
          this.canvasEl.width = viewport.width;

          // render context
          let renderContext: any = {
            canvasContext: context,
            viewport: viewport
          };

          // finally render pdf
          let render: any = page.render(renderContext);
          render.promise.then((a: any) => {
            console.log('renderPdf', a);
            this.setFit(this.fit);
            this.emit(this.ON_LOADED, true);
            this.renderAnnotations(page, viewport, context);
            resolve(a);
          }, reject);
        },
        (err: any) => {
          console.log('renderPdf', err);
        }
      );
    });
    return p;
  }

  private renderAnnotations(page: any, viewport: any, canvas: any): void {
    let layer: any = this.annotationsEl;
    if (!layer) {
      return;
    }
    layer.innerHTML = '';
    this.setAnnotationsBounds();
    console.log('pdf', layer);

    let appendAnchor = (element: any, url: any) => {
      let svgNS = this.annotationsEl.namespaceURI;
      let a = document.createElementNS(svgNS, 'a');
      a.setAttribute('class', 'pdf-link');
      a.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#');
      a.addEventListener('click', e => {
        console.log('pdf', 'click', url);
        if (url.link) {
          window.open(url.link, '_blank');
          e.preventDefault();
        } else if (url.internal) {
          this.page(url.page + 1);
        }
      });
      let rect = document.createElementNS(svgNS, 'rect');
      rect.setAttribute('x', element.rect[0]);
      rect.setAttribute('y', `${viewport.viewBox[3] - element.rect[3]}`);
      rect.setAttribute('width', `${element.rect[2] - element.rect[0]}`);
      rect.setAttribute('height', `${element.rect[3] - element.rect[1]}`);
      rect.setAttribute('fill', 'rgba(30,144,255,1)');
      // rect.setAttribute("stroke", "dodgerblue");
      // rect.setAttribute("stroke-width", "1");
      a.appendChild(rect);
      this.annotationsEl.appendChild(a);
    };

    page.getAnnotations().then((annotationsData: any) => {
      console.log(annotationsData);
      // annotationsData.rect[x, y, x2, y2] 196.764, 161.004, 414.036, 174.036   792
      viewport = viewport.clone({
        dontFlip: true
      });
      layer.setAttribute('viewBox', viewport.viewBox.join(' '));
      annotationsData.forEach((element: any) => {
        if (element.dest && typeof element.dest === 'string') {
          this.pdfObj.getDestination(element.dest).then(
            (res: any) => {
              console.log('pdf', res);
              this.pdfObj.getPageIndex(res[0]).then(
                (page: any) => {
                  console.log('pdf', page);
                  appendAnchor(element, { internal: true, page: page });
                },
                (err: any) => {
                  console.error('pdf', err);
                }
              );
            },
            (err: any) => {
              console.error('pdf', err);
            }
          );
        } else if (element.url) {
          appendAnchor(element, { link: element.url });
        }
      });
      // let annotationLayer: any = PDFJS.AnnotationLayer;
      // annotationLayer.render({
      //     annotations: annotationsData,
      //     div: layer,
      //     page: page,
      //     viewport: viewport,
      //     linkService: this.pdfLink,
      // });
    });
  }

  private handleURL(url: string) {
    if (url.indexOf('dropbox.com') > -1) {
      url = url.split('www.dropbox.com').join('dl.dropboxusercontent.com');
      return `${config.docs_url}/default/relay?url=${url}`;
    }

    return url;
  }
}

class PdfLink extends Emitter {
  public get ON_GOTO_PAGE(): string {
    return 'goto_page';
  }

  public baseUrl!: string;
  public pdfDocument: any;
  public pdfViewer: any;
  public pdfHistory: any;

  private _pagesRefCache: any = undefined;

  constructor() {
    super();
  }

  public setDocument(pdfDocument: any, baseUrl: string) {
    this.baseUrl = baseUrl;
    this.pdfDocument = pdfDocument;
    this._pagesRefCache = {}; // Object.create(undefined);
  }

  /**
   * @returns {number}
   */
  public get pagesCount(): number {
    return this.pdfDocument.numPages;
  }

  /**
   * @returns {number}
   */
  public get page(): number {
    return this.pdfViewer.currentPageNumber;
  }
  /**
   * @param {number} value
   */
  public set page(value: number) {
    this.pdfViewer.currentPageNumber = value;
  }
  /**
   * @param dest - The PDF destination object.
   */
  public navigateTo(dest: any): void {
    let destString: string = '';

    let goToDestination: any = (destRef: any) => {
      // dest array looks like that: <page-ref> </XYZ|FitXXX> <args..>
      let pageNumber: number =
        destRef instanceof Object ? this._pagesRefCache[destRef.num + ' ' + destRef.gen + ' R'] : destRef + 1;

      if (pageNumber) {
        if (pageNumber > this.pagesCount) {
          pageNumber = this.pagesCount;
        }
        this.emit(this.ON_GOTO_PAGE, pageNumber);
        // $scope.goToPage(pageNumber); TODO !!
      } else {
        this.pdfDocument.getPageIndex(destRef).then((pageIndex: any) => {
          let pageNum: number = pageIndex + 1;
          let cacheKey: string = destRef.num + ' ' + destRef.gen + ' R';
          this._pagesRefCache[cacheKey] = pageNum;
          goToDestination(destRef);
        });
      }
    };

    let destinationPromise;
    if (typeof dest === 'string') {
      destString = dest;
      destinationPromise = this.pdfDocument.getDestination(dest);
    } else {
      destinationPromise = Promise.resolve(dest);
    }
    destinationPromise.then(function(destination: any) {
      dest = destination;
      if (!(destination instanceof Array)) {
        return; // invalid destination
      }
      goToDestination(destination[0]);
    });
  }

  /**
   * @param dest - The PDF destination object.
   * @returns {string} The hyperlink to the PDF object.
   */
  public getDestinationHash(dest: any) {
    if (typeof dest === 'string') {
      return this.getAnchorUrl('#' + escape(dest));
    }
    if (dest instanceof Array) {
      let destRef = dest[0]; // see navigateTo method for dest format
      let pageNumber =
        destRef instanceof Object ? this._pagesRefCache[destRef.num + ' ' + destRef.gen + ' R'] : destRef + 1;
      if (pageNumber) {
        let pdfOpenParams = this.getAnchorUrl('#page=' + pageNumber);
        let destKind = dest[1];
        if (typeof destKind === 'object' && 'name' in destKind && destKind.name === 'XYZ') {
          let scale = dest[4];
          let scaleNumber = parseFloat(scale);
          if (scaleNumber) {
            scale = scaleNumber * 100;
          }
          pdfOpenParams += '&zoom=' + scale;
          if (dest[2] || dest[3]) {
            pdfOpenParams += ',' + (dest[2] || 0) + ',' + (dest[3] || 0);
          }
        }
        return pdfOpenParams;
      }
    }
    return '';
  }

  /**
   * Prefix the full url on anchor links to make sure that links are resolved
   * relative to the current URL instead of the one defined in <base href>.
   * @param {String} anchor The anchor hash, including the #.
   * @returns {string} The hyperlink to the PDF object.
   */
  public getAnchorUrl(anchor: string): string {
    return (this.baseUrl || '') + anchor;
  }

  /**
   * @param {string} hash
   */
  // public setHash(hash) { },

  /**
   * @param {string} action
   */
  // public executeNamedAction(action) { }

  /**
   * @param {number} pageNum - page number.
   * @param {Object} pageRef - reference to the page.
   */
  public cachePageRef(pageNum: any, pageRef: any) {
    let refStr: string = pageRef.num + ' ' + pageRef.gen + ' R';
    this._pagesRefCache[refStr] = pageNum;
  }
}
