/**
   * Starting point
   *
   * @param args
   */
  public static void main(String args[]) {
    System.out.println("Program initialisation");

    // Initializing Logs
    final long startTime = System.currentTimeMillis();

    System.out.println("Initializing logs");

    String logDirectory = "./log";
    String allLogFileName = "all.log";
    String infoLogFileName = "info.log";
    String warningLogFileName = "warning.log";
    String errorLogFileName = "error.log";
    String debugLogFileName = "debug.log";
    String harvesterLogFileName = "log/harvester.log";

    File logdir = new File(logDirectory);
    logdir.mkdir();
    File allFile = new File(logDirectory + "/" + allLogFileName);
    File infoFile = new File(logDirectory + "/" + infoLogFileName);
    File warningFile = new File(logDirectory + "/" + warningLogFileName);
    File errorFile = new File(logDirectory + "/" + errorLogFileName);
    File debugFile = new File(logDirectory + "/" + debugLogFileName);
    File harvesterFile = new File(harvesterLogFileName);

    allFile.delete();
    infoFile.delete();
    warningFile.delete();
    errorFile.delete();
    debugFile.delete();

    // Set loggers outputs
    try {
      FileOutputStream allFileOutputStream = new FileOutputStream(allFile, true);
      FileOutputStream harvesterFileOutputStream = new FileOutputStream(harvesterFile, true);
      FileOutputStream infoFileOutputStream = new FileOutputStream(infoFile, true);
      FileOutputStream warningFileOutputStream = new FileOutputStream(warningFile, true);
      FileOutputStream errorFileOutputStream = new FileOutputStream(errorFile, true);
      FileOutputStream debugFileOutputStream = new FileOutputStream(debugFile, true);
      RFHarvesterLogger.setInfoLog(
          new TeeOutputStream(
              System.out,
              new TeeOutputStream(
                  harvesterFileOutputStream,
                  new TeeOutputStream(allFileOutputStream, infoFileOutputStream))));
      RFHarvesterLogger.setWarningLog(
          new TeeOutputStream(
              System.out,
              new TeeOutputStream(
                  harvesterFileOutputStream,
                  new TeeOutputStream(allFileOutputStream, warningFileOutputStream))));
      RFHarvesterLogger.setErrorLog(
          new TeeOutputStream(
              System.out,
              new TeeOutputStream(
                  harvesterFileOutputStream,
                  new TeeOutputStream(allFileOutputStream, errorFileOutputStream))));
      RFHarvesterLogger.setDebugLog(
          new TeeOutputStream(
              System.out,
              new TeeOutputStream(
                  harvesterFileOutputStream,
                  new TeeOutputStream(allFileOutputStream, debugFileOutputStream))));
    } catch (FileNotFoundException e) {
      e.printStackTrace();
      System.exit(
          ExitCodes.EX_CANTCREAT.value()); // Program won't run without correctly set loggers.
    }

    RFHarvesterLogger.setDatation(true);
    RFHarvesterLogger.info("Logs correctly initialized");

    RFHarvesterState.begin();

    Runtime.getRuntime()
        .addShutdownHook(
            new Thread() {
              @Override
              public void run() {
                if (RFHarvesterState.checkRunningStatus() > 0) {
                  RFHarvesterState.updateStatus("Interrompue");
                  RFHarvesterState.updateMessage("Moisson interrompue.");
                }
                RFHarvesterState.endStatus();
                long endTime = System.currentTimeMillis();
                RFHarvesterLogger.info(
                    "Program ended at:   " + RFHarvesterDatation.getDateHour(endTime));
                RFHarvesterLogger.info(
                    "Program Total duration : "
                        + RFHarvesterDatation.duration(endTime - startTime));
                RFHarvesterLogger.info(
                    "------------------------------------------------------------------------------------------------------------------------");
                RFHarvesterLogger.debug(
                    "------------------------------------------------------------------------------------------------------------------------");
                RFHarvesterLogger.warning(
                    "------------------------------------------------------------------------------------------------------------------------");
                RFHarvesterLogger.error(
                    "------------------------------------------------------------------------------------------------------------------------");
              }
            });

    RFHarvesterLogger.info("Program started at: " + RFHarvesterDatation.getDateHour(startTime));

    MainClass program = new MainClass();
    ArrayList<String> arguments = new ArrayList<String>(Arrays.asList(args));

    int flags = 0b00000000000000000000000000000000;
    final int harvestFlag = 0b00000000000000000000000000000001;
    final int harvestParameter = 0b00000000000000000000000000000100;

    for (String arg : arguments) {
      RFHarvesterLogger.debug(arg);
      String[] argWithValues = arg.split("=");
      switch (argWithValues[0]) {
        case "--harvest":
          flags |= harvestFlag;
          if (argWithValues.length > 1) flags |= harvestParameter;
          break;
          // NEW WAY TO RUN CONFIGURATION, OTHER ONES ARE DEPRECATED
        case "--configuration":
          int exitCode = ExitCodes.EX_OK.value();
          if (argWithValues.length <= 1) {
            RFHarvesterLogger.error("ERROR: Missing configuration value.");
            RFHarvesterState.updateStatus("ERREUR!!!");
            RFHarvesterState.updateMessage("Missing configuration value.");
            exitCode = ExitCodes.EX_USAGE.value();
          } else {
            try {
              RFHarvesterState.updateConfiguration("ID: " + argWithValues[1]);
              program.runConfiguration(argWithValues[1]);
              RFHarvesterState.updateStatus("Terminée");
            } catch (Exception e) {
              String exceptionMessage = RFHarvesterLogger.exceptionToString(e);
              RFHarvesterLogger.error("FATAL ERROR!!!" + exceptionMessage);
              RFHarvesterState.updateStatus("ERREUR!!!");
              RFHarvesterState.updateMessage(exceptionMessage.split("\n")[1].trim());
              exitCode = ExitCodes.EX_SOFTWARE.value();
            }
          }
          System.exit(exitCode);
          break;

        case "--info":
        case "--list-properties":
        case "--version":
          break;
        default:
          System.out.println("Unknown property: " + argWithValues[0]);
          System.exit(ExitCodes.EX_USAGE.value());
          break;
      }
    }
    if (((flags & harvestFlag) != harvestFlag)) {
      System.out.println("Missing mandatory property --harvest");
      System.exit(ExitCodes.EX_USAGE.value());
    } else if ((flags & harvestParameter) != harvestParameter) {
      System.out.println("Property --harvest have no defined value");
      System.exit(ExitCodes.EX_USAGE.value());
    }

    String harvest = null;
    for (String arg : arguments) {
      String[] argWithValues = arg.split("=");
      switch (argWithValues[0]) {
        case "--list-properties":
          System.getProperties().list(System.out);
          break;
        case "--restore":
          if (argWithValues.length > 2) {
            System.out.println("Property --harvest wrongly defined: " + arg.substring(10));
            System.exit(ExitCodes.EX_USAGE.value());
          }
          harvest = argWithValues[1];
          break;
        case "--harvest":
          if (argWithValues.length > 2) {
            System.out.println("Property --harvest wrongly defined: " + arg.substring(10));
            System.exit(ExitCodes.EX_USAGE.value());
          }
          harvest = argWithValues[1];
          break;
        default:
          break;
      }
    }

    if (((flags & harvestFlag) == harvestFlag)) {
      switch (harvest) {
        case "portfolio":
          program.harvestPortfolio();
          RFHarvesterState.updateStatus("Terminée");
          break;
        case "authorities":
          program.harvestAuthorities();
          RFHarvesterState.updateStatus("Terminée");
          break;
        default:
          RFHarvesterLogger.error("Unrecognized harvesting value: " + harvest);
          break;
      }
    }
  }