ServiceUtils.java [src/java/util] Revision: default  Date:
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package util;

import csip.api.server.PayloadParameter;
import csip.api.server.ServiceException;
import csip.utils.TextParser;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.LocalDate;
import java.time.Year;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Scanner;
import static m.ghg.ApplicationResources.MODEL_OFFSET;

/**
 *
 * @author od
 */
public class ServiceUtils {

  // crop types
  public static final String CORN = "C[1-9][1-9]?";
  public static final String SOYB = "SYBN[1-9]";
  public static final String OAT = "OAT1";
  public static final String GCP = "GCP";
  public static final String GI = "GI2";
  public static final String WHEAT = "W[1-9]";
  public static final String SPRINGWHEAT = "SW[1-9]";
  public static final String SORGHUM = "SORG[1-9]";
  public static final String SORGHUMFORAGE = "FSORG";
  public static final String ALFALFA = "ALF";
  public static final String GRASSHAY = "G3CPI";
  public static final String COTTON = "COT";
  public static final String PUMPKIN = "JTOM";
  public static final String CORNSILAGE = "CSL13";
  public static final String SUNFLOWER = "SUN";
  public static final String BARLEY = "BAR[1-9]";
  public static final String RYEGRASS = "RYE";


  public static String checkRemoveExtension(String filename) {
    return Optional.ofNullable(filename)
        .filter(f -> f.contains("."))
        .map(f -> f.substring(0, filename.lastIndexOf("."))).orElse(filename);
  }


  public static double[] getColumnData(File lisFile, String column) throws IOException {
    List<String> l = new ArrayList<>();
    try ( TextParser p = new TextParser(lisFile).autoClose(false).nextLine()) {
      int col = p.tokens().indexOf(column);
      while (p.nextLineSkipEmpty().notEOF()) {
        l.add(p.getWsTokenAt(col));
      }
    }
    return l.stream().mapToDouble(Double::parseDouble).toArray();
  }


  public static String[] getStringColumnData(File lisFile, String column) throws IOException {
    List<String> l = new ArrayList<>();
    try ( TextParser p = new TextParser(lisFile).autoClose(false).nextLine()) {
      int col = p.tokens().indexOf(column);
      while (p.nextLineSkipEmpty().notEOF()) {
        l.add(p.getWsTokenAt(col));
      }
    }
    return l.toArray(new String[0]);
  }


  public static String[] getStringColumnDataCSV(File lisFile, String column) throws IOException {
    int rowLines = 0;
    try ( Scanner scanner = new Scanner(lisFile)) {
      while (scanner.hasNextLine()) {
        scanner.nextLine();
        rowLines++;
      }
    } catch (FileNotFoundException e) {
      throw new RuntimeException(e.getMessage());
    }
    rowLines--;
    String[] tot = new String[rowLines];
    try ( Scanner scanner = new Scanner(lisFile)) {
      String header = scanner.nextLine();
      String[] cols = header.split(",");
      int c = 0;
      for (int i = 0; i < cols.length; i++) {
        if (cols[i].toLowerCase().trim().equals(column.toLowerCase().trim())) {
          c = i;
        }
      }
      int index = 0;

      //Read line
      while (scanner.hasNextLine()) {
        String line = scanner.nextLine();
        String[] items = line.split(",");
        tot[index] = items[c];
        index++;
        //Scan the line for tokens
//      try (Scanner rowScanner = new Scanner(line)) {
//      rowScanner.useDelimiter(",");
//      while (rowScanner.hasNext()) {
//        System.out.print(scanner.next());
//      }
//    }
      }
    } catch (FileNotFoundException e) {
      throw new RuntimeException(e.getMessage());
    }
    return tot;
  }


  public static double[] getColumnData(File outFile, int columnIndex) throws FileNotFoundException, IOException {
    List<String> l = new ArrayList<>();
    try ( TextParser p = new TextParser(outFile).autoClose(false).nextLine()) {
      while (p.nextLineSkipEmpty().notEOF()) {
        l.add(p.getWsTokenAt(columnIndex));
      }
    }
    return l.stream().mapToDouble(Double::parseDouble).toArray();
  }


  public static int[] getIntegerColumnData(File outFile, int columnIndex) throws FileNotFoundException, IOException {
    List<String> l = new ArrayList<>();
    try ( TextParser p = new TextParser(outFile).autoClose(false).nextLine()) {
      while (p.nextLineSkipEmpty().notEOF()) {
        l.add(p.getWsTokenAt(columnIndex));
      }
    }
    return l.stream().mapToInt(Integer::parseInt).toArray();
  }


