text: 'use strict';
  
  /**
   * @ignore
   * @suppress {duplicate}
   */
  var fs = require('fs');
  
  /**
   * @ignore
   * @suppress {duplicate}
   */
  var path = require('path');
  
  /**
   * @ignore
   * @suppress {duplicate}
   */
  var Q = require('q');
  
  /**
   * @ignore
   * @suppress {duplicate}
   */
  var utils = require('./utils.js');
  
  /**
   * @type {WarningsFilterProcessor}
   */
  var instance;
  
  /**
   * Instantiates a {@link WarningsFilterProcessor} object.
   *
   * @classdesc This class contains all filters from the registered warnings filter files. Further it filters out all
   * messages that are catched by any registered filter.
   *
   * @constructor
   *
   * @param {number} code The return code of the GCC process.
   */
  function WarningsFilterProcessor (code) {
      this._registry = {};
      this._code = code;
  }
  
  /**
   * Register a warnings filter file to this object.
   *
   * @returns {Promise} A promise that will be resolved in case of success and rejected in case of an error.
   * @param {string} pathToFile The file path of the warnings filter file that willm be registered to this instance.
   */
  WarningsFilterProcessor.prototype.registerWarningsFilterFile = function (pathToFile) {
      var resolvedPathToFile = path.resolve(pathToFile);
      var self = this;
      var defered = Q.defer();
      if (Object.keys(this._registry).indexOf(resolvedPathToFile) !== -1) {
          defered.resolve(self);
          return defered.promise;
      }
      fs.readFile(resolvedPathToFile, 'utf8', function (err, data) {
          if (err) {
              defered.reject(err);
          } else {
              self._registry[resolvedPathToFile] = data.split('\n').filter(function (line) {
                  return line.trim().length !== 0;
              });
              defered.resolve(self);
          }
      });
      return defered.promise;
  };
  
  /**
   * Get all defined warning filters from the passed warnings filter file paths.
   *
   * @returns {Array<string>} An array of filters defined by the warnings filter files represented by the given file
   *          paths.
   * @param {Array<string>} pathsToFiles A collection of file paths to the warning filter files.
   * @throws {Error} Thrown in case pathsToFiles is not an array.
   */
  WarningsFilterProcessor.prototype.getFilters = function (pathsToFiles) {
      if (pathsToFiles !== undefined && pathsToFiles !== null && !Array.isArray(pathsToFiles)) {
          throw new Error('"pathsToFiles" must be an array!');
      }
      var self = this;
      return utils
          .arrayToSet((pathsToFiles || [])
                      .map(function (pathToFile) {
                          return path.resolve(pathToFile);
                      })
                      .reduce(function (accumulator, currentPath) {
                          if (!Object.prototype.hasOwnProperty.call(self._registry, currentPath)) {
                              throw new Error('The warnings filter file "' + currentPath + '" is not known!');
                          }
                          Array.prototype.push.apply(accumulator, self._registry[currentPath]);
                          return accumulator;
                      }, []));
  };
  
  /**
   * Processes all passed messages and filters out all warnings that are catched by any filter defined in a corresponding
   * warnigns filter file.
   *
   * @returns {Array<GCCMessage>} The resulting collection of messages.
   * @param {Array<GCCMessage>} messages The original collection of messages generated by the GCC on stderr.
   * @param {Array<string>} pathsToFiles A collection of file paths to warnigns filter files.
   * @throws {Error} Thrown in case of bad arguments.
   */
  WarningsFilterProcessor.prototype.processMessages = function (messages, pathsToFiles) {
      if (messages !== undefined && messages !== null && !Array.isArray(messages)) {
          throw new Error('"messages" must be an Array!');
      }
      if (pathsToFiles !== undefined && pathsToFiles !== null && !Array.isArray(pathsToFiles)) {
          throw new Error('pathsToFiles" must be an Array!');
      }
      var filters = this.getFilters(pathsToFiles);
      var results = (messages || [])
          .filter(function (message) {
              return !message.isWarning() || filters.indexOf(message.getHeading()) === -1;
          });
      if (results.length !== 0 && results[results.length - 1].isStatus()) {
          results[results.length - 1].setWarningsCount(results.length - 1);
          results[results.length - 1].setFilteredWarningsCount(messages.length - results.length);
      }
      if (results.length === 1 && results[0].isStatus()) results = [];
      return results;
  };
  
  /**
   * A factory function for the type {@link WarningsFilterProcessor}. The factory method ensures that there is only one
   * instance of {@link WarningsFilterProcessor}, so it is realized as a singleton.
   *
   * @returns {WarningsFilterProcessor} The created {@link WarningsFilterProcessor} instance.
   * @param {number} code The return code of the GCC process.
   * @throws {Error} Thrown in case the parameter code is not a number.
   */
  function getWarningsFilterProcessor (code) {
      if ((typeof code) !== 'number') throw new Error('"code" must be a number!');
      if (instance) {
          instance._code = code;
          return instance;
      } else {
          instance = new /** @type {function(new:WarningsFilterProcessor, number)} */ (WarningsFilterProcessor)(code);
          return instance;
      }
  }
  
  module.exports = getWarningsFilterProcessor;
  