/**
   * reads in time plan file, including start, end, depart, arrive, origin,destination, time of
   * walk, drive and transit, store them into a map. the key of this map is a describe of this time
   * plan, for example from which hotspots to which streets block vice verse, the value is the time
   * plan.
   */
  public void readFile(String travelCostFilePath, HouseholdPool householdPool) {

    String pattern = "\\d+";

    final int hholdColumn = 0;

    final int personColumn = 1;

    final int tripColumn = 3;

    // final int modeColumn = 10;

    final int originColumn = 7;

    final int destinationColumn = 8;

    // final int purposeColumn = 9;

    final int walkTimeColumn = 19;

    final int driveTimeColumn = 20;

    final int transitTimeColumn = 21;

    final int waitTimeColumn = 22;

    final int otherTimeColumn = 23;

    final int costColumn = 25;

    // =======2nd row

    final int legTypeColumn = 1;
    final int legIdColumn = 2;
    final int legTimeColumn = 3;

    String[] nextline;
    CSVReader csvReader = null;
    CSVWriter csvWriter = null;

    if (logger.isTraceEnabled()) {
      logger.trace("Dumping household pool");
      for (Map.Entry<Integer, Household> household : householdPool.getHouseholds().entrySet()) {
        logger.trace("Household: " + household.getKey());
        logger.trace(household.getValue().toString());
      }
    }

    String[] headings = {
      "household id",
      "person id",
      "trip id",
      "pirpose",
      "mode",
      "total travel time",
      "income",
      "travel cost"
    };

    try {
      // Skip first two lines as they are headers.
      csvReader =
          new CSVReader(
              new BufferedReader(new FileReader(new File(timePlanFilePath))),
              '\t',
              CSVParser.DEFAULT_QUOTE_CHARACTER,
              2);

      csvWriter = new CSVWriter(new BufferedWriter(new FileWriter(travelCostFilePath)));
      csvWriter.writeNext(headings);

      double[] legs = new double[2];

      int lastHholdID = 0;
      // get the last household ID in the pool to determine trips started within the study area.
      for (Household household : main.getHouseholdPool().getHouseholds().values()) {
        if (household.getId() > lastHholdID) {
          lastHholdID = household.getId();
        }
      }

      while ((nextline = csvReader.readNext()) != null) {
        if (nextline[0].matches(pattern)) {
          // ========trips time=====
          if (legs[0] != 0) {
            ArrayList<Double> trips = (ArrayList<Double>) linksTripsTime.get((int) legs[0]);
            if (trips == null) {
              ArrayList<Double> temp = new ArrayList<>();
              temp.add(legs[1]);
              linksTripsTime.put((int) legs[0], temp);
            } else {
              trips.add(legs[1]);
            }
          }
          legs[0] = legs[1] = 0;

          // ======time plan=====
          /*
           * Only read Time plan with trips that have Origin inside
           * study area, which means all trips with ID less than or
           * equal to "maxID" in HholdPool. The other trips with ID,
           * which is greater than "maxID" in HholdPool, have Origin
           * outside study area
           */
          if (Integer.parseInt(nextline[hholdColumn].trim()) <= lastHholdID) {

            TimePlan timePlan = new TimePlan();

            String editedValue = nextline[originColumn].replace("\"", "").trim();
            timePlan.setOrigin(Integer.parseInt(editedValue));

            editedValue = nextline[destinationColumn].replace("\"", "").trim();
            timePlan.setDestination(Integer.parseInt(editedValue));

            editedValue = nextline[walkTimeColumn].replace("\"", "").trim();
            timePlan.setWalkTime(Double.parseDouble(editedValue));

            editedValue = nextline[driveTimeColumn].replace("\"", "").trim();
            timePlan.setDriveTime(Double.parseDouble(editedValue));

            editedValue = nextline[transitTimeColumn].replace("\"", "").trim();
            timePlan.setTransitTime(Double.parseDouble(editedValue));

            editedValue = nextline[waitTimeColumn].replace("\"", "").trim();
            timePlan.setWaitTime(Double.parseDouble(editedValue));

            editedValue = nextline[otherTimeColumn].replace("\"", "").trim();
            timePlan.setWaitTime(Double.parseDouble(editedValue));

            editedValue = nextline[hholdColumn].replace("\"", "").trim();
            int hhold = Integer.parseInt(editedValue);
            timePlan.setHhold(hhold);

            editedValue = nextline[personColumn].replace("\"", "").trim();
            int person = Integer.parseInt(editedValue);
            timePlan.setPerson(person);

            editedValue = nextline[tripColumn].replace("\"", "").trim();
            int trip = Integer.parseInt(editedValue);
            timePlan.setTrip(trip);

            timePlan.setStart(0);
            timePlan.setEnd(0);
            timePlan.setDepart(0);
            timePlan.setArrive(0);

            /* save successful into Hash Map */
            String hhPersonTrip = String.valueOf(hhold) + "_" + person + "_" + trip;
            // logger.debug(hhPersonTrip);

            // for testing only if commented
            try {
              int mode = main.getHmHhPersonTripTravelMode().get(hhPersonTrip);
              timePlan.setMode(TravelModes.classify(mode));
            } catch (Exception e) {
              logger.error("Exception caught", e);
              logger.debug(hhPersonTrip);
            }

            String label = generateLabel(timePlan.getOrigin(), timePlan.getDestination());

            timePlan.setParkingFee(new BigDecimal(Double.parseDouble(nextline[costColumn])));

            if (main.getHmHhPersonTripTravelMode().get(hhPersonTrip) != null) {
              timePlan.setCost(
                  travelModeSelection
                      .calculateCost(
                          TravelModes.classify(
                              main.getHmHhPersonTripTravelMode()
                                  .get(String.valueOf(hhold) + "_" + person + "_" + trip)),
                          timePlan)
                      .doubleValue());
            }
            TimePlan storedTimePlan = timePlanMap.get(label);
            if (storedTimePlan == null) {
              timePlanMap.put(label, timePlan);
            } else {
              timePlanMap.put(label, compareCost(timePlan, storedTimePlan));
            }

            // store travel cost of each individual in the csv files
            // for testing only if commented
            //						logger.debug(householdPool.getByID(hhold));
            //
            //                        Household household = householdPool.getByID(hhold);
            //
            //                        if (household != null) {
            //                            if (household.getResidents().size() > (person - 1)) {
            //                                storeTravelCost(
            //                                        household.getResidents()
            //                                                .get(person - 1).getIncome(),
            //                                        timePlan, csvWriter);
            //                            } else {
            //                                logger.warn("Individual with ID: " + person + "
            // doesn't exist in household: " + hhold + ". Skipping entry");
            //                            }
            //                        } else {
            //                            logger.warn("Household with ID: " + hhold + " doesn't
            // exist in Pool. Skipping entry");
            //                        }

            /*
             * setup Delta FixedCost & Variable Cost for new Travel
             * Mode Choice design
             */
            setupDeltaFixedCostVariableCost(timePlan, hhPersonTrip);
          }
        } else {
          if (nextline[legTypeColumn].contains("LINK")) {
            if (legs[0] == 0) {
              legs[0] = Math.abs(Double.parseDouble(nextline[legIdColumn]));
              legs[1] = Double.parseDouble(nextline[legTimeColumn]);
            } else {
              if (legs[1] < Double.parseDouble(nextline[legTimeColumn])) {
                legs[0] = Math.abs(Double.parseDouble(nextline[legIdColumn]));
                legs[1] = Double.parseDouble(nextline[legTimeColumn]);
              }
            }
          }
        }
      }

    } catch (FileNotFoundException e) {
      logger.error("Exception caught", e);
    } catch (IOException e) {
      logger.error("Exception caught", e);
    } finally {
      try {
        if (csvReader != null) {
          csvReader.close();
        }
        if (csvWriter != null) {
          csvWriter.close();
        }
      } catch (IOException e) {
        logger.error("Exception caught", e);
      }
    }
  }
  /**
   * Reads in time plan file, including start, end, depart, arrive, origin,destination, time of
   * walk, drive and transit, store them into a map. The key of this map is a describe of this time
   * plan, for example from which hot-spots to which streets block vice verse, the value is the time
   * plan.
   *
   * <p>After that, using time of walk, drive and transit of the car driver to assign for the car
   * passenger and calculate the delta fixed cost and variable cost in order to make the travel mode
   * choice in the next step
   *
   * @author vlcao
   */
  public void readFileFixedTimeCarPax() {

    String pattern = "\\d+";

    final int hholdColumn = 0;

    final int personColumn = 1;

    final int tripColumn = 3;

    final int originColumn = 7;

    final int destinationColumn = 8;

    final int walkTimeColumn = 19;

    final int driveTimeColumn = 20;

    final int transitTimeColumn = 21;

    final int waitTimeColumn = 22;

    final int otherTimeColumn = 23;

    final int costColumn = 25;

    // =======2nd row

    final int legTypeColumn = 1;
    final int legIdColumn = 2;
    final int legTimeColumn = 3;

    String[] nextline;
    CSVReader csvReader = null;

    try {
      csvReader =
          new CSVReader(new BufferedReader(new FileReader(new File(timePlanFilePath))), '\t');

      nextline = csvReader.readNext();
      nextline = csvReader.readNext();

      double[] legs = new double[2];

      int lastHholdID = 0;
      // get the last household ID in the pool to determine trips started within the study area.
      for (Household household : main.getHouseholdPool().getHouseholds().values()) {
        if (household.getId() > lastHholdID) {
          lastHholdID = household.getId();
        }
      }

      while ((nextline = csvReader.readNext()) != null) {
        if (nextline[0].matches(pattern)) {
          // ========trips time=====
          if (legs[0] != 0) {
            ArrayList<Double> trips = (ArrayList<Double>) linksTripsTime.get((int) legs[0]);
            if (trips == null) {
              ArrayList<Double> temp = new ArrayList<>();
              temp.add(legs[1]);
              linksTripsTime.put((int) legs[0], temp);
            } else {
              trips.add(legs[1]);
            }
          }
          legs[0] = legs[1] = 0;

          // ======time plan=====
          /*
           * Only read Time plan with trips that have Origin inside
           * study area, which means all trips with ID less than or
           * equal to "maxID" in HholdPool. The other trips with ID,
           * which is greater than "maxID" in HholdPool, have Origin
           * outside study area
           */
          if (Integer.parseInt(nextline[hholdColumn].trim()) <= lastHholdID) {

            TimePlan timePlan = new TimePlan();

            String editedValue = nextline[originColumn].replace("\"", "").trim();
            timePlan.setOrigin(Integer.parseInt(editedValue));

            editedValue = nextline[destinationColumn].replace("\"", "").trim();
            timePlan.setDestination(Integer.parseInt(editedValue));

            editedValue = nextline[walkTimeColumn].replace("\"", "").trim();
            timePlan.setWalkTime(Double.parseDouble(editedValue));

            editedValue = nextline[driveTimeColumn].replace("\"", "").trim();
            timePlan.setDriveTime(Double.parseDouble(editedValue));

            editedValue = nextline[transitTimeColumn].replace("\"", "").trim();
            timePlan.setTransitTime(Double.parseDouble(editedValue));

            editedValue = nextline[waitTimeColumn].replace("\"", "").trim();
            timePlan.setWaitTime(Double.parseDouble(editedValue));

            editedValue = nextline[otherTimeColumn].replace("\"", "").trim();
            timePlan.setWaitTime(Double.parseDouble(editedValue));

            editedValue = nextline[hholdColumn].replace("\"", "").trim();
            int hhold = Integer.parseInt(editedValue);
            timePlan.setHhold(hhold);

            editedValue = nextline[personColumn].replace("\"", "").trim();
            int person = Integer.parseInt(editedValue);
            timePlan.setPerson(person);

            editedValue = nextline[tripColumn].replace("\"", "").trim();
            int trip = Integer.parseInt(editedValue);
            timePlan.setTrip(trip);

            timePlan.setStart(0);
            timePlan.setEnd(0);
            timePlan.setDepart(0);
            timePlan.setArrive(0);

            /* save successful into Hash Map */
            String hhPersonTrip = String.valueOf(hhold) + "_" + person + "_" + trip;
            // logger.debug(hhPersonTrip);

            // for testing only if commented
            try {
              int mode = main.getHmHhPersonTripTravelMode().get(hhPersonTrip);
              timePlan.setMode(TravelModes.classify(mode));
            } catch (Exception e) {
              logger.error("Exception caught", e);
              logger.debug(hhPersonTrip);
            }

            String label = generateLabel(timePlan.getOrigin(), timePlan.getDestination());

            timePlan.setParkingFee(new BigDecimal(Double.parseDouble(nextline[costColumn])));

            if (main.getHmHhPersonTripTravelMode().get(hhPersonTrip) != null) {
              timePlan.setCost(
                  travelModeSelection
                      .calculateCost(
                          TravelModes.classify(
                              main.getHmHhPersonTripTravelMode()
                                  .get(String.valueOf(hhold) + "_" + person + "_" + trip)),
                          timePlan)
                      .doubleValue());
            }
            TimePlan storedTimePlan = timePlanMap.get(label);
            if (storedTimePlan == null) {
              timePlanMap.put(label, timePlan);
            } else {
              timePlanMap.put(label, compareCost(timePlan, storedTimePlan));
            }

            /* patch 2 for fixed the time of car passenger */

            /* get the "hhPersonTrip" and "person" in Travel Diary */
            String hhPersonTripTD = main.getHhPersonTripConvertedMap().get(hhPersonTrip);

            if (hhPersonTripTD != null) {
              char[] hhPersonTripTDArray = hhPersonTripTD.toCharArray();
              String personTD = "";
              int countUS = 0;

              for (char aHhPersonTripTDArray : hhPersonTripTDArray) {
                if (countUS == 1) {
                  personTD = personTD + aHhPersonTripTDArray;
                }

                if (aHhPersonTripTDArray == '_') {
                  countUS++;

                  if (countUS == 2) {
                    personTD = personTD.replace("_", "");
                    break;
                  }
                }
              }

              /*
               * only assign travel time when this individual exists
               * in the Individual Pool
               */
              if (main.getIndividualPool().getByID(Integer.parseInt(personTD)) != null) {

                /*
                 * when this individual is the Car Passenger, assign the
                 * travel time of his/her Car Driver to his/her
                 * travel time
                 */
                if (main.getOtherHhodCarPaxCarDriverMap().get(hhPersonTripTD) != null) {
                  String carDriver = main.getOtherHhodCarPaxCarDriverMap().get(hhPersonTripTD);

                  // driverTimeMap:
                  // <"HhPersonTrip_TravelDiary",[WalkTime,DriveTime,TransitTime,WaitTime,OtherTime]>

                  if (main.getDriverTimeMap().get(carDriver) != null) {
                    timePlan.setWalkTime(main.getDriverTimeMap().get(carDriver)[0]);
                    timePlan.setDriveTime(main.getDriverTimeMap().get(carDriver)[1]);
                    timePlan.setTransitTime(main.getDriverTimeMap().get(carDriver)[2]);
                    timePlan.setWaitTime(main.getDriverTimeMap().get(carDriver)[3]);
                    timePlan.setOtherTime(main.getDriverTimeMap().get(carDriver)[4]);
                  }
                }

                //								/*
                //								 * when this individual is Under15 child and is the
                //								 * Car Passenger, assign the travel time of his/her
                //								 * Car Driver to his/her travel time
                //								 */
                //								if (main.getIndividualPool()
                //										.getByID(Integer.parseInt(personTD))
                //										.getHouseholdRelationship() == HouseholdRelationship.U15Child
                //										&& main.getU15HhodCarPaxCarDriverMap()
                //												.get(hhPersonTripTD) != null) {
                //
                //									String carDriver = main
                //											.getU15HhodCarPaxCarDriverMap().get(
                //													hhPersonTripTD);
                //
                //									// driverTimeMap:
                //									//
                // <"HhPersonTrip_TravelDiary",[WalkTime,DriveTime,TransitTime,WaitTime,OtherTime]>
                //
                //									if (main.getDriverTimeMap().get(carDriver) != null) {
                //										timePlan.setWalkTime(main
                //												.getDriverTimeMap().get(carDriver)[0]);
                //										timePlan.setDriveTime(main
                //												.getDriverTimeMap().get(carDriver)[1]);
                //										timePlan.setTransitTime(main
                //												.getDriverTimeMap().get(carDriver)[2]);
                //										timePlan.setWaitTime(main
                //												.getDriverTimeMap().get(carDriver)[3]);
                //										timePlan.setOtherTime(main
                //												.getDriverTimeMap().get(carDriver)[4]);
                //									}
                //
                //								} else {
                //									/*
                //									 * when this individual is NOT Under15 child,
                //									 * but is still the Car Passenger, assign the
                //									 * travel time of his/her Car Driver to his/her
                //									 * travel time
                //									 */
                //									if (main.getIndividualPool()
                //											.getByID(Integer.parseInt(personTD))
                //											.getHouseholdRelationship() != HouseholdRelationship.U15Child
                //											&& main.getOtherHhodCarPaxCarDriverMap()
                //													.get(hhPersonTripTD) != null) {
                //										String carDriver = main
                //												.getOtherHhodCarPaxCarDriverMap()
                //												.get(hhPersonTripTD);
                //
                //										// driverTimeMap:
                //										//
                // <"HhPersonTrip_TravelDiary",[WalkTime,DriveTime,TransitTime,WaitTime,OtherTime]>
                //
                //										if (main.getDriverTimeMap().get(carDriver) != null) {
                //											timePlan.setWalkTime(main
                //													.getDriverTimeMap().get(
                //															carDriver)[0]);
                //											timePlan.setDriveTime(main
                //													.getDriverTimeMap().get(
                //															carDriver)[1]);
                //											timePlan.setTransitTime(main
                //													.getDriverTimeMap().get(
                //															carDriver)[2]);
                //											timePlan.setWaitTime(main
                //													.getDriverTimeMap().get(
                //															carDriver)[3]);
                //											timePlan.setOtherTime(main
                //													.getDriverTimeMap().get(
                //															carDriver)[4]);
                //										}
                //									}
                //								}
              } else {
                logger.error("Null pointer exception at:" + hhPersonTripTD);
              }
            }
          }
        } else {
          if (nextline[legTypeColumn].contains("LINK")) {
            if (legs[0] == 0) {
              legs[0] = Math.abs(Double.parseDouble(nextline[legIdColumn]));
              legs[1] = Double.parseDouble(nextline[legTimeColumn]);
            } else {
              if (legs[1] < Double.parseDouble(nextline[legTimeColumn])) {
                legs[0] = Math.abs(Double.parseDouble(nextline[legIdColumn]));
                legs[1] = Double.parseDouble(nextline[legTimeColumn]);
              }
            }
          }
        }
      }

    } catch (FileNotFoundException e) {
      logger.error("Exception caught", e);
    } catch (IOException e) {
      logger.error("Exception caught", e);
    } finally {
      try {
        if (csvReader != null) {
          csvReader.close();
        }
      } catch (IOException e) {
        logger.error("Exception caught", e);
      }
    }
  }