  public static List<String> getCropHarvest(File schFile, String croptype, String termination) throws IOException {
    List<String> years = new ArrayList<>();
    try ( TextParser p = new TextParser(schFile).autoClose(false)) {
//      p.toLineStaringWith("3943"); // just for lRR C
      p.toLineStartingWith("3901");
//      p.toLineStaringWith("3960"); // just for LRR B
      try ( TextParser block = p.allUntil("-999 -999 X").autoClose(false)) {
        cropHarvestFromBlock(block, years, croptype, termination);
      }

      while (true) {
        p.toLineContaining("Last year");
        if (p.isEOF()) {
          break;
        }
//        System.out.println(p);
        try ( TextParser block = p.allUntil("-999 -999 X")) {
          if (block == null) {
            break;
          }
          block.autoClose(false);
          cropHarvestFromBlock(block, years, croptype, termination);
        }
      }
    }
    return years;
  }


  public static void cropHarvestFromBlock(TextParser block, List<String> years, String croptype, String termination)
      throws IOException {

//    System.out.println("In Block " + block);
    int endYear = block.nextLine().leftOfFirst("Last").asInteger();  // last year
    int repeats = block.nextLine().leftOfFirst("Repeats").asInteger();  // Repeats
    int startingYear = block.nextLine().leftOfFirst("Output").asInteger();  // starting year
    block.toLineContaining("  1");  // first operation in block

    int startyear = startingYear - MODEL_OFFSET;
    int endyear = endYear - MODEL_OFFSET;

    while (block.notEOF()) {
//      String[] crop = block.toLineContaining("CROP " + croptype).tokens().asStringArray();
      String[] crop = block.toLineMatching("^.*\\sCROP " + croptype + "\\s*$").tokens().asStringArray();
//          System.out.println("CR " + Arrays.toString(crop));
      if (crop.length == 0) {
        break;
      }
//      System.out.println(crop[3]);
      String[] harv = block.toLineContaining(termination).tokens().asStringArray();
      if (harv.length == 0) {
        break;
      }
//          System.out.println("HA " + Arrays.toString(harv));
      int op_year = Integer.parseInt(harv[0]);
      int op_doy = Integer.parseInt(harv[1]);

      for (int year = startyear; year <= endyear; year = year + repeats) {
        // get day of the year one month earlier
        // because daycent doesn't manage two crops
        // at the same time
        if (termination.equals("HERB")
            || termination.equals("WKIL")) {
          int y = year + op_year - 1;
          Year yObj = Year.of(y);
          LocalDate ld = yObj.atDay(op_doy);
          LocalDate ld_mm = ld.minusMonths(1);
          op_doy = ld_mm.getDayOfYear();
        }
        years.add(year + op_year - 1 + "." + op_doy);
      }
    }
  }


  public static List<String> getHarvest(File schFile, String termination) throws IOException {
    List<String> years = new ArrayList<>();
    try ( TextParser p = new TextParser(schFile).autoClose(false)) {
//      p.toLineStaringWith("3943"); // just for lRR C
      p.toLineStartingWith("3950");
//      p.toLineStaringWith("3960"); // just for LRR B
      try ( TextParser block = p.allUntil("-999 -999 X").autoClose(false)) {
        cropHarvestFromBlock(block, years, termination);
      }

      while (true) {
        p.toLineContaining("Last year");
        if (p.isEOF()) {
          break;
        }
//        System.out.println(p);
        try ( TextParser block = p.allUntil("-999 -999 X")) {
          if (block == null) {
            break;
          }
          block.autoClose(false);
          cropHarvestFromBlock(block, years, termination);
        }
      }
    }
    return years;
  }


  public static void cropHarvestFromBlock(TextParser block, List<String> years, String termination)
      throws IOException {

//    System.out.println("In Block " + block);
    int endYear = block.nextLine().leftOfFirst("Last").asInteger();  // last year
    int repeats = block.nextLine().leftOfFirst("Repeats").asInteger();  // Repeats
    int startingYear = block.nextLine().leftOfFirst("Output").asInteger();  // starting year
    block.toLineContaining("  1");  // first operation in block

    int startyear = startingYear - MODEL_OFFSET;
    int endyear = endYear - MODEL_OFFSET;

    while (block.notEOF()) {
////      String[] crop = block.toLineContaining("CROP " + croptype).tokens().asStringArray();
//      String[] crop = block.toLineMatching("^.*\\sCROP " + croptype + "\\s*$").tokens().asStringArray();
////          System.out.println("CR " + Arrays.toString(crop));
//      if (crop.length == 0) {
//        break;
//      }
//      System.out.println(crop[3]);
      String[] harv = block.toLineContaining(termination).tokens().asStringArray();
      if (harv.length == 0) {
        break;
      }
//          System.out.println("HA " + Arrays.toString(harv));
      int op_year = Integer.parseInt(harv[0]);
      int op_doy = Integer.parseInt(harv[1]);

      for (int year = startyear; year <= endyear; year = year + repeats) {
        // get day of the year one month earlier
        // because daycent doesn't manage two crops
        // at the same time
        if (termination.equals("HERB")
            || termination.equals("WKIL")) {
          int y = year + op_year - 1;
          Year yObj = Year.of(y);
          LocalDate ld = yObj.atDay(op_doy);
          LocalDate ld_mm = ld.minusMonths(1);
          op_doy = ld_mm.getDayOfYear();
        }
        years.add(year + op_year - 1 + "." + op_doy);
      }
    }
  }


