text: 'use strict';
  
  /*global require*/
  var CatalogItem = require('./CatalogItem');
  var defined = require('terriajs-cesium/Source/Core/defined');
  var defineProperties = require('terriajs-cesium/Source/Core/defineProperties');
  var GeoJsonCatalogItem = require('./GeoJsonCatalogItem');
  var inherit = require('../Core/inherit');
  var knockout = require('terriajs-cesium/Source/ThirdParty/knockout');
  var loadXML = require('terriajs-cesium/Source/Core/loadXML');
  var proxyCatalogItemUrl = require('./proxyCatalogItemUrl');
  var ShortReportSection = require('./ShortReportSection');
  var URI = require('urijs');
  var when = require('terriajs-cesium/Source/ThirdParty/when');
  var xml2json = require('../ThirdParty/xml2json');
  var createCatalogMemberFromType = require('./createCatalogMemberFromType');
  
  /**
   * A catalog item representing the result of invoking a web processing service (WPS).
   *
   * @alias WebProcessingServiceCatalogItem
   * @constructor
   * @extends CatalogItem
   *
   * @param {Terria} terria The Terria instance.
   */
  function WebProcessingServiceCatalogItem(terria) {
      CatalogItem.call(this, terria);
  
      this._geoJsonItem = undefined;
  
      /**
       * Gets or sets the parameters to the WPS function.
       * All parameter names must be entered in lowercase in order to be consistent with references in TerrisJS code.
       * @type {FunctionParameter[]}
       */
      this.parameters = undefined;
  
      /**
       * Gets or sets the values of the parameters that were used to invoke this function.
       * @type {Object}
       */
      this.parameterValues = undefined;
  
      /**
       * Gets or sets the URL of the WPS completed response.  This property is ignored if
       * {@link WebProcessingServiceCatalogItem#wpsResponse} is defined.  This property is observable.
       * @type {String}
       */
      this.wpsResponseUrl = undefined;
  
      /**
       * Gets or sets the completed WPS response, as either XML or the result of passing the
       * XML through {@link xml2json}.
       * @type {Object|Document}
       */
      this.wpsResponse = undefined;
  
      knockout.track(this, ['wpsResponseUrl', 'wpsResponse']);
  }
  
  inherit(CatalogItem, WebProcessingServiceCatalogItem);
  
  defineProperties(WebProcessingServiceCatalogItem.prototype, {
      /**
       * Gets the type of data member represented by this instance.
       * @memberOf WebProcessingServiceCatalogItem.prototype
       * @type {String}
       */
      type : {
          get : function() {
              return 'wps-result';
          }
      },
  
      /**
       * Gets a human-readable name for this type of data source, 'Web Processing Service Result'.
       * @memberOf WebProcessingServiceCatalogItem.prototype
       * @type {String}
       */
      typeName : {
          get : function() {
              return 'Web Processing Service Result';
          }
      },
  
      /**
       * Gets the data source associated with this catalog item.
       * @memberOf WebProcessingServiceCatalogItem.prototype
       * @type {DataSource}
       */
      dataSource : {
          get : function() {
              return defined(this._geoJsonItem) ? this._geoJsonItem.dataSource : undefined;
          }
      }
  });
  
  WebProcessingServiceCatalogItem.prototype._getValuesThatInfluenceLoad = function() {
      return [this.wpsResponseUrl, this.wpsResponse];
  };
  
  WebProcessingServiceCatalogItem.prototype._load = function() {
      if (defined(this._geoJsonItem)) {
          this._geoJsonItem._hide();
          this._geoJsonItem._disable();
          this._geoJsonItem = undefined;
      }
  
      var that = this;
      return getGeoJson(this).then(function(geojson) {
          var wpsResponsePromise;
          if (defined(that.wpsResponse)) {
              wpsResponsePromise = when(that.wpsResponse);
          } else {
              wpsResponsePromise = loadXML(proxyCatalogItemUrl(that, that.wpsResponseUrl, '1d'));
          }
  
          return wpsResponsePromise.then(function(xmlOrJson) {
              var json;
              if (xmlOrJson instanceof Document) {
                  json = xml2json(xmlOrJson);
              } else {
                  json = xmlOrJson;
              }
  
              var processOutputs = json.ProcessOutputs;
  
              if (!defined(processOutputs)) {
                  return;
              }
  
              var outputs = processOutputs.Output;
              if (!defined(outputs)) {
                  return;
              } else if (!Array.isArray(outputs)) {
                  outputs = [outputs];
              }
  
              for (var i = 0; i < outputs.length; ++i) {
                  if (!defined(outputs[i].Data)) {
                      continue;
                  }
  
                  // skip process contexts
                  if (defined(outputs[i].Identifier) && outputs[i].Identifier === '.context') {
                      continue;
                  }
  
                  if (defined(outputs[i].Data.LiteralData)) {
                      that.shortReportSections.push(new ShortReportSection({
                          name: outputs[i].Title,
                          content: formatOutputValue(outputs[i].Title, outputs[i].Data.LiteralData)
                      }));
                  } else if (defined(outputs[i].Data.ComplexData)) {
                      var content = outputs[i].Data.ComplexData;
                      if (outputs[i].Data.ComplexData.mimeType === 'text/csv') {
                          content = '<collapsible title="' + outputs[i].Title + '" open="' + (i === 0 ? 'true' : 'false') + '">';
                          content += '<chart can-download="true" hide-buttons="false" title="' + outputs[i].Title + '" data=\'' + outputs[i].Data.ComplexData + '\' styling="histogram"></chart>';
                          content += '</collapsible>';
                      } else if (outputs[i].Data.ComplexData.mimeType === 'application/vnd.terriajs.catalog-member+json') {
                          content = 'Chart ' + outputs[i].Title + ' generated.';
                          var jsonCatalogItem = JSON.parse(outputs[i].Data.ComplexData.text);
                          var catalogItem = createCatalogMemberFromType(jsonCatalogItem.type, that.terria);
                          catalogItem.updateFromJson(jsonCatalogItem);
                      }
  
                      that.shortReportSections.push(new ShortReportSection({
                          content: content
                      }));
                  }
              }
  
              var inputsSection =
                  '<table class="cesium-infoBox-defaultTable">' +
                  (that.parameters || []).reduce(function(previousValue, parameter) {
                      return previousValue +
                          '<tr>' +
                              '<td style="vertical-align: middle">' + parameter.name + '</td>' +
                              '<td style="padding-left: 4px">' + parameter.formatValueAsString(that.parameterValues[parameter.id]) + '</td>' +
                          '</tr>';
                  }, '') +
                  '</table>';
  
              var outputsSection =
                  '<table class="cesium-infoBox-defaultTable">' +
                  (outputs || []).reduce(function(previousValue, output) {
                      if (!defined(output.Data) || (!defined(output.Data.LiteralData) && !defined(output.Data.ComplexData))) {
                          return previousValue;
                      }
                      var content = "";
                      if (defined(output.Data.LiteralData)) {
                          content = formatOutputValue(output.Title, output.Data.LiteralData);
                      } else if (defined(output.Data.ComplexData)) {
                          if (output.Data.ComplexData.mimeType === 'text/csv' ) {
                              content = '<chart can-download="true" hide-buttons="false" title="' + output.Title + '" data=\'' + output.Data.ComplexData + '\' styling: "feature-info">';
                          }
                          else if (output.Data.ComplexData.mimeType === 'application/vnd.terriajs.catalog-member+json') {
                              content = 'Chart ' + output.Title + ' generated.';
                          }
                          // Support other types of ComplexData here as it becomes necessary.
                      }
  
                      return previousValue +
                          '<tr>' +
                              '<td style="vertical-align: middle">' + output.Title + '</td>' +
                              '<td>' + content + '</td>' +
                          '</tr>';
                  }, '') +
                  '</table>';
  
              var section = that.findInfoSection('Inputs');
              if (!defined(section)) {
                  that.info.push({
                      name: 'Inputs',
                      content: inputsSection
                  });
              }
  
              if (!defined(that.featureInfoTemplate)) {
                  that.featureInfoTemplate =
                      '#### Inputs\n\n' +
                      inputsSection + '\n\n' +
                      '#### Outputs\n\n' +
                      outputsSection;
              }
  
              if (defined(geojson)) {
                  that._geoJsonItem = new GeoJsonCatalogItem(that.terria);
                  that._geoJsonItem.name = that.name;
                  that._geoJsonItem.data = geojson;
                  return that._geoJsonItem.load().then(function() {
                      if (!defined(that.rectangle)) {
                          that.rectangle = that._geoJsonItem.rectangle;
                      }
                  });
              }
          });
      });
  };
  
  WebProcessingServiceCatalogItem.prototype._enable = function() {
      if (defined(this._geoJsonItem)) {
          this._geoJsonItem._enable();
      }
  };
  
  WebProcessingServiceCatalogItem.prototype._disable = function() {
      if (defined(this._geoJsonItem)) {
          this._geoJsonItem._disable();
      }
  };
  
  WebProcessingServiceCatalogItem.prototype._show = function() {
      if (defined(this._geoJsonItem)) {
          this._geoJsonItem._show();
      }
  };
  
  WebProcessingServiceCatalogItem.prototype._hide = function() {
      if (defined(this._geoJsonItem)) {
          this._geoJsonItem._hide();
      }
  };
  
  function formatOutputValue(title, value) {
      if (!defined(value)) {
          return '';
      }
  
      var values = value.split(',');
  
      return values.reduce(function(previousValue, currentValue) {
          if (value.match(/[.\/](png|jpg|jpeg|gif|svg)/i)) {
              return previousValue + '<a href="' + currentValue + '"><img src="' + currentValue + '" alt="' + title + '" /></a>';
          } else if (currentValue.indexOf('http:') === 0 || currentValue.indexOf('https:') === 0) {
              var uri = new URI(currentValue);
              return previousValue + '<a href="' + currentValue + '">' + uri.filename() + '</a>';
          } else {
              return previousValue + currentValue;
          }
      }, '');
  }
  
  function getGeoJson(catalogItem) {
      if (!defined(catalogItem.parameters) || !defined(catalogItem.parameterValues)) {
          return when(undefined);
      }
      var features = [];
  
      for (var i=0; i<catalogItem.parameters.length; i++) {
          if (typeof catalogItem.parameters[i].getGeoJsonFeature === 'function') {
              var potentialFeature = catalogItem.parameters[i].getGeoJsonFeature(catalogItem.parameterValues[catalogItem.parameters[i].id]);
              if (defined(potentialFeature)) {
                  if (potentialFeature instanceof Array) {
                      features = features.concat(potentialFeature);
                  } else {
                      features.push(potentialFeature);
                  }
              }
          }
      }
      return when.all(features).then(function(results) {
          var geojson = {
              "type":"FeatureCollection",
              "features": results,
              "totalFeatures": results.length
          };
          return geojson;
      });
  }
  
  module.exports = WebProcessingServiceCatalogItem;
  