'use strict';
define(function() {
  const itvVisuFactory = function(
      $http,
      QueryFactory,
      gclayers,
      itvSoumfactory2,
      $q,
      FeatureTypeFactory,
      itvStylesFactory,
      PortalsFactory
  ) {
    var portalid = angular.module('gcMain').portalid;
    if (portalid == undefined || portalid == '') {
      portalid = PortalsFactory.getPortalId();
    }
    var app = angular.module('gcMain').app;
    if (app == undefined || app == '') {
      app = localStorage.getItem('app');
    }

    /**
     * Récupére la description des inspections de fichiers ITV stocké en BDD.
     *
     * @param {*} itvids : Identifiant des ITVs à chercher
     * @param {*} datastore : source de données contenant les dites ITVs
     * @param {*} network : réseau d'assainissement concerné par ces ITVs
     * @param {*} agLayers : couches ArcGIS des table des IT6Vs
     * @returns
     */
    function getItvFromBdd(itvids, datastore, network, agLayers, configName) {
      var promise = $http.get( '/services/' + portalid + '/itv/' + app +
          '/getItvFromBdd?f=json&itvids=' + itvids +
          '&datastore=' + datastore +
          '&network=' + network +
          '&configname=' + configName +
          '&arcgislayers=' + agLayers
      );
      return promise;
    }


    /**
     * Récupére la photo d'une observation.
     *
     * @param {*} filename : nom du fichier photo
     * @param {*} id : identifiant de l'observation
     * @param {*} detailLayerName : nom de la couche observation
     * @returns
     */
    const getPictureForVisualisation = (filename, id, detailLayerName) => {
      return $http.get('/services/' + portalid + '/itv/' + app +
          '/getPictureForVisualisation?f=json&filename=' + filename +
          '&id=' + id + '&detailLayerName='+detailLayerName
      );
    };


    /**
     * Service de cration de la géométrie des observations des inspections des
     * fichers ITVs dont on passe les identifiants en paramétre..
     *
     * @param {*} itvids
     * @param {*} itvparts
     * @param {*} datastore
     * @param {*} network
     * @param {*} agLayers
     * @returns
     */
    function createGeometryOfDetails(itvids, itvparts, datastore, network,
      agLayers, configName) {
      var promise = $http.get( '/services/' + portalid + '/itv/' + app +
          '/createGeometryOfDetails?f=json&itvids=' + itvids +
          '&itvparts=' + itvparts +
          '&datastore=' + datastore +
          '&network=' + network +
          '&configname=' + configName +
          '&arcgislayers=' + agLayers
      );
      return promise;
    }


    /**
     * Ajout d'un noeud à une liste.
     *
     * @param {*} code : code à ajouter
     * @param {*} codes : liste des codes de la portion
     * @param {*} part : poriton inspectée en cours de traitement
     * @param {*} res : liste à alimenter
     * @returns
     */
    const addNodeOrEdgeToList = (code, codes, part, res) => {
      const codeIndex = codes.indexOf(code);
      if (codeIndex !== -1) {
        res.push(part.headers[codeIndex]);
        return true;
      }
      return false;
    };


    /**
     * Préparer la liste des ouvrages à représenter sur la carte
     * en mode mise en évidence.
     *
     * @param {*} part : portion inspectée dont on veut représenter les ouvrages
     * @returns liste des ouvrages à représenter.
     */
    const getNodesandEdges = (part) => {
      const res = [];
      let connectionPipeHasDevice = true;
      const codes = part.headers.map((x) => {
        return x._code;
      });
      if (part.branchement) {
        //-- Inspection de branchement
        connectionPipeHasDevice =  addNodeOrEdgeToList('@01', codes, part, res);
        addNodeOrEdgeToList('AAT', codes, part, res);
        addNodeOrEdgeToList('AAU', codes, part, res);
        //-- Récupération du sens de l'inspection de branchement
        addNodeOrEdgeToList('AAV', codes, part, res);
      }
      if (!addNodeOrEdgeToList('CAA', codes, part, res)
        || !connectionPipeHasDevice) {
        addNodeOrEdgeToList('AAA', codes, part, res);
        addNodeOrEdgeToList('AAD', codes, part, res);
        addNodeOrEdgeToList('AAF', codes, part, res);
      }
      return res;
    };


    const defineLayer = (header, LayerName, crs, promises, branchement,
      replace, val, reverse) => {
      const layer = gclayers.getOperationalLayerByName(LayerName);
      if (layer != undefined) {
        let headerValue;
        if (replace) {
          if (val) {
            headerValue = val.replace(/ /g, '');
          }
          else {
            headerValue = header.value.replace(/ /g, '');
          }
        }
        else {
          headerValue = header.value;
        }
        const promise
          = QueryFactory.get(layer.uid, headerValue, crs);
        promise.then((res) => {
          let headerCode = header._code;
          if ((headerCode === 'AAT' || headerCode === 'AAU') && reverse) {
            //-- Inversion pour représenter l'inspection de branchement
            //-- avec en vert le bon noeud de départ de l'inspection et
            //-- en rouge le noeud de fin.
            headerCode = headerCode === 'AAT' ? 'AAU' : 'AAT';
          }
          switch (headerCode) {
          case 'AAA':
            if (branchement) {
              itvSoumfactory2.defineLayer(
                itvStylesFactory.CANAL_DE_BRCHT_STYLE, res, 'AAA');
            }
            else {
              itvSoumfactory2.defineLayer(
                itvStylesFactory.CANALISATION_STYLE, res, 'AAA');
            }
            break;
          case 'AAD':
          case 'AAT':
            itvSoumfactory2.defineLayer(
              itvStylesFactory.NODE_AMONT, res, header._code);
            break;
          case 'CAA':
            itvSoumfactory2.defineLayer(
              itvStylesFactory.NODE_ALONE, res, header._code);
            break;
          case 'AAF':
          case 'AAU':
            itvSoumfactory2.defineLayer(
              itvStylesFactory.NODE_AVAL, res, header._code);
            break;
          case '@01':
            itvSoumfactory2.defineLayer(
              itvStylesFactory.BRANCHEMENT_STYLE, res, '@01');
            break;
          }
        });
        promises.push(promise);
      }
    };


    /**
     * Lance une requête de recherche d'un objet d'un composant sur la valeur
     * de son identifiant et retourne la promesse de cette requête.
     *
     * @param {*} idValue : valeur de l'identifiant
     * @param {*} fti : description du comopsant
     * @param {*} crs : Coordinate Reference Syteme
     * @returns
     */
    const getQueryPromise = (idValue, fti, crs) => {
      let promise;
      if (fti.type === 'esri') {
        if (idValue.indexOf('.') != -1) {
          idValue = idValue.split('.')[1];
        }
        promise = QueryFactory.data(fti.uid,
          fti.esriIdField + '=' + idValue, crs);
      }
      else {
        promise = QueryFactory.get(fti.uid, idValue.replace(/ /g, ''), crs);
      }
      return promise;
    };


    /**
     * Dessine sur la carte l'ouvrage demandé dans les paramétres, donc soit
     * le regard de début d'inspection soit celui de fin, soit le regard
     * inspecté, soit les tronçons inspectés.
     *
     * @param {*} hdrCode
     * @param {*} hdrValue
     * @param {*} ftiUid
     * @param {*} crs
     * @param {*} promises
     */
    const drawTheFeature = (hdrCode, hdrValue, ftiUid, crs, promises) => {
      let layerName, layerFti;
      if (hdrValue.indexOf('.') !== -1) {
        layerName = hdrValue.split('.')[0].replace(/ /g, '');
        layerFti = gclayers.getOperationalLayerByName(layerName);
      }
      else {
        layerFti = FeatureTypeFactory.getFeatureByUid(ftiUid);
      }
      //-- Pas de FTI si pas de correspondance,
      //-- on a l'identifiant lu dans fichier ITV
      if (layerFti != undefined && layerFti.uid!=='') {
        const promise = getQueryPromise(hdrValue, layerFti, crs);
        promise.then((res) => {
          if (hdrCode === 'AAD') {
            itvSoumfactory2.defineLayer(itvStylesFactory.NODE_AMONT, res,
              'AAD');
          }
          else if (hdrCode == 'AAF') {
            itvSoumfactory2.defineLayer(itvStylesFactory.NODE_AVAL, res, 'AAF');
          }
          else if (hdrCode == 'CAA') {
            itvSoumfactory2.defineLayer(itvStylesFactory.NODE_ALONE, res,
              'CAA');
          }
          else if (hdrCode == 'AAA') {
            itvSoumfactory2.defineLayer(itvStylesFactory.CANALISATION_STYLE,
              res, 'AAA');
          }
          else if (hdrCode == '@01') {
            itvSoumfactory2.defineLayer(itvStylesFactory.BRANCHEMENT_STYLE,
              res, '@01');
          }
        });
        promises.push(promise);
      }
    };


    function drawFeatureBranchement(part, crs, promises) {
      var Headers = getNodesandEdges(part);
      let connectionPipeHasDevice = false;
      for (let ind = 0; ind < Headers.length; ind++) {
        const header = Headers[ind];
        const LayerName = header.value.split('.')[0];
        if (header != undefined) {
          if (header._code == '@01') {
            connectionPipeHasDevice = true;
            drawTheFeature (header._code, header.value, header.featUid, crs,
              promises);
          }
          else if (header._code === 'AAT' || header._code === 'AAU') {
            //-- Lorsque l'inspection d'une canalisation latérale est réalisée
            //-- à partir d'une canalisation principale, le point de départ
            //-- de l'inspection est :
            //-- ⎯ le raccordement au collecteur principal (A) ; ou,
            //-- ⎯ le troisième nœud (B).
            const AAV = Headers.find(header => header._code === 'AAV');
            defineLayer(header, LayerName, crs, promises, null, null, null,
              AAV && AAV.value==='A' ? true : false);
            connectionPipeHasDevice = true;
          }
        }
      }
      return connectionPipeHasDevice;
    }


    const drawFeature = (part, crs) => {
      const Headers = getNodesandEdges(part);
      const promises = [];
      if (!drawFeatureBranchement(part, crs, promises)) {
        for (let ind = 0; ind < Headers.length; ind++) {
          const header = Headers[ind];
          if (header != undefined) {
            if (header._code == 'AAA') {
              if (header.value.replace(/ /g, '').split(',').length == 1) {
                drawTheFeature(header._code, header.value, header.featUid, crs,
                  promises);
              }
              else {
                const values = header.value.replace(/ /g, '').split(',');
                for (let ind = 0; ind < values.length; ind++) {
                  drawTheFeature(header._code, values[ind], header.featUids[ind],
                    crs, promises);
                }
              }
            }
            else {
              drawTheFeature(header._code, header.value, header.featUid, crs,
                promises);
            }
          }
        }
      }
      return $q.all(promises);
    };


    function removeItvs(itvids, datastore, agLayers, contentOnly, configName) {
      return $http.get( '/services/' + portalid + '/itv/' + app +
        '/removeItvs?f=json&itvids=' + itvids
        + '&datastore=' + datastore
        + '&arcgislayers=' + agLayers
        + '&contentonly=' + contentOnly
        + '&configname=' + configName
      );
    }

    /**
     * Retourne la couche openLayers d'après le nom du fti récupéré dans la valeur du header
     * @param headerValue valeur du header fournie
     * @return {null|ol.layer.Vector} null si le header ne contient pas de point
     * ou bien si gcLayers.OperationalLayers ne contient de couche portant le nom
     */
    const getLayerFtiByHeaderValue = (headerValue) => {
      if (headerValue.includes('.')) {
        const layerName = headerValue.split('.')[0].replace(/ /g, '');
        return gclayers.getOperationalLayerByName(layerName);
      }
      return null;
    };

    /**
     * Récupère le geojson des objets constituant la portion d'ITV
     * @param part portion de l'ITV
     * @param projection code EPSG de la projection de la carte
     * @return {Promise}
     */
    const getPartGeometries = (part, projection) => {
      const headers = getNodesandEdges(part);
      const callsForFeature = [];
      for (const header of headers) {
        const layerFti = getLayerFtiByHeaderValue(header.value);
        if (layerFti) {
          const callForFeature = getQueryPromise(header.value, layerFti, projection);
          callsForFeature.push(callForFeature);
        }
      }
      return $q.all(callsForFeature);
    };

    return {
      getItvFromBdd: getItvFromBdd,
      getPictureForVisualisation: getPictureForVisualisation,
      drawFeature: drawFeature,
      createGeometryOfDetails: createGeometryOfDetails,
      removeItvs: removeItvs,
      getPartGeometries: getPartGeometries
    };
  };
  itvVisuFactory.$inject = [
    '$http',
    'QueryFactory',
    'gclayers',
    'itvSoumFactory2',
    '$q',
    'FeatureTypeFactory',
    'itvStylesFactory',
    'PortalsFactory'
  ];
  return itvVisuFactory;
});