  static Map<String, String> createlookup(String[] key, String[] val) {
    Map<String, String> m = new LinkedHashMap<>();
    for (int i = 0; i < val.length; i++) {
      m.put(key[i], val[i]);
    }
    return m;
  }


  static Map<String, String> createlookup(String[] key, double[] val) {
    Map<String, String> m = new LinkedHashMap<>();
    for (int i = 0; i < val.length; i++) {
      m.put(key[i], String.valueOf(val[i]));
    }
    return m;
  }


  static Map<String, List<String>> createlookuplist(String[] key, String[] val) {
    Map<String, List<String>> m = new LinkedHashMap<>();
    for (int i = 0; i < val.length; i++) {
      if (m.containsKey(key[i])) {
        List<String> tmpList = m.get(key[i]);
        tmpList.add(String.valueOf(val[i]));
        m.put(key[i], tmpList);
      } else {
        List<String> tmpList = new ArrayList<>();
        tmpList.add(String.valueOf(val[i]));
        m.put(key[i], tmpList);
      }
    }
    return m;
  }


  public static Map<String, String> getMapFor(File wsFile, String column) throws IOException {
    String[] time = getStringColumnData(wsFile, "time");
    String[] col = getStringColumnData(wsFile, column);
    return createlookup(time, col);
  }


  public static Map<String, List<String>> getMapList(File wsFile, String column) throws IOException {
    String[] time = getStringColumnDataCSV(wsFile, "time");
    String[] col = getStringColumnDataCSV(wsFile, column);
    return createlookuplist(time, col);
  }


  public static Map<String, String> getMapFor(File wsFile, int column) throws IOException {
    double[] year = getColumnData(wsFile, 0);
    int[] doy = getIntegerColumnData(wsFile, 1);

    String[] time = getTime(year, doy);

    double[] col = getColumnData(wsFile, column);
    return createlookup(time, col);
  }


  public static String[] getTime(double[] year, int[] doy) {
    if (year.length != doy.length) {
      String msg = "Year and doy have different size " + year.length + " " + doy.length;
      throw new IllegalArgumentException(msg);
    }

    List<String> time = new ArrayList<>();
    for (int i = 0; i < year.length; i++) {
      int y = (int) year[i] - MODEL_OFFSET;
      int d = doy[i];
//      Year yy = Year.of(y);
//      LocalDate ld = yy.atDay(d);
//      time.add(ld.format(DateTimeFormatter.ISO_DATE));
      time.add(y + "-" + String.format("%03d", d));
    }
    return time.stream().toArray(String[]::new);
  }


  public static void dictPopulation(Map<String, Map<String, Double>> hashmap, String s, PayloadParameter parameter) throws ServiceException {
    String[] parts = s.split("\\.");
    String cropName = parts[1];
    String parameterName = parts[2];
    Double parameterValue = parameter.getDouble(s);
    if (hashmap.containsKey(cropName)) {
      hashmap.get(cropName).put(parameterName, parameterValue);
    } else {
      Map<String, Double> val1 = new HashMap<>();
      val1.put(parameterName, parameterValue);
      hashmap.put(cropName, val1);
    }
  }


  public static void main(String[] args) throws IOException {

//    Pattern p = Pattern.compile("^.*\\sCROP C[1-9][1-9]?\\s*$");
//    System.out.println(p.matcher("   1   110 CROP C3").matches());
//    List<String> l = getCropHarvest(new File("/od/tmp/Truterra.sch"), "C3");
    List<String> l = getCropHarvest(new File("/tmp/csip/work/22/13/d09fae44-d38c-11eb-8191-f1753a1bc9f5/Truterra.sch"), "C3", "HARV");
    for (String s : l) {
      System.out.println(s);
    }
//    Map<String, String> c = getMapFor(new File("/od/tmp/Truterra.lis"), "cgracc");

  }

}