/**
   * @param dataStore
   * @param damageArea
   * @param target
   * @return
   * @throws IOException
   * @throws SQLException
   */
  public static Map<Integer, Double> calculateDamageValues(
      JDBCDataStore dataStore, Geometry damageArea, int target) throws IOException, SQLException {
    String wkt = damageArea.toText();
    DefaultTransaction transaction = new DefaultTransaction();
    Connection conn = null;
    Map<Integer, Double> damageValues = new HashMap<Integer, Double>();
    try {
      conn = dataStore.getConnection(transaction);

      if (FormulaUtils.isSimpleTarget(target)) {
        if (FormulaUtils.checkTarget(target, FormulaUtils.humanTargetsList)) {
          addDamageValuesByField(damageValues, conn, target + "", wkt);
        } else {
          addDamageValuesByArea(damageValues, conn, target + "", wkt);
        }

      } else if (FormulaUtils.isAllHumanTargets(target)) {
        addDamageValuesByField(damageValues, conn, FormulaUtils.humanTargetsList, wkt);
      } else if (FormulaUtils.isAllNotHumanTargets(target)) {
        addDamageValuesByArea(damageValues, conn, FormulaUtils.notHumanTargetsList, wkt);
      } else {
        addDamageValuesByField(damageValues, conn, FormulaUtils.humanTargetsList, wkt);
        addDamageValuesByArea(damageValues, conn, FormulaUtils.notHumanTargetsList, wkt);
      }

      return damageValues;
    } catch (SQLException e) {
      throw new ProcessException(e);
    } finally {
      transaction.close();
      if (conn != null) {
        conn.close();
      }
    }
  }
  private SimpleFeatureCollection calculateRisk(
      SimpleFeatureCollection features,
      JDBCDataStore dataStore,
      String storeName,
      Integer precision,
      String connectionParams,
      int processing,
      int formula,
      int target,
      String materials,
      String scenarios,
      String entities,
      String severeness,
      String fpfield,
      int batch,
      boolean simulation,
      Geometry damageArea,
      Map<Integer, Double> damageValues,
      List<TargetInfo> changedTargets,
      Map<Integer, Map<Integer, Double>> cffs,
      List<String> psc,
      Map<Integer, Map<Integer, Double>> padrs,
      Map<Integer, Double> piss,
      List<Integer> distances,
      boolean extendedSchema)
      throws IOException, SQLException {

    if (precision == null) {
      precision = 3;
    }

    DefaultTransaction transaction = new DefaultTransaction();
    Connection conn = null;
    try {
      conn = dataStore.getConnection(transaction);

      // output FeatureType (risk)
      //  - id_geo_arco
      //  - geometria
      //  - rischio1
      //  - rischio2
      SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
      tb.add(
          "id_geo_arco", features.getSchema().getDescriptor("id_geo_arco").getType().getBinding());
      tb.add(
          "geometria",
          MultiLineString.class,
          features.getSchema().getGeometryDescriptor().getCoordinateReferenceSystem());

      if (extendedSchema) {
        tb.add("rischio_sociale", Double.class);
        tb.add("rischio_ambientale", Double.class);
        tb.add("nr_corsie", Integer.class);
        tb.add("lunghezza", Integer.class);
        tb.add("nr_incidenti", Integer.class);
      } else {
        tb.add("rischio1", Double.class);
        tb.add("rischio2", Double.class);
      }
      // fake layer name (risk) used for WPS output. Layer risk must be defined in GeoServer
      // catalog
      tb.setName(new NameImpl(features.getSchema().getName().getNamespaceURI(), "risk"));
      SimpleFeatureType ft = tb.buildFeatureType();

      // feature level (1, 2, 3)
      int level = FormulaUtils.getLevel(features);

      LOGGER.info("Doing calculus for level " + level);

      Formula formulaDescriptor = Formula.load(conn, processing, formula, target);

      if (formulaDescriptor == null) {
        throw new ProcessException("Unable to load formula " + formula);
      }

      if (((!formulaDescriptor.hasGrid() && level == 3)
              || (!formulaDescriptor.hasNoGrid() && level < 3))
          && !extendedSchema) {
        LOGGER.info("Formula not supported on this level, returning empty collection");
        return new EmptyFeatureCollection(ft);
      } else {
        // iterator on source
        SimpleFeatureIterator iter = features.features();

        // result builder
        SimpleFeatureBuilder fb = new SimpleFeatureBuilder(ft);
        ListFeatureCollection result = new ListFeatureCollection(ft);
        int count = 0;
        Double[] risk = new Double[] {0.0, 0.0};

        // iterate source features
        try {
          // we will calculate risk in batch of arcs
          // we store each feature of the batch in a map
          // indexed by id
          Map<Number, SimpleFeature> temp = new HashMap<Number, SimpleFeature>();
          StringBuilder ids = new StringBuilder();
          String fk_partner = null;

          while (iter.hasNext()) {
            SimpleFeature feature = iter.next();
            Number id = (Number) feature.getAttribute("id_geo_arco");
            fk_partner = (String) feature.getAttribute("fk_partner");
            fb.add(id);
            fb.add(feature.getDefaultGeometry());
            if (formulaDescriptor.takeFromSource()) {
              risk[0] = ((Number) feature.getAttribute("rischio1")).doubleValue();
              risk[1] = ((Number) feature.getAttribute("rischio2")).doubleValue();
            }
            fb.add(risk[0]);
            fb.add(risk[1]);
            if (extendedSchema) {
              fb.add((Number) feature.getAttribute("nr_corsie"));
              fb.add((Number) feature.getAttribute("lunghezza"));
              fb.add((Number) feature.getAttribute("nr_incidenti"));
            }
            temp.put(id.intValue(), fb.buildFeature(id + ""));

            if (simulation) {
              Double pis = piss.get(id.intValue());
              Map<Integer, Double> padr = padrs.get(id.intValue());
              Map<Integer, Double> cff = cffs.get(id.intValue());

              Map<Integer, Map<Integer, Double>> simulationTargets =
                  new HashMap<Integer, Map<Integer, Double>>();

              if (!changedTargets.isEmpty()) {
                for (int distance : distances) {
                  Geometry buffer =
                      BufferUtils.iterativeBuffer(
                          (Geometry) feature.getDefaultGeometry(), (double) distance, 100);
                  for (TargetInfo targetInfo : changedTargets) {
                    if (targetInfo.getGeometry() != null) {
                      Geometry intersection = buffer.intersection(targetInfo.getGeometry());
                      if (intersection != null && intersection.getArea() > 0) {
                        Map<Integer, Double> distancesMap =
                            simulationTargets.get(targetInfo.getType());
                        if (distancesMap == null) {
                          distancesMap = new HashMap<Integer, Double>();
                          simulationTargets.put(targetInfo.getType(), distancesMap);
                        }
                        double value = 0.0;
                        if (targetInfo.isHuman()) {
                          value =
                              intersection.getArea()
                                  / targetInfo.getGeometry().getArea()
                                  * targetInfo.getValue();
                        } else {
                          value = intersection.getArea();
                        }
                        if (targetInfo.isRemoved()) {
                          value = -value;
                        }
                        distancesMap.put(distance, value);
                      }
                    }
                  }
                }
              }

              FormulaUtils.calculateSimulationFormulaValuesOnSingleArc(
                  conn,
                  level,
                  processing,
                  formulaDescriptor,
                  id.intValue(),
                  fk_partner,
                  materials,
                  scenarios,
                  entities,
                  severeness,
                  fpfield,
                  target,
                  simulationTargets,
                  temp,
                  precision,
                  cff,
                  psc,
                  padr,
                  pis,
                  null,
                  extendedSchema);

              result.addAll(temp.values());
              temp = new HashMap<Number, SimpleFeature>();
            } else if (damageArea != null) {
              Geometry arcGeometry = (Geometry) feature.getDefaultGeometry();
              if (arcGeometry != null && arcGeometry.intersects(damageArea)) {
                FormulaUtils.calculateSimulationFormulaValuesOnSingleArc(
                    conn,
                    level,
                    processing,
                    formulaDescriptor,
                    id.intValue(),
                    fk_partner,
                    materials,
                    scenarios,
                    entities,
                    severeness,
                    fpfield,
                    target,
                    null,
                    temp,
                    precision,
                    null,
                    null,
                    null,
                    null,
                    damageValues,
                    extendedSchema);
                result.addAll(temp.values());
              }
              temp = new HashMap<Number, SimpleFeature>();
            } else {
              ids.append("," + id);
              count++;
              // calculate batch items a time
              if (count % batch == 0) {
                LOGGER.info("Calculated " + count + " values");
                FormulaUtils.calculateFormulaValues(
                    conn,
                    level,
                    processing,
                    formulaDescriptor,
                    ids.toString().substring(1),
                    fk_partner,
                    materials,
                    scenarios,
                    entities,
                    severeness,
                    fpfield,
                    target,
                    temp,
                    precision,
                    extendedSchema);
                result.addAll(temp.values());
                ids = new StringBuilder();
                temp = new HashMap<Number, SimpleFeature>();
              }
            }
          }

          // final calculus for remaining items not in batch size
          LOGGER.info("Calculating remaining items");
          if (ids.length() > 0) {
            FormulaUtils.calculateFormulaValues(
                conn,
                level,
                processing,
                formulaDescriptor,
                ids.toString().substring(1),
                fk_partner,
                materials,
                scenarios,
                entities,
                severeness,
                fpfield,
                target,
                temp,
                precision,
                extendedSchema);
          }
          result.addAll(temp.values());

          LOGGER.info("Calculated " + result.size() + " values");

        } finally {
          iter.close();
        }
        return result;
      }

    } finally {
      transaction.close();
      if (conn != null) {
        conn.close();
      }
    }
  }