"use strict";
/*global require*/
var CatalogItem = require("./CatalogItem");
var createGuid = require("terriajs-cesium/Source/Core/createGuid").default;
var defined = require("terriajs-cesium/Source/Core/defined").default;
var GeoJsonCatalogItem = require("./GeoJsonCatalogItem");
var inherit = require("../Core/inherit");
var knockout = require("terriajs-cesium/Source/ThirdParty/knockout").default;
var loadXML = require("../Core/loadXML");
var proxyCatalogItemUrl = require("./proxyCatalogItemUrl");
var ShortReportSection = require("./ShortReportSection");
var URI = require("urijs");
var when = require("terriajs-cesium/Source/ThirdParty/when").default;
var xml2json = require("../ThirdParty/xml2json");
var createCatalogMemberFromType = require("./createCatalogMemberFromType");
var i18next = require("i18next").default;
/**
* 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);
Object.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 i18next.t("models.webProcessingService.wpsResult");
}
},
/**
* 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);
// The server might return duplicate names and IDs derived from it will not be unique.
// So we force the id to a GUID.
catalogItem.id = createGuid();
}
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;