package ch.epfl.isochrone.timetable;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import ch.epfl.isochrone.geo.PointWGS84;

/**
 * Classe servant à lire les horaires
 * 
 * @author Charles Thiebaut (238935) 
 * @author Arnaud Delamare (234841)
 *
 */

public final class TimeTableReader {
    private String prefixe;
    
    public TimeTableReader(String baseResourceName)
    {
        this.prefixe=baseResourceName;
    }
    
    public TimeTable readTimeTable() throws IOException 
    {
        TimeTable.Builder tb = readStops(new TimeTable.Builder());
        
        tb = readServices(tb);
        
        return tb.build();
    }
    
    public Graph readGraphForServices(Set<Stop> stops, Set<Service> services, int walkingTime, double walkingSpeed) throws IOException
    {
        Graph.Builder gb = new Graph.Builder(stops);
        
        InputStream stopsStream = getClass().getResourceAsStream(prefixe + "stops_times.csv");
        
        BufferedReader reader = new BufferedReader( new InputStreamReader(stopsStream, StandardCharsets.UTF_8));
        String line;
        String champs[];
        Stop stop1 = null, stop2 = null;
        while ((line = reader.readLine()) != null) {
            champs = line.split(";");
            
            for (Service s : services)
            {
                if (s.name().equals(champs[0]))
                {
                    for (Stop st : stops)
                    {
                        if (st.name().equals(champs[1]))
                        {
                            stop1 = st;
                        }
                        if (st.name().equals(champs[3]))
                        {
                            stop2 = st;
                        }
                        
                        gb.addTripEdge(stop1, stop2, Integer.parseInt(champs[2]), Integer.parseInt(champs[4]));
                    }
                }
            }
        }
        reader.close();
        
        gb.addAllWalkEdges(walkingTime, walkingSpeed);
        
        return gb.build(); 
    }
    
    private TimeTable.Builder readStops(TimeTable.Builder tb) throws IOException 
    {
        InputStream stopsStream = getClass().getResourceAsStream(prefixe + "stops.csv");
        
        BufferedReader reader = new BufferedReader( new InputStreamReader(stopsStream, StandardCharsets.UTF_8));
        String line;
        String champs[];
        while ((line = reader.readLine()) != null) {
            champs = line.split(";");
            tb.addStop(new Stop(champs[0], new PointWGS84(Double.parseDouble(champs[1]), Double.parseDouble(champs[2]))));
        }
        reader.close();
        
        return tb;
    }
    
    private TimeTable.Builder readServices(TimeTable.Builder tb) throws IOException 
    {
        InputStream serviceStream = getClass().getResourceAsStream(prefixe + "calendar.csv");
        
        BufferedReader reader = new BufferedReader( new InputStreamReader(serviceStream, StandardCharsets.UTF_8));
        List<Service.Builder> sbListe = new ArrayList<Service.Builder>();
        Service.Builder sb;
        String line;
        String champs[];
        Date.DayOfWeek[] tab = Date.DayOfWeek.values();
        
        while ((line = reader.readLine()) != null) {
            champs = line.split(";");
            sb = new Service.Builder(champs[0], stringToDate(champs[8]), stringToDate(champs[9]));
            
            for (int i=1; i<=7; i++)
            {
                if (Integer.parseInt(champs[i])==1)
                {
                    sb.addOperatingDay(tab[i-1]);
                }
            }
            
            sbListe.add(sb);
        }
        reader.close();
        
        
        InputStream serviceStream2 = getClass().getResourceAsStream(prefixe + "calendar_dates.csv");
        
        BufferedReader reader2 = new BufferedReader( new InputStreamReader(serviceStream, StandardCharsets.UTF_8));
        
        while ((line = reader.readLine()) != null) {
            champs = line.split(";");
            
            for (Service.Builder sb2 : sbListe)
            {
                if (sb2.name().equals(champs[0]))
                {
                    if (Integer.parseInt(champs[2])==1)
                    {
                        sb2.addIncludedDate(stringToDate(champs[1]));
                    }
                    else
                    {
                        sb2.addExcludedDate(stringToDate(champs[1]));
                    }
                }
            }
        }
        reader.close();
        
        for (Service.Builder sb2 : sbListe)
        {
            tb.addService(sb2.build());
        }
        
        return tb;
    }
    
    private Date stringToDate(String s){
        
        return new Date(Integer.parseInt(s.substring(6, 7)), Integer.parseInt(s.substring(4, 5)), Integer.parseInt(s.substring(0, 3)));
    }

}
