import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.antlr.runtime.ANTLRInputStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;

import airlineMajorExample.AirplaneType;
import airlineMajorExample.Airport;
import airlineMajorExample.FlightTracker;
import airlineMajorExample.Frequency;
import airlineMajorExample.RegularFlight;
import airlineMajorExample.RegularFlightSchedule;
import airlineMajorExample.RegularLeg;

public class Runner {
  private static final int NUM_OF_ENTRIES = 2000;

  boolean VERBOSE = false;

  boolean trackerCreated = false;
  
  FlightTracker tracker = null;
  
  // int suffix = 0;
  String line = "";

  FileWriter fw = null;

  BufferedWriter bw = null;

  String lastFlightID = null;

  Map<String, AirplaneType> planes = null;

  Map<String, Airport> airports = null;

  Map<String, Frequency> frequencies = null;

  Map<String, RegularFlight> regularFlights = null;

  Runner() {
    try {
      fw =
        new FileWriter(
          "C:\\Users\\Dusani\\Desktop\\Work\\dev\\docs\\Major Umple Examples\\Airline\\TestScript.txt");
      bw = new BufferedWriter(fw);
      planes = new HashMap<String, AirplaneType>();
      airports = new HashMap<String, Airport>();
      frequencies = new HashMap<String, Frequency>();
      regularFlights = new HashMap<String, RegularFlight>();
      lastFlightID = "";
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  public void start() {
    String filePath =
      "C:\\Users\\Dusani\\Desktop\\Work\\dev\\docs\\Major Umple Examples\\Airline\\AirCanadaSched-CleanExtractedData-June2008.csv";
    try {
      FileReader fis = null;
      BufferedReader bis = null;

      fis = new FileReader(filePath);

      bis = new BufferedReader(fis);

      line = bis.readLine();
      int count = 0;
      line = bis.readLine();
      do {
        ANTLRInputStream ANTLRinput =
          new ANTLRInputStream(new ByteArrayInputStream(line.getBytes()));

        // Create an ExprLexer that feeds from that stream
        CSVParserLexer lexer = new CSVParserLexer(ANTLRinput);

        // Create a stream of tokens fed by the lexer
        CommonTokenStream tokens = new CommonTokenStream(lexer);

        // Create a parser that feeds off the token stream
        CSVParserParser parser = new CSVParserParser(tokens);

        // Begin parsing at rule start, get return value structure
        parser.start(this);

        line = bis.readLine();
        count++;
      } while (line != null && count < NUM_OF_ENTRIES);
      fw.close();
      bw.close();

      System.out.println("Done.");
    } catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (RecognitionException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

  }

  public void createEntry(String flightID, String departureTime,
    String arrivalTime, String symbol, String originSymbol, String originName,
    String destSymbol, String destName, String validDates, String planeType,
    String frequency) {

    if(!trackerCreated){
      createTracker();
      trackerCreated = true;
    }
    
    if (!containsRegularFlight(flightID)) {
      /*
       * if (suffix != 0) suffix = 0;
       */
      if (VERBOSE) {
        try {
          fw.write("//" + line + "\n");
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
      // planes = new HashMap<String, AirplaneType>();
      // airports = new HashMap<String, Airport>();
      // frequencies = new HashMap<String, Frequency>();
      regularFlights = new HashMap<String, RegularFlight>();

      createAirplaneType(planeType);

      createAirport(originSymbol, originName);

      createAirport(destSymbol, destName);

      createFrequency(frequency);

      createRegularFlight(flightID);

      createRegularLeg(flightID, originSymbol, destSymbol, 0);

      createRegularFlightSchedule(flightID, validDates, planeType, 0);

      createRegularLegSchedule(flightID, departureTime, arrivalTime, frequency,
        originSymbol, destSymbol, planeType, 0, 0);

      insertComment();
      System.out.println(flightID);
    } else {
      // suffix++;
      int legSuffix = 0;
      // int legSchedSuffix = 0;
      int fligtSchedSuffix = 0;
      RegularLeg theLeg = null;
      RegularFlightSchedule theFlightSchedule = null;
      RegularFlight theFlight = regularFlights.get(flightID);

      if (VERBOSE) {
        try {
          fw.write("//" + line + "\n");
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }

      // These parameters can change between different schedules and legs
      // and they aren't added multiple times.
      createAirplaneType(planeType);
      createAirport(originSymbol, originName);
      createAirport(destSymbol, destName);
      createFrequency(frequency);

      // Determine same or different dates - effects if we create new
      // RegularFlightSchedule
      for (RegularLeg leg : theFlight.getRegularLegs()) {
        if (leg.getOrigin().getCode().equals(originSymbol)
          && leg.getDestination().getCode().equals(destSymbol)) {
          theLeg = leg;
          break;
        } else
          legSuffix++;
      }

      if (theLeg == null) {
        createRegularLeg(flightID, originSymbol, destSymbol, legSuffix);
        for (RegularLeg leg : theFlight.getRegularLegs()) {
          if (leg.getOrigin().getCode().equals(originSymbol)
            && leg.getDestination().getCode().equals(destSymbol)) {
            theLeg = leg;
          }
        }
      }

      // Determine same or different (origin and destination) - if same, reuse
      // RegularLeg and add new RegularLegSchedule. If different, add both new
      // RegularLegSchedule and RegularLeg
      for (RegularFlightSchedule flightSchedule : theFlight
        .getRegularFlightSchedules()) {
        if ((flightSchedule.getEffectiveDate().equals(validDates) || flightSchedule
          .getDiscontinuedDate().equals(validDates))
          && flightSchedule.getAirplaneType().getTypeCode().equals(planeType)) {
          theFlightSchedule = flightSchedule;
          break;
        } else
          fligtSchedSuffix++;
      }

      if (theFlightSchedule == null) {
        createRegularFlightSchedule(flightID, validDates, planeType,
          fligtSchedSuffix);
        for (RegularFlightSchedule flightSchedule : theFlight
          .getRegularFlightSchedules()) {
          if (flightSchedule.getEffectiveDate().equals(validDates)
            || flightSchedule.getDiscontinuedDate().equals(validDates)) {
            theFlightSchedule = flightSchedule;
          }
        }
      }

      createRegularLegSchedule(flightID, departureTime, arrivalTime, frequency,
        originSymbol, destSymbol, planeType, legSuffix, fligtSchedSuffix);

      insertComment();
      System.out.println(flightID);
    }
  }

  private void createTracker(){
    try {
      fw.write("create FlightTracker tracker\n");
      tracker = new FlightTracker();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
  
  private void createAirplaneType(String type) {
    try {
      if (!containsPlane(type)) {
        fw.write("create AirplaneType Type" + type + "\n");
        fw.write(type + "\n");

        // planes.add(type);
        planes.put(type, new AirplaneType(type));
      }
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  private boolean containsPlane(String type) {
    if (planes.get(type) != null) {
      return true;
    }
    return false;
  }

  private void createAirport(String code, String name) {
    try {
      if (!containsAirport(code)) {
        fw.write("create Airport " + code + "\n");
        fw.write(code + "\n");
        fw.write("set name of " + code + "\n");
        fw.write(name + "\n");

        // airports.add(code);
        Airport airport = new Airport(code);
        airport.setName(name);
        airports.put(code, airport);
      }
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

  }

  private boolean containsAirport(String type) {
    if (airports.get(type) != null) {
      return true;
    }
    return false;
  }

  private void createFrequency(String freq) {
    if (freq.contains(" ")) {
      freq = freq.substring(0, freq.indexOf(' '));
    }
    boolean monday = false;
    boolean tuesday = false;
    boolean wednesday = false;
    boolean thursday = false;
    boolean friday = false;
    boolean saturday = false;
    boolean sunday = false;

    if (freq.startsWith("Daily")) {
      if (!containsFrequency("Daily")) {
        writeFrequency(freq, true, true, true, true, true, true, true);
      }
    } else if (freq.startsWith("X")) {
      if (!containsFrequency(freq)) {
        if (freq.contains("1"))
          monday = false;
        else
          monday = true;
        if (freq.contains("2"))
          tuesday = false;
        else
          tuesday = true;
        if (freq.contains("3"))
          wednesday = false;
        else
          wednesday = true;
        if (freq.contains("4"))
          thursday = false;
        else
          thursday = true;
        if (freq.contains("5"))
          friday = false;
        else
          friday = true;
        if (freq.contains("6"))
          saturday = false;
        else
          saturday = true;
        if (freq.contains("7"))
          sunday = false;
        else
          sunday = true;
        writeFrequency(freq, monday, tuesday, wednesday, thursday, friday,
          saturday, sunday);
      }
    } else {
      if (!containsFrequency(freq)) {
        if (freq.contains("1"))
          monday = true;
        if (freq.contains("2"))
          tuesday = true;
        if (freq.contains("3"))
          wednesday = true;
        if (freq.contains("4"))
          thursday = true;
        if (freq.contains("5"))
          friday = true;
        if (freq.contains("6"))
          saturday = true;
        if (freq.contains("7"))
          sunday = true;
        writeFrequency(freq, monday, tuesday, wednesday, thursday, friday,
          saturday, sunday);
      }
    }
  }

  private boolean containsFrequency(String type) {
    if (frequencies.get(type) != null) {
      return true;
    }
    return false;
  }

  private void createRegularLegSchedule(String flightID, String depTime,
    String arrTime, String freq, String origin, String destination,
    String airplaneType, int legSuffix, int flightSuffix) {
    int indexOfPlus = arrTime.indexOf('+');
    String variance = null;
    if (indexOfPlus != -1) {
      variance = arrTime.substring(indexOfPlus + 1);
      arrTime = arrTime.substring(0, indexOfPlus);
    }

    try {
      fw.write("add RegularLegSchedule to RegLeg" + flightID + "-" + legSuffix
        + "\n");
      fw.write("RegLegSched" + flightID + "-" + legSuffix + "-" + flightSuffix
        + "\n");
      fw.write(depTime + "\n");
      fw.write(arrTime + "\n");
      if (variance == null)
        fw.write("0\n");
      else
        fw.write(variance + "\n");
      fw.write("$RegFlightSched" + flightID + "-" + flightSuffix + "\n");

      if (freq.contains(" "))
        freq = freq.substring(0, freq.indexOf(' '));

      fw.write("$" + freq + "\n");

      // In-memory representation part.
      RegularLeg theLeg = null;
      for (RegularLeg leg : regularFlights.get(flightID).getRegularLegs()) {
        if (leg.getOrigin().getCode().equals(origin)
          && leg.getDestination().getCode().equals(destination)) {
          theLeg = leg;
          break;
        }
      }
      if (theLeg == null)
        throw new IOException("Leg was null. Runner, line 367.");

      RegularFlightSchedule theRFS = null;
      for (RegularFlightSchedule rfs : regularFlights.get(flightID)
        .getRegularFlightSchedules()) {
        if (rfs.getAirplaneType().getTypeCode().equals(airplaneType)) {
          theRFS = rfs;
          break;
        }
      }

      if (theRFS == null)
        throw new IOException();

      if (variance == null)
        theLeg.addRegularLegSchedule(depTime, arrTime, 0, theRFS, frequencies
          .get(freq));
      else
        theLeg.addRegularLegSchedule(depTime, arrTime, Integer
          .parseInt(variance), theRFS, frequencies.get(freq));

    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      System.exit(1);
    }
  }

  private void createRegularFlightSchedule(String flightID, String validDates,
    String planeType, int flightSuffix) {

    try {
      fw.write("add RegularFlightSchedule to RegFlight" + flightID + "\n");
      fw.write("RegFlightSched" + flightID + "-" + flightSuffix + "\n");
      if (validDates.contains("Disc")) {
        fw.write("all\n");
        fw.write(validDates + "\n");

        regularFlights.get(flightID).addRegularFlightSchedule("", validDates,
          planes.get(planeType));
      } else if (validDates.contains("Eff")) {
        fw.write(validDates + "\n");
        fw.write("all\n");

        regularFlights.get(flightID).addRegularFlightSchedule(validDates, "",
          planes.get(planeType));
      } else if (validDates.contains("Exc")) {
        fw.write("all\n");
        fw.write("none\n");

        regularFlights.get(flightID).addRegularFlightSchedule("", "",
          planes.get(planeType));
      } else {
        fw.write("all\n");
        fw.write("none\n");

        regularFlights.get(flightID).addRegularFlightSchedule("", "",
          planes.get(planeType));
      }
      fw.write("$Type" + planeType + "\n");

    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  private void createRegularLeg(String flightID, String originAirport,
    String destAirport, int legSuffix) {
    try {
      fw.write("add RegularLeg to RegFlight" + flightID + "\n");
      fw.write("RegLeg" + flightID + "-" + legSuffix + "\n");
      fw.write("$" + destAirport + "\n");
      fw.write("$" + originAirport + "\n");

      regularFlights.get(flightID).addRegularLeg(airports.get(destAirport),
        airports.get(originAirport));
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  private void createRegularFlight(String flightID) {
    try {
      fw.write("create RegularFlight RegFlight" + flightID + "\n");
      fw.write(flightID + "\n");
      fw.write("$tracker\n");

      // regularFlights.add(flightID);
      regularFlights.put(flightID, new RegularFlight(flightID, tracker));
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  private boolean containsRegularFlight(String type) {
    if (regularFlights.get(type) != null) {
      return true;
    }
    return false;
  }

  private void writeFrequency(String name, boolean monday, boolean tuesday,
    boolean wednesday, boolean thursday, boolean friday, boolean saturday,
    boolean sunday) {
    try {
      fw.write("create Frequency " + name + "\n");
      fw.write(monday + "\n");
      fw.write(tuesday + "\n");
      fw.write(wednesday + "\n");
      fw.write(thursday + "\n");
      fw.write(friday + "\n");
      fw.write(saturday + "\n");
      fw.write(sunday + "\n");
      // frequencies.add(name);
      frequencies.put(name, new Frequency(monday, tuesday, wednesday, thursday,
        friday, saturday, sunday));
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  private void insertComment() {
    try {
      // fw.write("\n//New record\n");
      fw.write("\n");
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

  }
}
