NLeSC/Cesium-NcWMS

View on GitHub
app/scripts/ncwmsservice/ncwms.service.js

Summary

Maintainability
F
4 days
Test Coverage
(function() {
  'use strict';

  function NcwmsService($q, $http, Messagebus) {
    this.ncWMSURL = 'http://localhost:8080/ncWMS-2.0-rc1-maartenvm/wms?';

    var deferred = $q.defer();
    this.ready = deferred.promise;

    this.ncWMSdata = {
      'metadata': {},
      'palettes': []
    };
    this.datasets = [];
    this.startDate = {};
    this.endDate = {};

    this.initialized = false;

    this.init = function() {
      // load JSON data
      $http.get('serverconfig.json').then(function(res) {
        if (res.data.id === 'ncWMS') {
          this.ncWMSURL = res.data.url;
        } else {
          console.log(res.data.url + ' is no valid server config, defaulting to: ' + this.ncWMSURL);
        }

        // Ask the server to give us the data we need to get started, in
        // this case an overview of the available datasets
        this.getMenu().then(function success(menuPromise) {
          // Build an array containing our datasets (--NG--)
          this.datasets = this.loadMenu(menuPromise);
          // Store the first dataset as our 'currently selected' dataset
          // (--NG--)
          Messagebus.publish('ncwmsDatasetSelected', this.datasets[0]);

          // Get the id of the first dataset we got from the server,
          // because we can
          // only get some information out of the server if we dig a
          // little deeper, and we need an ID to do just that.
          var firstDatasetID = menuPromise.data.children[0].children[0].id;

          // To get the server to give us the available palette names,
          // we use this first ID
          this.getMetadata(firstDatasetID).then(function success(firstDatasetMetaDataPromise) {
            // Store the palette names and image URL's. (--NG--)
            this.ncWMSdata.palettes = this.loadPalettes(firstDatasetID, firstDatasetMetaDataPromise.data.palettes);

            // Store the first palette we receive as the currently
            // selected palette. (--NG--)
            //me.selectedPalette = this.ncWMSdata.palettes[0];
            Messagebus.publish('ncwmsPaletteSelected', this.ncWMSdata.palettes[0]);
          }.bind(this), function error(msg) {
            console.log('Error in getMetadata, ' + msg);
          });

          // Define an array to store our waiting promises in
          var httpRequestPromises = [];

          // Do a new metadata request for every loaded dataset
          this.datasets.forEach(function(dataset) {
            var promise = this.getMetadata(dataset.id).then(function success(metaDataPromise) {
              var workingDataset = this.datasets[this.datasets.indexOf(dataset)];
              workingDataset.metaData = metaDataPromise.data;

              // Once the metadata request is resolved, store the
              // dates with
              // data in
              // the previously made datasets datastructure.
              var dates = [];
              if (metaDataPromise.data.supportsTimeseries) {
                for (var year in metaDataPromise.data.datesWithData) {
                  var monthArray = metaDataPromise.data.datesWithData[year];
                  for (var month in monthArray) {
                    var dayArray = monthArray[month];
                    for (var day in dayArray) {
                      dates.push(new Date(Date.UTC(year, month, dayArray[day], 0, 0, 0)));
                    }
                  }
                }
              }
              workingDataset.datesWithData = dates;

              // Store the scale ranges
              workingDataset.min = parseFloat(metaDataPromise.data.scaleRange[0]);
              workingDataset.max = parseFloat(metaDataPromise.data.scaleRange[1]);

              workingDataset.units = metaDataPromise.data.units;
            }.bind(this), function error(msg) {
              console.log('Error in getMetadata, ' + msg);
            });
            // Add this promise to the array of waiting promises.
            httpRequestPromises.push(promise);
          }.bind(this));

          // The $q service lets us wait for an array of promises to be
          // resolved
          // before continuing. We wait here until all the promises for
          // the metadata requests for each dataset are complete.
          $q.all(httpRequestPromises).then(function() {
            var dates = this.datasets[this.datasets.indexOf(this.datasets[0])].datesWithData;

            this.datasets.forEach(function(dataset) {
              var workingDataset = this.datasets[this.datasets.indexOf(dataset)];
              if (workingDataset.statsGroup) {
                //If this dataset is a statistics group, modify it's min and max to reflect the actual value represented.

                var id = workingDataset.id.split('/')[0];
                var ds1 = id + '/' + workingDataset.id.split('/')[1].split(':')[0];
                var ds2 = id + '/' + workingDataset.id.split('/')[1].split(':')[1].split('-')[0];

                workingDataset.graphicalMin = this.getDatasetByName(ds1).min;
                workingDataset.graphicalMax = this.getDatasetByName(ds1).max + this.getDatasetByName(ds2).max;
              }
            }.bind(this));

            this.startDate = dates[0];
            this.endDate = dates[this.datasets[this.datasets.indexOf(this.datasets[0])].datesWithData.length - 1];

            Messagebus.publish('timeFrameRedefined', {
              start: this.startDate,
              stop: this.endDate
            });

            Messagebus.publish('ncwmsUnitsChange', this.datasets[0].units);
            Messagebus.publish('legendMinChange', this.datasets[0].min);
            Messagebus.publish('legendMaxChange', this.datasets[0].max);

            if (this.datasets[0].graphicalMin !== 0) {
              Messagebus.publish('graphMinChange', this.datasets[0].graphicalMin);
              Messagebus.publish('graphMaxChange', this.datasets[0].graphicalMax);
            } else {
              Messagebus.publish('graphMinChange', this.datasets[0].min);
              Messagebus.publish('graphMaxChange', this.datasets[0].max);
            }

            deferred.resolve();
            this.initialized = true;
          }.bind(this));

        }.bind(this), function error(msg) {
          console.log('Error in getMenu, ' + msg);
        });
      }.bind(this));
    };

    this.getMenu = function() {
      return $http.get(this.ncWMSURL + 'item=menu&menu=&REQUEST=GetMetadata');
    };

    this.loadMenu = function(menuPromiseResolve) {
      var result = [];

      this.ncWMSdata.metadata = menuPromiseResolve.data.children;
      menuPromiseResolve.data.children.forEach(function(dataset) {
        var dataSetLabel = dataset.label;
        dataset.children.forEach(function(child) {
          if (child.plottable) {
            //Check if this is a ncwms stats_group
            if (child.id.indexOf('stats_group') > -1) {
              //This is a stats group, so we will infer the min and max from the first child
              result.push({
                id: child.id,
                label: dataSetLabel + '/' + child.label,
                statsGroup: true,
                datesWithData: {},
                min: 0.0,
                max: 0.0,
                units: {},
                graphicalMin: 0,
                graphicalMax: 0
              });
            } else {
              //Not a stats_group, but a normal dataset
              result.push({
                id: child.id,
                label: dataSetLabel + '/' + child.label,
                statsGroup: false,
                datesWithData: {},
                min: 0.0,
                max: 0.0,
                units: {},
                graphicalMin: 0,
                graphicalMax: 0
              });
            }
            if (child.children !== undefined) {
              child.children.forEach(function(grandChild) {
                if (grandChild.plottable) {
                  //The children of stats_groups are treated as normal datasets
                  result.push({
                    id: grandChild.id,
                    label: dataSetLabel + '/' + grandChild.label,
                    statsGroup: false,
                    datesWithData: {},
                    min: 0.0,
                    max: 0.0,
                    units: {},
                    graphicalMin: 0,
                    graphicalMax: 0
                  });
                }
              });
            }
          }
        });
      });

      return result;
    };

    this.getMetadata = function(id) {
      return $http.get(this.ncWMSURL + 'item=layerDetails&layerName=' + id + '&REQUEST=GetMetadata');
    };

    this.loadPalettes = function(id, res) {
      var result = [];

      res.forEach(function(paletteName) {
        var imgURL2 = this.ncWMSURL + 'REQUEST=GetLegendGraphic&LAYER=' + id + '&COLORBARONLY=true&WIDTH=10&HEIGHT=150&NUMCOLORBANDS=250&PALETTE=' + paletteName;

        result.push({
          name: paletteName,
          graphic: imgURL2
        });
      }.bind(this));

      return result;
    };

    this.getSupportedTimesInISOFormat = function(selectedDataset) {
      var times = [];
      this.datasets[this.datasets.indexOf(selectedDataset)].datesWithData.forEach(function(date) {
        times.push(date.toISOString());
      });

      return times;
    };

    this.getFeatureInfoSeries = function(selectedDataset, selectedPalette, boundingRect, callbackSuccess, callbackFailure) {
      if (this.datasets.length === 0) {
        return;
      }

      var ltlo = boundingRect.leftTopLon;
      var ltla = boundingRect.leftTopLat;
      var rblo = boundingRect.rightBottomLon;
      var rbla = boundingRect.rightBottomLat;

      // Define an array to store our waiting promises in
      var httpRequestPromises = [];

      var times = this.getSupportedTimesInISOFormat(selectedDataset);

      times.forEach(function(time) {
        var promise = $http.get(this.ncWMSURL +
          'SERVICE=WMS' +
          '&VERSION=1.3.0' +
          '&REQUEST=GetFeatureInfo' +
          '&LAYERS=' + selectedDataset.id +
          '&QUERY_LAYERS=' + selectedDataset.id +
          '&STYLES=' + selectedDataset.metaData.supportedStyles[0] +
          '/' + selectedPalette.name +
          '&BBOX=' + ltlo.toFixed(6) + ',' + ltla.toFixed(6) + ',' + rblo.toFixed(6) + ',' + rbla.toFixed(6) +
          '&FEATURE_COUNT=2' +
          '&HEIGHT=100' +
          '&WIDTH=100' +
          '&FORMAT=image/png' +
          '&INFO_FORMAT=text/xml' +
          '&CRS=CRS:84' +
          '&I=50' +
          '&J=50' +
          '&TIME=' + time);
        httpRequestPromises.push(promise);
      }.bind(this));

      var parseXml;

      if (typeof window.DOMParser !== 'undefined') {
        parseXml = function(xmlStr) {
          return (new window.DOMParser()).parseFromString(xmlStr, 'text/xml');
        };
      } else if (typeof window.ActiveXObject !== 'undefined' && new window.ActiveXObject('Microsoft.XMLDOM')) {
        parseXml = function(xmlStr) {
          var xmlDoc = new window.ActiveXObject('Microsoft.XMLDOM');
          xmlDoc.async = 'false';
          xmlDoc.loadXML(xmlStr);
          return xmlDoc;
        };
      } else {
        throw new Error('No XML parser found');
      }

      $q.all(httpRequestPromises).then(function(res) {
        var graphInfo = [];

        res.forEach(function(individualResolve) {
          var xml = parseXml(individualResolve.data);

          var timeHTML = xml.getElementsByTagName('time')[0];
          var time;
          if (timeHTML !== undefined) {
            time = timeHTML.innerHTML;
          }
          var valueHTML = xml.getElementsByTagName('value')[0];
          var value;
          if (valueHTML !== undefined) {
            value = valueHTML.innerHTML;
          }
          var errorHTML = xml.getElementsByTagName('value')[1];
          var error;
          if (errorHTML !== undefined) {
            error = errorHTML.innerHTML;
          } else {
            error = 0;
          }

          var resLatHTML = xml.getElementsByTagName('latitude')[0];
          var resLat;
          if (resLatHTML !== undefined) {
            resLat = resLatHTML.innerHTML;
          }
          var resLonHTML = xml.getElementsByTagName('longitude')[0];
          var resLon;
          if (resLonHTML !== undefined) {
            resLon = resLonHTML.innerHTML;
          }

          if (time !== undefined && value !== undefined && error !== undefined && resLat !== undefined && resLon !== undefined) {
            graphInfo.push({
              'time': time.replace(new RegExp(/\+([0-9]{2}):([0-9]{2})/), '+$1$2'),
              'latitude': resLat,
              'longitude': resLon,
              'value': parseFloat(value),
              'error': parseFloat(error)
            });
          }

        });

        if (graphInfo !== undefined && graphInfo.length > 0) {
          callbackSuccess(graphInfo);
        } else {
          callbackFailure('No graph info could be derived');
        }
      }, function() {
        callbackFailure('The http requests failed');
      });
    };

    this.getDatasetByName = function(datasetName) {
      var result;
      this.datasets.forEach(function(dataset) {
        if (dataset.id === datasetName) {
          result = dataset;
        }
      });
      return result;
    };
  }

  angular.module('eWaterCycleApp.ncwms').service('NcwmsService', NcwmsService);
})();