'use strict';
define(function() {
  var GlobalServices = function(
    FeatureTypeFactory,
    $q,
    ConfigFactory,
    FunctionFactory,
    $timeout,
     gaJsUtils
  ) {
    var resources = {
      globalValues: {},
      appKeyWordConfig: {},
    };


    /**
     *    Return date string ine the correct format for database field value.
     */
    function stringDateCorrectlyFormatted(value) {
      var indPos, year, month, day;

      indPos = value.indexOf('-');
      if (indPos == -1) indPos = value.indexOf('/');

      if (indPos == 4) {
        year = value.substr(0, 4);
        indPos = value.indexOf('-', 5);
        month = value.substr(5, indPos - 5);
        day = value.substr(indPos + 1, 2);
      } else if (indPos == 2) {
        year = value.substr(6, 4);
        month = value.substr(3, 2);
        day = value.substr(0, 2);
      }

      if (parseInt(month) > 12) {
        indPos = month;
        month = day;
        day = indPos;
      }
      return year + '-' + month + '-' + day + 'T12:00:00.000-0300';
    }

    /**
     *
     */
    function getAttributeIndex(desc, fieldName) {
      for (var ind1 = 0; ind1 < desc.attributes.length; ind1++)
        if (desc.attributes[ind1].name == fieldName) return ind1;
      return -1;
    }

    /**
     *        When necessary format the value in order to store it into the DataBase.
     */
    function getValueForDB(desc, fieldName, value, indAtt) {
      var ind1;

      ind1 = indAtt;

      if (ind1 == -1 || ind1 == undefined)
        ind1 = getAttributeIndex(desc, fieldName);
      if (ind1 != -1) {
        if (typeof value == 'boolean') return value;
        if (!desc.attributes[ind1].fieldTypeIsString && value == '')
          return null;
        if (
          desc.attributes[ind1].type != null &&
          desc.attributes[ind1].type.indexOf('.Date') != -1
        ) {
          if (value == undefined) return null;
          if (value.trim == undefined)
            //-- Date value is not a string so we assume it is a Date object.
            return (
              '' +
              value.getFullYear() +
              '-' +
              (1 + value.getMonth()) +
              '-' +
              value.getDate() +
              'T12:00:00.000+0200'
            );
          //-- Case of a date value stored as a string
          //-- there we ensure the string format is OK
          return stringDateCorrectlyFormatted(value);
          //return "2016-01-02T12:00:00.000+0000";
        }
        if (
          value != undefined &&
          value.trim !== undefined &&
          value.indexOf('!') != -1
        ) {
          var params;
          var obj = getValueForKeyWord(value, params);
          if (obj.done) return obj.newValue;
        }
      }

      if (value == undefined) return null;
      return value;
    }

    function initEditFeatures(featureCount) {
      if (featureCount === undefined) featureCount = 1;
      //-- Build GeoJSON object describing the object we want  to insert
      var features = {};
      features.type = 'FeatureCollection';
      features.features = [];
      for (var ind = 0; ind < featureCount; ind++) {
        features.features[ind] = {};
        features.features[ind].type = 'feature';
        features.features[ind].geometry = {};
        features.features[ind].properties = {};
      }

      return features;
    }

    /**
     *      Convert the date formatted as string gotten from database
     *  thru query services into a javascript date object.
     *  This is usefull in cases like:
     *   - setting bs date picker which works with Date Object.
     *   - comparing date values.
     */
    function getDateFromDbString(objFieldValue) {
      var strDate, dDate, ms;

      if (objFieldValue != null && objFieldValue.trim != undefined) {
        //-- Actually the date is a string ...
        //-- Betting the date has the expected JAVA GEoJSson format
        //-- convert it into a Date (format example: 2015-02-03T23:00:00.000+0000)
        strDate = objFieldValue;
        dDate = new Date();
        dDate.setFullYear(strDate.substr(0, 4));
        dDate.setMonth(strDate.substr(5, 2) - 1);
        dDate.setDate(strDate.substr(8, 2));
        dDate.setHours(strDate.substr(11, 2));
        dDate.setMinutes(strDate.substr(14, 2));
        dDate.setSeconds(strDate.substr(17, 2));
        //----- TODO Modify server side after better DATE managemen
        //-- Date returned is day-1 23H00 so we add 2 hours
        //-- (one should be enough ...) to display correct date.
        //-- In the DB the displayed date is OK.
        //-- When date will be better managed we'll get rid of this.
        ms = dDate.getTime() + 7200000; //  = 60 secondes x 1000 x 60 minutes x 2 heures
        dDate.setTime(ms);

        return dDate;
      }
      return null;
    }

    /**
     *       Convert a field value into a correct format for the user interface.
     *  The converted value is returned.
     */
    function formatFieldValueToStringForDisplaying(
      value,
      fieldDesc,
      fieldName
    ) {
      var ind;

      for (ind = 0; ind < fieldDesc.length; ind++)
        if (fieldDesc[ind].name == fieldName) break;
      if (ind < fieldDesc.length)
        switch (fieldDesc[ind].type) {
          case 'java.util.Date':
          case 'java.sql.Date':
            var dDate = getDateFromDbString(value);
            return dDate.toLocaleDateString();
            break;
          case 'java.sql.Boolean':
            if (value == 'true') return 'VRAI';
            else return 'FAUX';
            break;
        }
      return value;
    }

    /**
     *    Get configured keywords, which are values parameterd in the config files used by the application.
     *  First use is the direction name put in the queries.
     *  In the main/keywords file, there is the "directionForQuery" property, which
     *  the value we put instead of !DIRECTION_FOR_UPDATE! in the property searchFilter
     *  of module configuration.
     */
    function initialize() {
      var deferred = $q.defer();

      if (resources.appKeyWordConfig['directionNameForQuery'] == undefined)
        ConfigFactory.get('main', 'keywords').then(function(res) {
          resources.appKeyWordConfig = res.data;
        });
      else deferred.resolve('');

      return deferred.promise;
    }

    function getObjUsingQueriesBuildWhere(where, queryResult) {
      var whereRes, reg, ind, indN, val;

      //-- CURRENT_YEAR + N
      ind = where.indexOf('!CURRENT_YEAR!+');
      if (ind != -1) {
        indN = where.indexOf(' ', ind + 15);
        if (indN == -1) val = parseInt(where.substr(ind + 15));
        else val = parseInt(where.substr(ind + 15, indN - ind - 15));
        val += getCurrentYear();
        if (indN == -1) whereRes = where.substr(0, ind) + val;
        else whereRes = where.substr(0, ind) + val + where.substr(indN);
      } else whereRes = where;

      //-- Query key word CURRENT_YEAR replaced by current full year value such as 2015.
      reg = new RegExp('!CURRENT_YEAR!', 'g');
      whereRes = whereRes.replace(reg, '' + getCurrentYear());

      //-- Query key word CURRENT_YEAR replaced by current full year value such as 2015.
      reg = new RegExp('!DIRECTION_FOR_QUERY!', 'g');
      whereRes = whereRes.replace(
        reg,
        '' + resources.appKeyWordConfig['directionNameForQuery']
      );

      //-- Query key word result is replaced by previous query result value.
      if (queryResult == null) {
        reg = new RegExp('=!NULL!', 'g');
        whereRes = whereRes.replace(reg, ' is NULL');
        reg = new RegExp('<>!NULL!', 'g');
        whereRes = whereRes.replace(reg, ' is not NULL');
      } else {
        reg = new RegExp('!result!', 'g');
        whereRes = whereRes.replace(reg, queryResult);
      }

      return whereRes;
    }

    /**
     *     Literal value allows to get values such as a field value or
     *  system values such current date, current year or NULL.
     */
    function getValueForKeyWord(value, params) {
      var reg, ind1, ind2, ind1_1;

      //-- If the value is an object, it means that it is itself an expression to be evaluated
      if (value != undefined && value.trim === undefined)
        return {
          done: true,
          newValue: evaluateSimpleExpression(value, params),
        };

      //-- Query key word CURRENT_DATE replaced by current date as a date object.
      if (value == '!CURRENT_DATE!')
        return { done: true, newValue: getCurrentDate() };

      //-- Query key word CURRENT_YEAR replaced by current full year value such as 2015.
      if (value == '!CURRENT_YEAR!')
        return { done: true, newValue: getCurrentYear() };

      //-- Query key word CURRENT_YEAR and  + something.
      if (value.substr(0, 15) == '!CURRENT_YEAR!+')
        return {
          done: true,
          newValue: getCurrentYear() + parseInt(value.substr(15)),
        };

      //-- Query contains key word CURRENT_YEAR and  + something.
      ind1 = value.indexOf('!CURRENT_YEAR!+');
      if (ind1 != -1) {
        ind2 = ind1 + 15;
        while (ind2 < value.length && !isNaN(parseInt(value.substr(ind2, 1))))
          ind2++;
        value =
          value.substr(0, ind1) +
          (getCurrentYear() +
            parseInt(value.substr(ind1 + 15, ind2 - ind1 - 15))) +
          value.substr(ind2);
      }

      //-- Query contains key word CURRENT_DATE and  + something.
      ind1 = value.indexOf('!CURRENT_DATE!+');
      ind1_1 = value.indexOf('!CURRENT_DATE!-');
      if (ind1 == 0 || ind1_1 == 0) {
        var delta;
        ind1 = ind1_1;
        ind2 = ind1 + 16;
        while (ind2 < value.length && !isNaN(parseInt(value.substr(ind2, 1))))
          ind2++;
        delta = parseInt(value.substr(ind1 + 16, ind2 - ind1 - 16));
        if (value.substr(ind2 + 1, 3) == 'day') delta *= 3600000 * 24;
        if (ind1_1 == 0) delta = -delta;
        return { done: true, newValue: getCurrentDate(delta) };
      }

      //-- Query key word NULL is replaced by the null value.
      if (value == '!NULL!') return { done: true, newValue: null };

      if (params !== undefined) {
        //-- Is it a field value from the objectFields list of fields ?
        if (
          params.objectFields !== undefined &&
          params.objectFields[value] !== undefined
        )
          return { done: true, newValue: params.objectFields[value] };

        //-- Query key word THIS_OBJECT_ID is replaced by the id of the object managed in this widget.
        if (value == '!THIS_OBJECT_ID!' && params.objectId !== undefined)
          return { done: true, newValue: params.objectId };

        //-- Extra parameter value (information given from caller)
        if (
          params.extraValues !== undefined &&
          params.extraValues[value] !== undefined
        )
          return { done: true, newValue: params.extraValues[value] };
      }

      if (value.substr(0, 1) == '!') {
        reg = new RegExp('!', 'g');
        var keyword = value.replace(reg, '');
        if (resources.appKeyWordConfig[keyword] != undefined)
          return { done: true, newValue: resources.appKeyWordConfig[keyword] };
        keyword = keyword.toLowerCase();
        for (var prop in resources.appKeyWordConfig)
          if (keyword == prop.toLowerCase())
            return { done: true, newValue: resources.appKeyWordConfig[prop] };
      }
      var aa = 'eee';

      return { done: false, newValue: value };
    }

    function buildSimpleExpressionFromLiteral(
      exprToEvaluate,
      literal,
      valName,
      params
    ) {
      var res, reg, ind, ind2, func;

      if (literal !== undefined) {
        var res = getValueForKeyWord(literal, params);
        if (res.done) {
          ind = exprToEvaluate.indexOf('!' + valName + '!.');
          if (ind != -1) {
            //-- A method has to be called on the object and the result returned
            ind = exprToEvaluate.indexOf('!.', ind);
            ind2 = exprToEvaluate.indexOf('()', ind);
            func = exprToEvaluate.substr(ind + 2, ind2 - ind - 2);
            return res.newValue[func]();
          } else {
            //-- No method has to be called on the object so evaluate the expression
            reg = new RegExp('!' + valName + '!', 'g');
            exprToEvaluate = exprToEvaluate.replace(reg, '' + res.newValue);
          }
        }
      }
      return exprToEvaluate;
    }

    function evaluateSimpleExpression(expression, params) {
      var res,
        exprToEvaluate = expression.operation;

      exprToEvaluate = buildSimpleExpressionFromLiteral(
        exprToEvaluate,
        expression.literal1,
        'v1',
        params
      );
      exprToEvaluate = buildSimpleExpressionFromLiteral(
        exprToEvaluate,
        expression.literal2,
        'v2',
        params
      );

      return eval(exprToEvaluate);
    }

    function getGeometryExtent(inCoords) {
      var minx, miny, maxx, maxy, workingCoords, coords, multi, ind0, newCoords;

      if (inCoords === undefined) return;
      workingCoords = inCoords;
      if (inCoords.length != 0) {
        if (inCoords[0].push === undefined) {
          workingCoords = [];
          multi = [];
          coords = [];
          coords.push(inCoords);
          multi.push(coords);
          workingCoords.push(multi);
        } else if (inCoords[0][0].push === undefined) {
          workingCoords = [];
          multi = [];
          coords = inCoords;
          multi.push(coords);
          workingCoords.push(multi);
        }
      }

      minx = maxx = workingCoords[0][0][0][0];
      miny = maxy = workingCoords[0][0][0][1];
      if (minx == undefined) {
        minx = maxx = workingCoords[0][0][0];
        miny = maxy = workingCoords[0][0][1];
      }
      for (ind0 = 0; ind0 < workingCoords.length; ind0++) {
        multi = workingCoords[ind0];
        for (var ind = 0; ind < multi.length; ind++) {
          coords = multi[ind];
          if (coords.length != 0 && coords[0][0] == undefined) {
            newCoords = [];
            newCoords.push(coords);
            coords = newCoords;
          }
          for (var ind1 = 0; ind1 < coords.length; ind1++) {
            if (coords[ind1][0] < minx) minx = coords[ind1][0];
            if (coords[ind1][1] < miny) miny = coords[ind1][1];
            if (coords[ind1][0] > maxx) maxx = coords[ind1][0];
            if (coords[ind1][1] > maxy) maxy = coords[ind1][1];
          }
        }
      }

      if (minx == maxx) {
        minx -= 100;
        maxx += 100;
      }
      if (miny == maxy) {
        miny -= 100;
        maxy += 100;
      }

      return [minx, miny, maxx, maxy];
    }

    function gotoGeometry(scope, coords) {
      var olExtent = getGeometryExtent(coords);
      scope.map.getView().fit(olExtent, scope.map.getSize());
    }

    function getFieldAliasFrom(tableDesc, fn, relName) {
      for (var ind = 0; ind < tableDesc.attributes.length; ind++) {
        if (tableDesc.attributes[ind].name == fn)
          return tableDesc.attributes[ind].alias;
      }

      //-- Alias not found, may be it's a field of an N-M relation.
      //-- In such case get relation table description,
      //-- and then look for the field name to get the alias.
      if (relName != undefined) {
        var relTableDesc = FeatureTypeFactory.getFeatureTypeDesc(
          tableDesc.storeName,
          relName
        );
        if (relTableDesc != undefined) {
          for (var ind = 0; ind < relTableDesc.attributes.length; ind++) {
            if (relTableDesc.attributes[ind].name == fn)
              return relTableDesc.attributes[ind].alias;
          }
        }
      }

      return fn;
    }

    function defineDefaultConfigManageRelationsRelNM(
      rel,
      cfg,
      ds,
      feat,
      tableDesc
    ) {
      var sf,
        fn,
        cfgMf,
        mfAddedTables = ';';
      var fn = '',
        otherTable;

      if (rel.componentStart == feat) {
        fn = rel.fieldStart;
        otherTable = rel.componentEnd;
      }
      if (rel.componentEnd == feat) {
        fn = rel.fieldEnd;
        otherTable = rel.componentStart;
      }
      if (fn != '') {
        //-- -1- Add field fieldEnd to field list
        // cfg.addedFields.push (rel.name);
        //-- -2- Build special config
        /*
                  *   "specialFields": {
                        "contact": {
                          "alias": "Contact",
                          "selectWithForm": true,
                          "configName": "config_chercher_demandeur_phy"
                        }
                      }
                  */
        sf = cfg.specialFields[rel.name] = {};
        sf.alias = getFieldAliasFrom(tableDesc, fn, rel.name);
        sf.selectWithForm = true;
        //-- -2- Build main field config
        /*
                     "tableMainFields": [
                            {
                              "table": "day_personne_physique",
                              "fields": [
                                {
                                  "field": "nom"
                                },
                                {
                                  "field": "prenom"
                                }
                              ]
                            }
                         ]
                 */
        if (mfAddedTables.indexOf(';' + otherTable + ';') == -1) {
          //-- Table has not been configured for main fields to display, so do it now.
          cfgMf = {};
          cfgMf.table = otherTable;
          cfgMf.fields = [{ field: 'nom' }, { field: 'prenom' }];
          cfg.tableMainFields.push(cfgMf);
          mfAddedTables += otherTable + ';';
        }
        /*
                  * {
                      "datastoreName": "yamoussoukro",
                      "featureName": "day_personne_physique",
                      "useDescription": "select_add"
                    }
                  */
        sf.configName = {};
        sf.configName.datastoreName = tableDesc.storeName;
        sf.configName.featureName = otherTable;
        sf.configName.useDescription = 'select_add';
      }
    }

    function defineDefaultConfigManageRelationsRel1N(
      rel,
      cfg,
      ds,
      feat,
      tableDesc
    ) {
      var sf,
        fn,
        cfgMf,
        mfAddedTables = ';';

      if (rel.componentEnd == feat) {
        //-- -1- Exclude field fieldEnd from field list
        fn = rel.fieldEnd;
        cfg.excludedFields.push(fn);
        //-- -2- Build special config
        /*
                  *   "specialFields": {
                        "contact": {
                          "alias": "Contact",
                          "selectWithForm": true,
                          "configName": "config_chercher_demandeur_phy"
                        }
                      }
                  */
        sf = cfg.specialFields[rel.name] = {};
        sf.alias = getFieldAliasFrom(tableDesc, fn);
        sf.selectWithForm = true;
        //-- -2- Build main field config
        /*
                     "tableMainFields": [
                            {
                              "table": "day_personne_physique",
                              "fields": [
                                {
                                  "field": "nom"
                                },
                                {
                                  "field": "prenom"
                                }
                              ]
                            }
                         ]
                 */
        if (mfAddedTables.indexOf(';' + rel.componentStart + ';') == -1) {
          //-- Table has not been configured for main fields to display, so do it now.
          cfgMf = {};
          cfgMf.table = rel.componentStart;
          cfgMf.fields = [{ field: 'nom' }, { field: 'prenom' }];
          cfg.tableMainFields.push(cfgMf);
          mfAddedTables += rel.componentStart + ';';
        }
        /*
                  * {
                      "datastoreName": "yamoussoukro",
                      "featureName": "day_personne_physique",
                      "useDescription": "select_add"
                    }
                  */
        sf.configName = {};
        sf.configName.datastoreName = tableDesc.storeName;
        sf.configName.featureName = rel.componentStart;
        sf.configName.useDescription = 'select_add';
      }
    }

    function defineDefaultConfigManageRelations(cfg, ds, feat, tableDesc) {
      var rel;
      if (cfg.excludedFields == undefined) cfg.excludedFields = [];
      if (cfg.specialFields == undefined) cfg.specialFields = {};
      if (cfg.tableMainFields == undefined) cfg.tableMainFields = [];
      for (var ind = 0; ind < tableDesc.relations.length; ind++) {
        rel = tableDesc.relations[ind];
        if (rel.occurence == 'N-M')
          defineDefaultConfigManageRelationsRelNM(
            rel,
            cfg,
            ds,
            feat,
            tableDesc
          );
        else
          defineDefaultConfigManageRelationsRel1N(
            rel,
            cfg,
            ds,
            feat,
            tableDesc
          );
      }
    }

    /**
     *    Store under a given a name an "objectField" used in the formfields.
     * This object contains the value of the field and is modified when the value
     * is gotten from database or because the user changes it.
     *
     * @param {Object} name
     * @param {Object} obj
     */
    function storeValueObj(name, obj) {
      if (resources.globalValues[name] == undefined)
        resources.globalValues[name] = {};
      resources.globalValues[name].gotten = false;
      resources.globalValues[name].obj = obj;
      if (resources.globalValues[name].deferred != undefined) {
        resources.globalValues[name].deferred.resolve(
          resources.globalValues[name].obj
        );
        resources.globalValues[name].gotten = true;
      }
    }

    /**
     *    Retrieve the "objectField" stored under a given name.
     * As the object is returned, actually its reference, it can be set
     * to a field (another field than the updatable one) to display the same value.
     *
     * @param {Object} name
     */
    function getStoredValueObj(name) {
      var deferred = $q.defer();
      if (resources.globalValues[name] == undefined)
        resources.globalValues[name] = {};

      //-- if valueObj has already been gotten, it means that we want to get
      //-- a newer one.
      if (
        resources.globalValues[name].obj == undefined ||
        resources.globalValues[name].gotten
      )
        resources.globalValues[name].deferred = deferred;
      else {
        deferred.resolve(resources.globalValues[name].obj);
        resources.globalValues[name].gotten = true;
      }

      return deferred.promise;
    }

    function gotStoredValue(name) {
      resources.globalValues[name].deferred = undefined;
    }

    function controlsOk(obj, config, retObj, fieldToControl) {
      var dateFin,
        dateDebut,
        iFin,
        ret = true,
        att,
        ctrls;
      var objProp, attNameDeb, attNameFin, attNameDebInCase, dateFinInCase;

      if (obj.properties != undefined) objProp = obj.properties;
      else objProp = obj;
      if (config != undefined) ctrls = config.controls;
      if (ctrls != undefined) {
        for (var iCtrl = 0; iCtrl < ctrls.length; iCtrl++)
          if (ctrls[iCtrl].date_fin_sup_date_debut != undefined) {
            //-- Recherche des valeurs de date de début et de fin
            attNameFin = ctrls[iCtrl].date_fin_sup_date_debut.endDateField;
            dateFin = objProp[attNameFin];
            if (dateFin != null && dateFin.trim != undefined)
              dateFin = getDateFromDbString(dateFin);
            attNameDeb = ctrls[iCtrl].date_fin_sup_date_debut.startDateField;
            dateDebut = objProp[attNameDeb];
            if (dateDebut != null && dateDebut.trim != undefined)
              dateDebut = getDateFromDbString(dateDebut);
            //-- On vérifie que la date de fin est bien postérieure à celle de début
            if (dateFin != null && dateDebut > dateFin) {
              if (fieldToControl == undefined || attNameFin == fieldToControl) {
                objProp[attNameFin] = dateDebut;
                ret = false;
                if (retObj != undefined)
                  retObj.nameOfWrongAttribute = attNameFin;
              }
              /*
                                else if (attNameDeb==fieldToControl)
                                   {
                                    //-- tore thisn case only this modification can be done
                                    dateFinInCase = angular.copy(dateFin);
                                    attNameDebInCase = attNameDeb;
                                   }
                                   */
            }
          }
        if (
          retObj.nameOfWrongAttribute == undefined &&
          attNameDebInCase != undefined
        ) {
          //-- La date de début est postérieure à la date de fin, mais cette dernière n'a pas été non modifiée
          if (dateFin.getDate() == 1) {
            dateFin.setDate(29);
            if (dateFin.getMonth() == 0) dateFin.setMonth(11);
            else dateFin.setMonth(dateFin.getMonth() - 1);
            objProp[attNameDeb] = dateFin;
          } else {
            dateFin.setDate(dateFin.getDate() - 1);
            objProp[attNameDeb] = dateFin;
          }
          ret = false;
          if (retObj != undefined) retObj.nameOfWrongAttribute = attNameDeb;
        }
      }

      return ret;
    }

    function getIdFromFullIdValue(idvalue) {
      var pos = idvalue.indexOf('.');
      if (pos != -1) return idvalue.substr(pos + 1);
      else return idvalue;
    }

    function getWsFromUrl(url) {
      var ws, iPos;
      ws = url.replace('/services/', '');
      iPos = ws.indexOf('/');
      ws = ws.substr(0, iPos);
      return ws;
    }

    var loadMapTimerPromise;

    function mapError(client) {
      if (client.status != 200) {
        require('toastr').error('Map: ' + client.statusText);
      } else {
        require('toastr').error('Map: ' + client.responseText);
      }
      loadMapTimerPromise = undefined;
    }

    return {
      controlsOk: controlsOk,
      initialize: initialize,
      gotStoredValue: gotStoredValue,
      storeValueObj: storeValueObj,
      getStoredValueObj: getStoredValueObj,
      getValueForDB: getValueForDB,
      getAttributeIndex: getAttributeIndex,
      initEditFeatures: initEditFeatures,
      getDateFromDbString: getDateFromDbString,
      getObjUsingQueriesBuildWhere: getObjUsingQueriesBuildWhere,
      getValueForKeyWord: getValueForKeyWord,
      evaluateSimpleExpression: evaluateSimpleExpression,
      formatFieldValueToStringForDisplaying: formatFieldValueToStringForDisplaying,
      gotoGeometry: gotoGeometry,
      defineDefaultConfigManageRelations: defineDefaultConfigManageRelations,
      getIdFromFullIdValue: getIdFromFullIdValue,
    };
  };
  GlobalServices.$inject = [
    'FeatureTypeFactory',
    '$q',
    'ConfigFactory',
    'FunctionFactory',
    '$timeout',
    'gaJsUtils',
  ];
  return GlobalServices;
});
