@SuppressWarnings("unchecked")
  @ApiMethod(name = "checkTrainAndStationStatus", path = "findmytrain/v1/checkStatus")
  public List<String> checkTrainAndStationStatus(
      @Named("Train id") String id, @Named("Currnet Station") String station) {

    // this method returns the list of stations for a selected train and
    // whether that train has passed each station

    final int STATION_GAP = 5; // five station from the current station to
    // both directions are considered for the
    // calculation
    final int RECORD_THRESHOLD = 10;
    final double PROBABILITY_THRESHOLD_LEFT = 0.65;
    final double PROBABILITY_THRESHOLD_NOT_LEFT = 0.35;
    final double TRANSITION_THRESHOLD = 0.2;
    final int RECORD_CONSIDERATION_LIMIT_NUMBER = 50;
    final int RECORD_CONSIDERATION_LIMIT_MINUTES = 30; // this value can be
    // reduced when the
    // number of users
    // become
    // higher.(since
    // there will be
    // more data to
    // analyze with in
    // the given time
    // period)
    final long ONE_MINUTE_IN_MILLIS = 60000;

    List<String> result = new ArrayList<String>();
    List<Train> trains = new ArrayList<Train>();
    List<Record> records = new ArrayList<Record>();

    PersistenceManager pm = PMF.get().getPersistenceManager();

    Query queryTrain = pm.newQuery(Train.class);
    queryTrain.setFilter("trainid == argTrainId");
    queryTrain.declareParameters("String argTrainId");

    Query queryRecord = pm.newQuery(Record.class);
    queryTrain.setFilter("trainid == argTrainId");
    queryTrain.declareParameters("String argTrainId");

    trains = (List<Train>) queryTrain.execute(id);
    records = (List<Record>) queryRecord.execute(id);
    List<Stop> stops = new ArrayList<Stop>();
    List<Record> tempRecords;
    int stationIndex = 0;
    int initialOneCount;
    int initialZeroCount;
    double probabilityInitial;
    double probabilityTransition;
    int[] centralDifference;
    int transitionCount;

    Date atRequest = new Date();
    SimpleDateFormat parser = new SimpleDateFormat("HH:mm");
    String serverTime = parser.format(atRequest);
    Date serverDate = null;
    Date lowerLimit = null;
    try {
      serverDate = parser.parse(serverTime);
      lowerLimit =
          new Date(
              serverDate.getTime() - (RECORD_CONSIDERATION_LIMIT_MINUTES * ONE_MINUTE_IN_MILLIS));
    } catch (ParseException e) {
      e.printStackTrace();
    }

    stops = trains.get(0).getStops();

    for (int i = 0; i < stops.size(); i++) {
      if (stops.get(i).getStation().equals(station)) stationIndex = i;
    }

    int loopStart = stationIndex >= STATION_GAP ? stationIndex - STATION_GAP : 0;
    int loopEnd =
        stationIndex + STATION_GAP < stops.size() ? stationIndex + STATION_GAP : stops.size();

    for (int i = loopStart; i < loopEnd; i++) {

      Stop tempStop = stops.get(i);
      String tempStatus = "not sure"; // for the situation where there are
      // not enough data present
      tempRecords = new ArrayList<Record>(); // these are the records used
      // to process the data for
      // each selected station

      initialOneCount = 0;
      initialZeroCount = 0;

      for (Record r : records) {
        if (r.getStation().equals(tempStop.getStation())) {
          tempRecords.add(r);
        }
      }

      // case where there is no data
      if (tempRecords.size() < RECORD_THRESHOLD) {
        result.add(tempStop.getStation() + ":" + tempStatus);
        continue;
      }

      // when there is enough data
      sortRecords(tempRecords);

      // selecting a set of record to perform the analysis based on their
      // recentness and the number of records
      int k = 0;
      for (int j = 0; j < tempRecords.size(); j++) {
        Date tempDate = new Date(tempRecords.get(j).getTimeStamp());
        String tempTime = parser.format(tempDate);
        try {
          Date recordDate = parser.parse(tempTime);
          if (recordDate.after(lowerLimit)) {
            k = j;
            break;
          }
        } catch (ParseException e) {
          e.printStackTrace();
        }
      }

      if (tempRecords.size() - k < RECORD_CONSIDERATION_LIMIT_NUMBER) {
        if (tempRecords.size() < RECORD_CONSIDERATION_LIMIT_NUMBER) {
          k = 0;
        } else k = tempRecords.size() - RECORD_CONSIDERATION_LIMIT_NUMBER;
      }

      for (int j = k; j < tempRecords.size(); j++) {
        // counting the initial ones and zeros
        System.out.print(j + " ");
        if (tempRecords.get(j).getStatus() == 1) initialOneCount++;
        else initialZeroCount++;
      }
      System.out.println();

      probabilityInitial = (double) initialOneCount / (tempRecords.size());

      if (probabilityInitial > PROBABILITY_THRESHOLD_LEFT) {
        tempStatus = "left";
      } else if (probabilityInitial < PROBABILITY_THRESHOLD_NOT_LEFT) {
        tempStatus = "not left";
      } else {
        // using the first central difference formula

        centralDifference = new int[tempRecords.size() - 1];

        for (int j = 1; j < tempRecords.size(); j++) {
          centralDifference[j - 1] =
              tempRecords.get(j).getStatus() - tempRecords.get(j - 1).getStatus();
        }

        transitionCount = 0;

        for (int j : centralDifference) {
          if (j == 1) transitionCount++;
        }

        probabilityTransition = (double) transitionCount / centralDifference.length;

        if (probabilityTransition < TRANSITION_THRESHOLD) {
          tempStatus = "left";
        } else {
          tempStatus = "not sure";
        }
      }
      // at this point data can be further checked to refine the results
      result.add(tempStop.getStation() + ":" + tempStatus);
    }

    return result;
  }
  @SuppressWarnings("unchecked")
  @ApiMethod(name = "listOfTrains", path = "findmytrain/v1/listTrains")
  public List<String> listTrains(@Named("station") String station) throws ParseException {
    // This method should return the list of trains based on the station
    // if a trains stops at the station 'station' that will be added to the
    // 'trains' list
    final long ONE_MINUTE_IN_MILLIS = 60000;
    final int TIME_GAP_IN_MINUTES = 30;
    List<Train> trains = new ArrayList<Train>();
    List<Train> tempTrains = null;

    Date atRequest = new Date();
    SimpleDateFormat parser = new SimpleDateFormat("HH:mm");
    String serverTime = parser.format(atRequest);
    Date serverDate = parser.parse(serverTime);
    Date upperLimit = new Date(serverDate.getTime() + (TIME_GAP_IN_MINUTES * ONE_MINUTE_IN_MILLIS));
    Date lowerLimit = new Date(serverDate.getTime() - (TIME_GAP_IN_MINUTES * ONE_MINUTE_IN_MILLIS));

    // System.out.println("Server date : " + serverDate);
    // System.out.println("Server time : " + serverTime);

    PersistenceManager pm = PMF.get().getPersistenceManager();

    Query q = pm.newQuery(Train.class);

    try {
      tempTrains = (List<Train>) q.execute();
      List<Stop> tempStops = new ArrayList<Stop>();

      for (Train t : tempTrains) {
        tempStops = t.getStops();

        for (Stop s : tempStops) {
          // checking if a selected train stops at the selected
          // station
          if (s.getStation().equals(station)) {

            Date stationTime = parser.parse(s.getTime());

            // checking whether the station time is in between the
            // required time gap
            if (stationTime.after(lowerLimit) && stationTime.before(upperLimit)) {
              trains.add(t);
              break;
            }
          }
        }
      }

    } finally {
      q.closeAll();
    }

    // returning a string list instead of the train list

    List<String> result = new ArrayList<String>();

    for (Train t : trains) {
      result.add("From " + t.getStart() + " To " + t.getDestination() + "\n" + t.getTrainid());
    }
    return result;

    // returning the list of train objects
    // return trains;
  }