/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
/* jshint node:true */
'use strict';

var windowObject_ =
    typeof window === 'undefined' ? Object.create(null) : window;

module.exports = {
  /**
   * Converts a string to an XML document. For internal use only.
   *
   * @function xmlFromString
   * @private
   * @param {string}
   *            str The string to convert.
   * @returns {string} The XML document from the conversion.
   */
  xmlFromString: function(str) {
    if (windowObject_.ActiveXObject) {
      // Remove null terminating character if exists
      var strNoNull = str.replace(/\x00+$/, '');

      var xmlDoc = new windowObject_.ActiveXObject('Microsoft.XMLDOM');
      xmlDoc.async = false;
      xmlDoc.loadXML(strNoNull);

      return xmlDoc;
    } else if (typeof windowObject_.DOMParser !== 'undefined') {
      return (new windowObject_.DOMParser()).parseFromString(str, 'text/xml');
    } else {
      // No native parser, use a JS one.
      var DOMParser = require('xmldom').DOMParser;
      return new DOMParser().parseFromString(str, 'text/xml');
    }
  },

  /**
   * Converts an XML document to a string. For internal use only.
   *
   * @function xmlToString
   * @private
   * @param {string}
   *            xmlDoc xml document to convert, as string.
   * @param {boolean}
   *            removeSelfClosingTags removes self closing tags to explicit
   *            tags. Example: <tag/> to <tag></tag>
   * @returns {string} The string from the conversion.
   */
  xmlToString: function(xmlDoc, removeSelfClosingTags) {
    var result = this.xmlToStringIeCompatible(xmlDoc);

    if (removeSelfClosingTags) {
      result = this.xmlRemoveSelfClosingTags(result);
    }

    return result;
  },

  /**
   * Removes all self-closing tags from some XML data. For internal use only.
   *
   * @function xmlRemoveSelfClosingTags
   * @private
   * @param {string}
   *            data The XML data before removing the tags.
   * @returns {string} The XML data after removing the tags.
   */
  xmlRemoveSelfClosingTags: function(data) {
    var split = data.split('/>');
    var newXml = '';
    for (var i = 0; i < split.length - 1; i++) {
      var edsplit = split[i].split('<');
      newXml +=
          split[i] + '></' + edsplit[edsplit.length - 1].split(' ')[0] + '>';
    }

    return newXml + split[split.length - 1];
  },

  /**
   * Converts an XML document to an IE compatible string. For internal use
   * only.
   *
   * @function xmlToStringIeCompatible
   * @private
   * @param {string}
   *            data The XML document to convert.
   * @returns {string} The IE compatible string.
   */
  xmlToStringIeCompatible: function(xmlNode) {
    if (windowObject_.XMLSerializer) {
      return (new windowObject_.XMLSerializer()).serializeToString(xmlNode);
    } else if (xmlNode.xml) {
      return xmlNode.xml;
    } else {
      var XMLSerializer = require('xmldom').XMLSerializer;
      return new XMLSerializer().serializeToString(xmlNode);
    }
  },

  /**
   * Removes all newline characters from some data. For internal use only.
   *
   * @function removeNewLineChars
   * @private
   * @param {string}
   *            data data from which to remove all newline characters, as
   *            string.
   * @returns {string} data with all newline characters removed, as string.
   */
  removeNewLineChars: function(data) {
    return data.replace(/(\r\n|\n|\r)/gm, '');
  },

  /**
   * Removes all carriage return characters from some data. For internal use
   * only.
   *
   * @param data
   *            Data from which to remove all carriage return characters, as
   *            string.
   * @return Data with all carriage return characters removed, as string.
   */
  removeCarriageReturnChars: function(data) {
    return data.replace(/\r/gm);
  },

  /**
   * Removes the null terminating character from some data. For internal use
   * only.
   *
   * @function removeNullTerminatingChar
   * @private
   * @param {string}
   *            data Data from which to remove the null terminating character,
   *            as string.
   * @returns {string} data with null terminating character removed, as
   *          string.
   */
  removeNullTerminatingChar: function(data) {
    return data.replace(/\x00+$/, '');
  },

  /**
   * Removes the XML header from a string representing an XML. For internal
   * use only.
   *
   * @function removeXmlHeaderFromString
   * @private
   * @param data
   *            The XML string from which to remove the XML header.
   * @return XML string with the XML header removed.
   */
  removeXmlHeaderFromString: function(data) {
    return data.replace('<?xml version="1.0" encoding="UTF-8"?>', '');
  },

  /**
   * Removes the signature node from a string representing an XML. For
   * internal use only.
   *
   * @function removeXmlSignature
   * @private
   * @param data
   *            The XML string from which to remove the signature node.
   * @return XML string with the signature node removed.
   */
  removeXmlSignature: function(data) {
    return data.replace(/<Signature[\s\S]*?Signature>/g, '');
  }
};
