text: import Configuration from './configuration.js';
  import EditorListener from './editorlistener.js';
  import Listeners from './listeners.js';
  import MathML from './mathml.js';
  import Util from './util.js';
  
  /**
   * This class represents the content of a ModalDialog class managing the following:
   * - Insertion in the ModalDialog.
   * - Actions to be done once the modal object has been submitted (submitAction() method).
   * - Updates itself when ModalDialog is updated, for example when ModalDialog
   *   is re-opened (update(modalObject) method).
   * - Communicates ModalDialog if some changes have be done (hasChanges() method).
   */
  export default class ContentManager {
      /**
       * Class constructor
       * @param {Object} contentManagerAttributes - Object containing all attributes needed to
       * create a new instance of ContentManager class.
       * @param {Object} contentManagerAttributes.editorAttributes - Object containing MathType editor parameters.
       */
      constructor(contentManagerAttributes) {
          /**
           * An object containing MathType editor parameters. See
           * http://docs.wiris.com/en/mathtype/mathtype_web/sdk-api/parameters for further information.
           * @type {Object}
           */
          this.contentManagerAttributes = {};
          if ('editorAttributes' in contentManagerAttributes) {
              this.editorAttributes = contentManagerAttributes.editorAttributes;
          } else {
              throw new Error('ContentManager constructor error: editorAttributes property missed.')
          }
  
          /**
           * CustomEditors instance. Contains the custom editors.
           * @type {CustomEditors}
           */
          this.customEditors = null;
          if ('customEditors' in contentManagerAttributes) {
              this.customEditors = contentManagerAttributes.customEditors;
          }
  
          /**
  		* Environment properties. This object contains data about the integration platform.
  		* @type {Object}
  		* @property {string} editor - Editor name. Usually the HTML editor.
  		* @property {string} mode - Save mode. Xml by default
  		* @property {string} version - Plugin version.
  	    */
         this.environment = {};
         if ('environment' in contentManagerAttributes) {
              this.environment = contentManagerAttributes.environment;
         } else {
              throw new Error('ContentManager constructor error: environment property missed');
         }
  
         /**
           * ContentManager language.
           * @type {string}
           */
          this.language = '';
          if ('language' in contentManagerAttributes) {
              this.language = contentManagerAttributes.language;
          } else {
              throw new Error('ContentManager constructor error: language property missed');
          }
  
           /**
           * Editor listener. Needed to get control about editor changes.
           * @type {EditorListener}
           */
          this.editorListener = new EditorListener();
  
          /**
           * MathType editor instance.
           * @type {JsEditor}
           */
          this.editor = null;
  
          /**
           * Navigator user agent.
           * @type {string}
           */
          this.ua = navigator.userAgent.toLowerCase();
  
          /**
           * Mobile device properties object
           * @type {Object}
           * @property {boolean} isAndroid - True if the device is android. False otherwise.
           * @property {boolean} isIOS - True if the device is iOS. False otherwise.
           */
          this.deviceProperties = {};
          this.deviceProperties.isAndroid = this.ua.indexOf("android") > -1;
          this.deviceProperties.isIOS = ((this.ua.indexOf("ipad") > -1) || (this.ua.indexOf("iphone") > -1));
  
          /**
           * Custom editor toolbar.
           * @type {string} toolbar
           */
          this.toolbar = null;
  
          /**
           * Instance of the ModalDialog class associated to the ContentManager instance.
           * @type {ModalDialog}
           */
          this.modalDialogInstance = null;
  
          /**
           * ContentManager listeners.
           * @type {Listeners}
           */
          this.listeners = new Listeners();
  
          /**
           * MathML associated to the ContentManager instance.
           * @type {string}
           */
          this.mathML = null;
  
          /**
           * Indicates if the edited element is a new element or not.
           * @type {boolean}
           */
          this.isNewElement = true;
  
          /**
           * IntegrationModel instance. Needed to call wrapper methods.
           * @type {IntegrationModel}
           */
          this.integrationModel = null;
  
          /**
           * Indicates if the editor is loaded.
           * @type {boolean}
           */
          this.isEditorLoaded = false;
      }
  
      /**
       * Add a new listener to ContentManager class.
       * @param {Object} listener - listener to be added.
       */
      addListener(listener) {
          this.listeners.add(listener);
  
      }
  
      /**
       * Sets an instance of an IntegrationModel
       * @param {IntegrationModel} integrationModel
       */
      setIntegrationModel(integrationModel) {
          this.integrationModel = integrationModel;
      }
  
      /**
       * Sets a modal dialog instance.
       * @param {ModalDialog} - a ModalDialog instance
       */
      setModalDialogInstance(modalDialogInstance) {
          this.modalDialogInstance = modalDialogInstance;
      }
  
      /**
       * Mandatory method. Inserts editor into modal object content container.
       */
      insert() {
          // Before insert the editor we update the modal object title to avoid weird render display.
          this.updateTitle(this.modalDialogInstance);
          this.insertEditor(this.modalDialogInstance);
      }
  
      /**
       * Method to insert MathType into modal object. This method
       * waits until editor JavaScript is loaded to insert the editor into
       * contentContainer modal object element.
       */
      insertEditor() {
          // To know if editor JavaScript is loaded we need to wait until com.wiris.jsEditor namespace is ready.
          if ('com' in window && 'wiris' in window.com && 'jsEditor' in window.com.wiris) {
              this.editor = com.wiris.jsEditor.JsEditor.newInstance(this.editorAttributes);
              this.editor.insertInto(this.modalDialogInstance.contentContainer);
              this.editor.focus();
              if (this.modalDialogInstance.rtl) {
                  this.editor.action('rtl');
              }
              // Setting div in rtl in case of it's activated.
              if (this.editor.getEditorModel().isRTL()) {
                  this.editor.element.style.direction = 'rtl';
              }
  
              // Editor listener: this object manages the changes logic of editor.
              this.editor.getEditorModel().addEditorListener(this.editorListener);
  
              // iOS events.
              if (this.modalDialogInstance.deviceProperties['isIOS']) {
                  setTimeout(function() { this.modalDialogInstance.hideKeyboard() }, 400);
                  var formulaDisplayDiv = document.getElementsByClassName('wrs_formulaDisplay')[0];
                  Util.addEvent(formulaDisplayDiv, 'focus', this.modalDialogInstance.handleOpenedIosSoftkeyboard);
                  Util.addEvent(formulaDisplayDiv, 'blur', this.modalDialogInstance.handleClosedIosSoftkeyboard);
              }
              // Fire onLoad event. Necessary to set the MathML into the editor
              // after is loaded.
              this.listeners.fire('onLoad', {});
              this.isEditorLoaded = true;
          } else {
              setTimeout(ContentManager.prototype.insertEditor.bind(this, this.modalDialogInstance), 100);
          }
      }
  
      /**
       * Loads MathType script.
       */
      init() {
          var queryParams = window.location.search.substring(1).split("&");
          for (var i = 0; i < queryParams.length; i++) {
              var pos = queryParams[i].indexOf("v=");
              if (pos >= 0) {
                  version = queryParams[i].substring(2);
              }
          }
  
          var script = document.createElement('script');
          script.type = 'text/javascript';
          var editorUrl = Configuration.get('editorUrl');
          // We create an object url for parse url string and work more efficiently.
          var urlObject = document.createElement('a');
          urlObject.href = editorUrl;
  
          // Change to https if necessary.
          if (window.location.href.indexOf("https://") == 0) {
              // It check if browser is https and configuration is http. If this is so, we will replace protocol.
              if (urlObject.protocol == 'http:') {
                  urlObject.protocol = 'https:';
              }
          }
  
          // Check protocol and remove port if it's standard.
          if (urlObject.port == '80' || urlObject.port == '443') {
              editorUrl = urlObject.protocol + '//' + urlObject.hostname + '/' + urlObject.pathname;
          } else {
              editorUrl = urlObject.protocol + '//' + urlObject.hostname + ':' + urlObject.port + '/' + urlObject.pathname;
          }
  
          // Editor stats. Use environment property to set it.
          var stats = {};
          if ('editor' in this.environment) {
              stats.editor = this.environment.editor;
          } else {
              stats.editor = 'unknown';
          }
  
          if ('mode' in this.environment) {
              stats.mode = this.environment.mode;
          } else {
              stats.mode = Configuration.get('saveMode');
          }
  
          if ('version' in this.environment) {
              stats.version = this.environment.version;
          } else {
              stats.version = Configuration.get('version');
          }
  
          // Load editor URL. We add stats as GET params.
          script.src = editorUrl +
                      "?lang=" + this.language +
                       '&stats-editor=' + stats.editor +
                       '&stats-mode=' + stats.mode +
                       '&stats-version=' + stats.version;
  
          document.getElementsByTagName('head')[0].appendChild(script);
      }
  
      /**
      * Set the editor initial content: an existing formula or a blank MathML
      */
      setInitialContent() {
          if (!this.isNewElement) {
              this.setMathML(this.mathML);
          }
      }
  
      /**
       * Set a MathML into editor.
       * @param {string} mathml - MathML string.
       * @param {bool} focusDisabled - if true editor don't get focus after the MathML is set. false by default.
       */
      setMathML(mathml, focusDisabled) {
          // By default focus is enabled
          if (typeof focusDisabled === 'undefined') {
              focusDisabled = false;
          }
          // Using setMathML method is not a change produced by the user but for the API
          // so we set to false the contentChange property of editorListener.
          this.editor.setMathMLWithCallback(mathml, function() {
              this.editorListener.setWaitingForChanges(true);
          }.bind(this));
          // We need to wait a little until the callback finish.
          setTimeout(function(){
              this.editorListener.setIsContentChanged(false);}.bind(this), 500);
  
          // In some scenarios - like closing modal object - editor mustn't be focused.
          if (!focusDisabled){
              this.onFocus();
          }
      }
  
      /**
       * Set focus on editor.
       */
      onFocus() {
          if (typeof this.editor !== 'undefined' && this.editor != null) {
              this.editor.focus();
          }
      }
  
      /**
       * Mandatory method: modal object calls this method to execute a callback action
       * on submit.
       * This method updates the edition area (inserting a new formula or update an older one),
       * and focus the edition area too.
       */
      submitAction() {
          if (!this.editor.isFormulaEmpty()) {
              let mathML = this.editor.getMathMLWithSemantics();
              // Add class for custom editors.
              if (this.customEditors.getActiveEditor() != null) {
                  mathML = MathML.addCustomEditorClassAttribute(mathML, this.customEditors.getActiveEditor().toolbar);
              } else {
                  // We need - if exists - the editor name from MathML
                  // class attribute.
                  for (const key in this.customEditors.editors) {
                      mathML = MathML.removeCustomEditorClassAttribute(mathML, key);
                  }
              }
              const mathmlEntitiesEncoded = MathML.mathMLEntities(mathML);
              this.integrationModel.updateFormula(mathmlEntitiesEncoded);
          }
          else {
              this.integrationModel.updateFormula(null);
          }
  
          this.customEditors.disable();
          this.integrationModel.notifyWindowClosed();
  
          // Set disabled focus to prevent lost focus.
          this.setEmptyMathML();
          this.customEditors.disable();
      }
  
      /**
       * Set an empty MathML into the editor in order to clean the edit area.
       */
      setEmptyMathML() {
          // As second argument we pass
          if (this.deviceProperties.isAndroid || this.deviceProperties.isIOS) {
              // We need to set a empty annotation in order to maintain editor in Hand mode.
              // Adding dir rtl in case of it's activated.
              if (this.editor.getEditorModel().isRTL()) {
                  this.setMathML('<math dir="rtl"><semantics><annotation encoding="application/json">[]</annotation></semantics></math>"', true);
              } else {
                  this.setMathML('<math><semantics><annotation encoding="application/json">[]</annotation></semantics></math>"', true);
              }
          } else {
              if (this.editor.getEditorModel().isRTL()) {
                  this.setMathML('<math dir="rtl"/>', true);
              } else {
                  this.setMathML('<math/>', true);
              }
          }
      }
  
      /**
       * Mandatory method: modal object calls this method when is updated, for example re-editing a formula when the
       * editor is open with another formula. This method updates the editor content (with an empty MathML or an existing formula),
       * updates - if needed - the editor toolbar (math --> chem or chem --> math) and recover the focus.
       */
      onOpen() {
          if (this.isNewElement) {
              this.setEmptyMathML();
          }
          else {
              this.setMathML(this.mathML);
          }
          this.updateToolbar();
          this.onFocus();
      }
  
      /**
       * Sets the correct toolbar depending if exist other custom toolbars at the same time (e.g: Chemistry)
       */
      updateToolbar() {
          this.updateTitle(this.modalDialogInstance);
          var customEditor;
          if (customEditor = this.customEditors.getActiveEditor()) {
              var toolbar = customEditor.toolbar ? customEditor.toolbar : _wrs_int_wirisProperties['toolbar'];
              if (this.toolbar == null || this.toolbar != toolbar) {
                  this.setToolbar(toolbar);
              }
          } else {
              var toolbar = this.getToolbar();
              if (this.toolbar == null || this.toolbar != toolbar) {
                  this.setToolbar(toolbar);
                  this.customEditors.disable();
              }
          }
      }
      /**
       * Updates the modalObject title: if a custom editor (with a custom toolbar) is enabled
       * picks the custom editor title. Otherwise default title.
       */
      updateTitle() {
          var customEditor;
          if (customEditor = this.customEditors.getActiveEditor()) {
              this.modalDialogInstance.setTitle(customEditor.title);
          } else {
              this.modalDialogInstance.setTitle('MathType');
          }
      }
      /**
       * Returns toolbar depending on the configuration local or server side.
       */
      getToolbar() {
          var toolbar;
  
          if ('toolbar' in this.editorAttributes) {
              toolbar = this.editorAttributes.toolbar;
          } else {
              toolbar = "general";
          }
          // TODO: Change global integration variable for integration custom toolbar
          if(toolbar == 'general'){
              toolbar = (typeof _wrs_int_wirisProperties == 'undefined' || typeof _wrs_int_wirisProperties['toolbar'] == 'undefined') ? 'general' : _wrs_int_wirisProperties['toolbar'];
          }
  
          return toolbar;
      }
  
      /**
       * Set a toolbar into editor.
       * @param {string} toolbar - toolbar name.
       */
      setToolbar(toolbar) {
          this.toolbar = toolbar;
          this.editor.setParams({'toolbar': this.toolbar});
      }
  
      /**
       * Returns true if the content of the editor has been changed. The logic of the changes
       * is delegated to editorListener object.
       */
      hasChanges() {
          return (!this.editor.isFormulaEmpty() && this.editorListener.getIsContentChanged());
      }
  }