/* Copyright 2017 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';
var domEvents = require('./dom_events.js');
function PDFHistory(options) {
 this.linkService = options.linkService;
 this.eventBus = options.eventBus || domEvents.getGlobalEventBus();
 this.initialized = false;
 this.initialDestination = null;
 this.initialBookmark = null;
}
PDFHistory.prototype = {
 initialize: function pdfHistoryInitialize(fingerprint) {
  this.initialized = true;
  this.reInitialized = false;
  this.allowHashChange = true;
  this.historyUnlocked = true;
  this.isViewerInPresentationMode = false;
  this.previousHash = window.location.hash.substring(1);
  this.currentBookmark = '';
  this.currentPage = 0;
  this.updatePreviousBookmark = false;
  this.previousBookmark = '';
  this.previousPage = 0;
  this.nextHashParam = '';
  this.fingerprint = fingerprint;
  this.currentUid = this.uid = 0;
  this.current = {};
  var state = window.history.state;
  if (this._isStateObjectDefined(state)) {
   if (state.target.dest) {
    this.initialDestination = state.target.dest;
   } else {
    this.initialBookmark = state.target.hash;
   }
   this.currentUid = state.uid;
   this.uid = state.uid + 1;
   this.current = state.target;
  } else {
   if (state && state.fingerprint && this.fingerprint !== state.fingerprint) {
    this.reInitialized = true;
   }
   this._pushOrReplaceState({ fingerprint: this.fingerprint }, true);
  }
  var self = this;
  window.addEventListener('popstate', function pdfHistoryPopstate(evt) {
   if (!self.historyUnlocked) {
    return;
   }
   if (evt.state) {
    self._goTo(evt.state);
    return;
   }
   if (self.uid === 0) {
    var previousParams = self.previousHash && self.currentBookmark && self.previousHash !== self.currentBookmark ? {
     hash: self.currentBookmark,
     page: self.currentPage
    } : { page: 1 };
    replacePreviousHistoryState(previousParams, function () {
     updateHistoryWithCurrentHash();
    });
   } else {
    updateHistoryWithCurrentHash();
   }
  });
  function updateHistoryWithCurrentHash() {
   self.previousHash = window.location.hash.slice(1);
   self._pushToHistory({ hash: self.previousHash }, false, true);
   self._updatePreviousBookmark();
  }
  function replacePreviousHistoryState(params, callback) {
   self.historyUnlocked = false;
   self.allowHashChange = false;
   window.addEventListener('popstate', rewriteHistoryAfterBack);
   history.back();
   function rewriteHistoryAfterBack() {
    window.removeEventListener('popstate', rewriteHistoryAfterBack);
    window.addEventListener('popstate', rewriteHistoryAfterForward);
    self._pushToHistory(params, false, true);
    history.forward();
   }
   function rewriteHistoryAfterForward() {
    window.removeEventListener('popstate', rewriteHistoryAfterForward);
    self.allowHashChange = true;
    self.historyUnlocked = true;
    callback();
   }
  }
  function pdfHistoryBeforeUnload() {
   var previousParams = self._getPreviousParams(null, true);
   if (previousParams) {
    var replacePrevious = !self.current.dest && self.current.hash !== self.previousHash;
    self._pushToHistory(previousParams, false, replacePrevious);
    self._updatePreviousBookmark();
   }
   window.removeEventListener('beforeunload', pdfHistoryBeforeUnload);
  }
  window.addEventListener('beforeunload', pdfHistoryBeforeUnload);
  window.addEventListener('pageshow', function pdfHistoryPageShow(evt) {
   window.addEventListener('beforeunload', pdfHistoryBeforeUnload);
  });
  self.eventBus.on('presentationmodechanged', function (e) {
   self.isViewerInPresentationMode = e.active;
  });
 },
 clearHistoryState: function pdfHistory_clearHistoryState() {
  this._pushOrReplaceState(null, true);
 },
 _isStateObjectDefined: function pdfHistory_isStateObjectDefined(state) {
  return state && state.uid >= 0 && state.fingerprint && this.fingerprint === state.fingerprint && state.target && state.target.hash ? true : false;
 },
 _pushOrReplaceState: function pdfHistory_pushOrReplaceState(stateObj, replace) {
  if (replace) {
   window.history.replaceState(stateObj, '', document.URL);
  } else {
   window.history.pushState(stateObj, '', document.URL);
  }
 },
 get isHashChangeUnlocked() {
  if (!this.initialized) {
   return true;
  }
  return this.allowHashChange;
 },
 _updatePreviousBookmark: function pdfHistory_updatePreviousBookmark() {
  if (this.updatePreviousBookmark && this.currentBookmark && this.currentPage) {
   this.previousBookmark = this.currentBookmark;
   this.previousPage = this.currentPage;
   this.updatePreviousBookmark = false;
  }
 },
 updateCurrentBookmark: function pdfHistoryUpdateCurrentBookmark(bookmark, pageNum) {
  if (this.initialized) {
   this.currentBookmark = bookmark.substring(1);
   this.currentPage = pageNum | 0;
   this._updatePreviousBookmark();
  }
 },
 updateNextHashParam: function pdfHistoryUpdateNextHashParam(param) {
  if (this.initialized) {
   this.nextHashParam = param;
  }
 },
 push: function pdfHistoryPush(params, isInitialBookmark) {
  if (!(this.initialized && this.historyUnlocked)) {
   return;
  }
  if (params.dest && !params.hash) {
   params.hash = this.current.hash && this.current.dest && this.current.dest === params.dest ? this.current.hash : this.linkService.getDestinationHash(params.dest).split('#')[1];
  }
  if (params.page) {
   params.page |= 0;
  }
  if (isInitialBookmark) {
   var target = window.history.state.target;
   if (!target) {
    this._pushToHistory(params, false);
    this.previousHash = window.location.hash.substring(1);
   }
   this.updatePreviousBookmark = this.nextHashParam ? false : true;
   if (target) {
    this._updatePreviousBookmark();
   }
   return;
  }
  if (this.nextHashParam) {
   if (this.nextHashParam === params.hash) {
    this.nextHashParam = null;
    this.updatePreviousBookmark = true;
    return;
   }
   this.nextHashParam = null;
  }
  if (params.hash) {
   if (this.current.hash) {
    if (this.current.hash !== params.hash) {
     this._pushToHistory(params, true);
    } else {
     if (!this.current.page && params.page) {
      this._pushToHistory(params, false, true);
     }
     this.updatePreviousBookmark = true;
    }
   } else {
    this._pushToHistory(params, true);
   }
  } else if (this.current.page && params.page && this.current.page !== params.page) {
   this._pushToHistory(params, true);
  }
 },
 _getPreviousParams: function pdfHistory_getPreviousParams(onlyCheckPage, beforeUnload) {
  if (!(this.currentBookmark && this.currentPage)) {
   return null;
  } else if (this.updatePreviousBookmark) {
   this.updatePreviousBookmark = false;
  }
  if (this.uid > 0 && !(this.previousBookmark && this.previousPage)) {
   return null;
  }
  if (!this.current.dest && !onlyCheckPage || beforeUnload) {
   if (this.previousBookmark === this.currentBookmark) {
    return null;
   }
  } else if (this.current.page || onlyCheckPage) {
   if (this.previousPage === this.currentPage) {
    return null;
   }
  } else {
   return null;
  }
  var params = {
   hash: this.currentBookmark,
   page: this.currentPage
  };
  if (this.isViewerInPresentationMode) {
   params.hash = null;
  }
  return params;
 },
 _stateObj: function pdfHistory_stateObj(params) {
  return {
   fingerprint: this.fingerprint,
   uid: this.uid,
   target: params
  };
 },
 _pushToHistory: function pdfHistory_pushToHistory(params, addPrevious, overwrite) {
  if (!this.initialized) {
   return;
  }
  if (!params.hash && params.page) {
   params.hash = 'page=' + params.page;
  }
  if (addPrevious && !overwrite) {
   var previousParams = this._getPreviousParams();
   if (previousParams) {
    var replacePrevious = !this.current.dest && this.current.hash !== this.previousHash;
    this._pushToHistory(previousParams, false, replacePrevious);
   }
  }
  this._pushOrReplaceState(this._stateObj(params), overwrite || this.uid === 0);
  this.currentUid = this.uid++;
  this.current = params;
  this.updatePreviousBookmark = true;
 },
 _goTo: function pdfHistory_goTo(state) {
  if (!(this.initialized && this.historyUnlocked && this._isStateObjectDefined(state))) {
   return;
  }
  if (!this.reInitialized && state.uid < this.currentUid) {
   var previousParams = this._getPreviousParams(true);
   if (previousParams) {
    this._pushToHistory(this.current, false);
    this._pushToHistory(previousParams, false);
    this.currentUid = state.uid;
    window.history.back();
    return;
   }
  }
  this.historyUnlocked = false;
  if (state.target.dest) {
   this.linkService.navigateTo(state.target.dest);
  } else {
   this.linkService.setHash(state.target.hash);
  }
  this.currentUid = state.uid;
  if (state.uid > this.uid) {
   this.uid = state.uid;
  }
  this.current = state.target;
  this.updatePreviousBookmark = true;
  var currentHash = window.location.hash.substring(1);
  if (this.previousHash !== currentHash) {
   this.allowHashChange = false;
  }
  this.previousHash = currentHash;
  this.historyUnlocked = true;
 },
 back: function pdfHistoryBack() {
  this.go(-1);
 },
 forward: function pdfHistoryForward() {
  this.go(1);
 },
 go: function pdfHistoryGo(direction) {
  if (this.initialized && this.historyUnlocked) {
   var state = window.history.state;
   if (direction === -1 && state && state.uid > 0) {
    window.history.back();
   } else if (direction === 1 && state && state.uid < this.uid - 1) {
    window.history.forward();
   }
  }
 }
};
exports.PDFHistory = PDFHistory;