'use strict';
define(function() {
  const NetworkFactory = function($http, $q, $timeout) {
    const NetworkFactory = {};

    const resources = {
      networks: [],
    };

    /**
     * Class : NetworkFactory
     * Factory WebServices
     */

    /**
     * Function: getnearestnode
     */
    function getnearestnode(
      senddata,
      networkName,
      inSrid,
      coordX,
      coordY,
      nodeType
    ) {
      var promise = $http.post(
        '/services/{portalid}/network/getNearestNode?f=json' +
          '&networkName=' +
          networkName +
          '&inSrid=' +
          inSrid +
          '&coordX=' +
          coordX +
          '&coordY=' +
          coordY +
          '&nodeType=' +
          nodeType,
        senddata
      );

      return promise;
    }
    /**
     * Function: getconnectedelements
     */
    function getconnectedelements(senddata, networkName, inSrid, nodesToParse) {
      var promise = $http.post(
        '/services/{portalid}/network/getConnectedElements?f=json' +
          '&networkName=' +
          networkName +
          '&inSrid=' +
          inSrid +
          '&nodesToParse=' +
          nodesToParse,
        senddata
      );

      return promise;
    }

    /**
     * Function: getnetworkpart
     */
    function getnetworkpart(senddata, networkName, inSrid, nodesToParse) {
      var promise = $http.post(
        '/services/{portalid}/network/getNetworkPart?f=json' +
          '&networkName=' + networkName +
          '&inSrid=' + inSrid +
          '&nodesToParse=' + nodesToParse,
        senddata,
        {
          timeout: 100000,
        }
      );

      return promise;
    }

    /**
     * Function: seekamontoravalnetworkpark
     */
    function seekamontoravalnetworkpart(
      senddata,
      networkName,
      inSrid,
      nodesToParse,
      seekForAmontElements
    ) {
      var promise = $http.post(
        '/services/{portalid}/network/seekAmontOrAvalNetworkPart?f=json' +
          '&networkName=' +
          networkName +
          '&inSrid=' +
          inSrid +
          '&nodesToParse=' +
          nodesToParse +
          '&seekForAmontElements=' +
          seekForAmontElements,
        senddata,
        {
          timeout: 100000,
        }
      );

      return promise;
    }

    /**
     * Function: processpathdistanceparse
     */
    function processpathdistanceparse(senddata, networkName, inSrid, distance) {
      var promise = $http.post(
        '/services/{portalid}/network/processPathDistanceParse?f=json' +
          '&networkName=' +
          networkName +
          '&inSrid=' +
          inSrid +
          '&distance=' +
          distance,
        senddata,
        {
          timeout: 100000,
        }
      );

      return promise;
    }

    /**
     * Function: getextendnetworkpart
     */
    function getextendnetworkpart(senddata, networkName, inSrid, nodesToParse) {
      var promise = $http.post(
        '/services/{portalid}/network/getExtendNetworkPart?f=json' +
          '&networkName=' +
          networkName +
          '&inSrid=' +
          inSrid +
          '&nodesToParse=' +
          nodesToParse,
        senddata,
        {
          timeout: 100000,
        }
      );

      return promise;
    }

    /**
     * Function: getorthogonalpoint
     */
    function getorthogonalpoint(networkName, inSrid, coordX, coordY, minDist) {
      var promise = $http.get(
        '/services/{portalid}/network/getOrthogonalPoint?f=json' +
          '&networkName=' +
          networkName +
          '&inSrid=' +
          inSrid +
          '&coordX=' +
          coordX +
          '&coordY=' +
          coordY +
          '&minDist=' +
          minDist
      );

      return promise;
    }

    /**
     * Function: getnearestedge
     */
    function getnearestedge(senddata, networkName, inSrid, coordX, coordY) {
      var promise = $http.post(
        '/services/{portalid}/network/getNearestEdge?f=json' +
          '&networkName=' +
          networkName +
          '&inSrid=' +
          inSrid +
          '&coordX=' +
          coordX +
          '&coordY=' +
          coordY,
        senddata
      );

      return promise;
    }
    /**
     * Function: getnearestnodes
     */
    function getnearestnodes(
      senddata,
      networkName,
      inSrid,
      coordX,
      coordY,
      count
    ) {
      var promise = $http.post(
        '/services/{portalid}/network/getNearestNodes?f=json' +
          '&networkName=' +
          networkName +
          '&inSrid=' +
          inSrid +
          '&coordX=' +
          coordX +
          '&coordY=' +
          coordY +
          '&count=' +
          count,
        senddata
      );

      return promise;
    }
    /**
     * Function: getnearestedges
     */
    function getnearestedges(
      senddata,
      networkName,
      inSrid,
      coordX,
      coordY,
      count
    ) {
      var promise = $http.post(
        '/services/{portalid}/network/getNearestEdges?f=json' +
          '&networkName=' +
          networkName +
          '&inSrid=' +
          inSrid +
          '&coordX=' +
          coordX +
          '&coordY=' +
          coordY +
          '&count=' +
          count,
        senddata
      );

      return promise;
    }


    /**
     * Function: getfastestway
     */
    let getfastestway = (senddata, networkName, inSrid) => {
      return $http.post(
        '/services/{portalid}/network/getFastestWay?f=json' +
        '&networkName=' + networkName +
        '&inSrid=' + inSrid,
        senddata
      );
    };


    /**
     * Function: updatenetwork
     */
    function updatenetwork(senddata, oldname) {
      var promise = $http.post(
        '/services/{portalid}/network/updateNetwork?f=json&oldname=' + oldname,
        senddata
      );
      promise.then(function(res) {
        var replaceIndex = resources.networks
          .map(function(x) {
            return x.uid;
          })
          .indexOf(senddata.uid);
        resources.networks[replaceIndex] = res.data;
      });
      return promise;
    }
    /**
     * Function: addnetwork
     */
    function addnetwork(senddata) {
      var promise = $http.post(
        '/services/{portalid}/network/addNetwork?f=json',
        senddata
      );
      promise.then(function(res) {
        resources.networks.push(res.data);
      });
      return promise;
    }
    /**
     * Function: deletenetwork
     */
    function deletenetwork(networkName) {
      var promise = $http.get(
        '/services/{portalid}/network/deleteNetwork?f=json' +
          '&networkName=' +
          networkName
      );
      promise.then(function() {
        var deleteIndex = resources.networks
          .map(function(x) {
            return x.name;
          })
          .indexOf(networkName);
        resources.networks.splice(deleteIndex, 1);
      });
      return promise;
    }

    let getPromise;
    /**
     * Function: get
     */
    /**
     * Récupère les réseaux.
     * @param {boolean} generate lance la création des réseaux dans le serveur. La requête API est toujours exécutée quand <code>generate = true</code>
     * <br>
     * La valeur par défaut aurait été <code>false</code> si cela n'avait pas été du dev KIS
     * @return {Promise} contient le tableau des réseaux
     */
    function get (generate = true) {
      const defer = $q.defer();
      if (resources.networks.length > 0 && !resources.getting) {
        defer.resolve({data: resources.networks});
      } else {
        if (resources.getting && getPromise && !generate) {
          // si la méthode est re-appelée avant la réponse du serveur,
          // on renvoie la promise du 1er appel API (ce qui devrait être fait sur FeatureTypeFactory.get)
          return getPromise;
        } else {
          resources.getting = true;
          $http.get('/services/{portalid}/network/get?f=json&generate=' + generate).then(
              (res) => {
                if (!resources.networks || resources.networks.length === 0) {
                  resources.networks = res.data;
                } else {
                  resources.networks.splice(0);
                  for (const network of res.data) {
                    resources.networks.push(network);
                  }
                }
                resources.getting = false;
                defer.resolve({data: resources.networks});
              },
              (err) => {
                resources.getting = false;
                defer.reject(err);
              });
        }
      }
      getPromise = defer.promise;
      return defer.promise;
    }

    /**
     * get the list of network names on the portail
     */
    const getAllNetworkNames = () => {
      const promise = get(false).then(res => {
        res.data = res.data.map(network => network.name);
        return res;
      });
      return promise;
    };

    /**
     * Function: getconnectedelementsxy
     */
    function getconnectedelementsxy(
      senddata,
      networkName,
      inSrid,
      nodesToParse,
      coordX,
      coordY,
      nodeType
    ) {
      var promise = $http.post(
        '/services/{portalid}/network/getConnectedElementsXY?f=json' +
          '&networkName=' +
          networkName +
          '&inSrid=' +
          inSrid +
          '&nodesToParse=' +
          nodesToParse +
          '&coordX=' +
          coordX +
          '&coordY=' +
          coordY +
          '&nodeType=' +
          nodeType,
        senddata
      );

      return promise;
    }

    /**
     * Function: getconnectededgesxy
     */
    let getconnectededgesxy = (
      senddata, networkName, inSrid, coordX, coordY, nodeType) => {
      return $http.post(
        '/services/{portalid}/network/getConnectedEdgesXY?f=json' +
        '&networkName=' + networkName +
        '&inSrid=' + inSrid +
        '&coordX=' + coordX +
        '&coordY=' + coordY +
        '&nodeType=' + nodeType,
        senddata
      );
    };


    /**
     * Attente de fin de recherche des chemins entre 2 noeuds.
     * 
     * @param {*} defer Defer qui fera le resolve pour l'appelant qui a demandé les chemins.
     * @param {*} threadId identifiant du thread de la recherche en cours côté serveur
     */
    const waitPathReady = (defer,threadId)  => {
      $http.get('/services/{portalid}/network/{appname}/getProgression?f=json'
        + '&threadid=' + threadId
      ).then((res) => {
        if (res.data.etat==='FINISHED') {
          $http.get('/services/{portalid}/network/{appname}/getThreadResult?f=json'
          + '&threadid=' + threadId
          ).then((res) => {
            defer.resolve(res);
          });
        }
        else if (res.data.etat==='RUNNING') {
          $timeout(() => {waitPathReady(defer,threadId);},1000);
        }
      });
    };


    /**
     * Recherche de tous les chemins existant entre 2 noeuds.
     *
     * @param {*} networkName : réseau dans lequel on cherche les chemins
     * @param {*} srid : référence spatial des données en entrées
     * @param {*} startNode : noeud de départ des chemins
     * @param {*} endNode  : noeud d'arrivée des chemins
     * @returns
     */
    let getAllPaths = (networkName, srid, startNode, endNode, maxNodes, maxPaths) => {
      let senddata = {
        noeudAmont: startNode,
        noeudAval: endNode,
        barriers:[],
        processConfig: {
          label: '',
          toolType: '',
          amontElements: [],
          avalElements: [],
          networkElements: [],
          amontElementsFilters: [],
          avalElementsFilters: [],
          networkElementsFilters: [],
          genericConfig: {},
          addPathAtEnd : false
        }
      };
      const promise = $http.post(
        '/services/{portalid}/network/getAllPaths?f=json' +
        '&networkName=' + networkName +
        '&maxNodes=' + maxNodes +
        '&maxPaths=' + maxPaths +
        '&inSrid=' + srid,
        senddata
      );
      const defer = $q.defer();
      promise.then((res) => {
        if (res.data.etat === 'en cours') {
          waitPathReady(defer,res.data.objValeur.threadId);
        }
      });
      return defer.promise;
    };


    /**
     * Function: getdetails
     */
    function getdetails(networkName) {
      var promise = $http.get(
        '/services/{portalid}/network/getDetails?f=json' +
          '&networkName=' +
          networkName
      );

      return promise;
    }
    const rechercheAmontAval = (networkName, pipes, distAmont, distAval,
      inSrid) => {
      return $http.post(
        '/services/{portalid}/network/rechercheAmontAval?f=json' +
        '&networkName=' + networkName +  '&inSrid=' + inSrid +
        '&distAmont=' + distAmont + '&distAval=' + distAval,
        pipes
      );
    };

    /**
     * Lance la création automatique des règles métier
     * @param network configuration du réseau du menu de réseau de l'administration KIS
     * @param selectedCreateRuleOption choix parmis: 
     *        "deleteAllRulesBefore"||"replaceAllRules"||"createMissingRules"
     */
    const createRules = (network, selectedCreateRuleOption) => {
      return $http.post(
        '/services/{portalid}/network/createRules?f=json' +
          '&selectedCreateRuleOption=' + selectedCreateRuleOption,
        network);
    };

    return {
      NetworkFactory: NetworkFactory,
      resources: resources,
      getnearestnode: getnearestnode,
      getconnectedelements: getconnectedelements,
      getnetworkpart: getnetworkpart,
      seekamontoravalnetworkpart: seekamontoravalnetworkpart,
      processpathdistanceparse: processpathdistanceparse,
      getextendnetworkpart: getextendnetworkpart,
      getorthogonalpoint: getorthogonalpoint,
      getnearestedge: getnearestedge,
      getnearestnodes: getnearestnodes,
      getnearestedges: getnearestedges,
      getfastestway: getfastestway,
      updatenetwork: updatenetwork,
      addnetwork: addnetwork,
      deletenetwork: deletenetwork,
      getconnectedelementsxy: getconnectedelementsxy,
      getconnectededgesxy: getconnectededgesxy,
      getdetails: getdetails,
      get: get,
      getAllNetworkNames: getAllNetworkNames,
      getAllPaths: getAllPaths,
      rechercheAmontAval: rechercheAmontAval,
      createRules: createRules
    };
  };
  NetworkFactory.$inject = ['$http','$q', '$timeout'];
  return NetworkFactory;
});
