package utils;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import model.*;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.util.*;

/**
 * Created by Gondr on 19/05/2017.
 */
public class DataManagerSerialiser extends Serialiser {

    public DataManagerSerialiser(){

    }

    /**
     * serialise DataManger
     * @param dataManager
     * @return
     */
    public boolean serialise(DataManager dataManager){
        ArrayList<Ride> rides = new ArrayList<>(dataManager.getRides());
        ArrayList<Stop> stops = new ArrayList<>(dataManager.getStops());
        ArrayList<Route> routes = new ArrayList<>(dataManager.getRoutes());
        ArrayList<Trip> trips = new ArrayList<>(dataManager.getTrips());
        ArrayList<SharedTrip> sharedTrips = new ArrayList<>(dataManager.getSharedTrips());
        boolean serialRidesSuccess = serialise(rides, "serialisation/rides.json");
        boolean serialStopsSuccess = serialise(stops, "serialisation/stops.json");
        boolean serialRoutesSuccess = serialiseRoutes(routes, "serialisation/routes.json");
        boolean serialTripsSuccess = serialiseTrips(trips, "serialisation/trips.json");
        boolean serialSharedTripsSuccess = serialiseSharedTrips(sharedTrips, "serialisation/sharedtrips.json");
        boolean serialUsersSuccess = serialiseUsers(dataManager.getUsers(), "serialisation/users.json");
        boolean serialDriversSuccess = serialiseDrivers(dataManager.getDrivers(), "serialisation/drivers.json");
        return (serialRidesSuccess && serialStopsSuccess && serialRoutesSuccess && serialTripsSuccess && serialSharedTripsSuccess && serialUsersSuccess && serialDriversSuccess);
    }

    /**
     * Serialises routes
     * @param routes Routes to be serialised
     * @param filepath File path to serialise it to.
     * @return
     */
    public boolean serialiseRoutes(ArrayList<Route> routes, String filepath){
        for (Route route: routes){
            route.serialise();
        }
        try{
            String path = getClass().getClassLoader().getResource(filepath).getPath();
            Writer writer = new OutputStreamWriter(new FileOutputStream(path), "UTF-8");
            gson.toJson(routes, writer);
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * Serialises trips
     * @param trips Trips to be serialised
     * @param filepath File path to serialise it to.
     * @return
     */
    public boolean serialiseTrips(ArrayList<Trip> trips, String filepath){
        for (Trip trip: trips){
            trip.serialise();
        }
        try{
            String path = getClass().getClassLoader().getResource(filepath).getPath();
            Writer writer = new OutputStreamWriter(new FileOutputStream(path), "UTF-8");
            gson.toJson(trips, writer);
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }


    /**
     * Serialises trips
     * @param trips Trips to be serialised
     * @param filepath File path to serialise it to.
     * @return
     */
    public boolean serialiseSharedTrips(ArrayList<SharedTrip> trips, String filepath){
        for (Trip trip: trips){
            trip.serialise();
        }
        try{
            String path = getClass().getClassLoader().getResource(filepath).getPath();
            Writer writer = new OutputStreamWriter(new FileOutputStream(path), "UTF-8");
            gson.toJson(trips, writer);
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public boolean serialiseUsers(Map<String,User> users, String filepath){
        for (String key: users.keySet()){
            users.get(key).serialise();
        }
        try{
            String path = getClass().getClassLoader().getResource(filepath).getPath();
            Writer writer = new OutputStreamWriter(new FileOutputStream(path), "UTF-8");
            gson.toJson(users, writer);
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public boolean serialiseDrivers(Map<String,Driver> drivers, String filepath){
        for (String key: drivers.keySet()){
            drivers.get(key).serialise();
        }
        try{
            String path = getClass().getClassLoader().getResource(filepath).getPath();
            Writer writer = new OutputStreamWriter(new FileOutputStream(path), "UTF-8");
            gson.toJson(drivers, writer);
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    /**
     * loads the data manager from file
     * @return whether the data was loaded properly or not
     * @throws IOException No File
     * @throws NoSuchMethodException No Method to Write
     * @throws IllegalAccessException No access allowed to file
     * @throws InvocationTargetException Thread error
     * @throws InstantiationException Nothing set
     */
    public DataManager load() throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Reader reader = new InputStreamReader(getClass().getClassLoader().getResourceAsStream("serialisation/rides.json"), "UTF-8");
        ArrayList<Ride> rides = gson.fromJson(reader, new TypeToken<ArrayList<Ride>>(){}.getType());
        reader.close();

        Reader reader2 = new InputStreamReader(getClass().getClassLoader().getResourceAsStream("serialisation/stops.json"), "UTF-8");
        ArrayList<Stop> stops = gson.fromJson(reader2, new TypeToken<ArrayList<Stop>>(){}.getType());
        reader2.close();

        Reader reader3 = new InputStreamReader(getClass().getClassLoader().getResourceAsStream("serialisation/routes.json"), "UTF-8");
        ArrayList<Route> routes = gson.fromJson(reader3, new TypeToken<ArrayList<Route>>(){}.getType());
        reader3.close();

        for (Route route: routes){
            route.deserialise();
        }

        Reader reader4 = new InputStreamReader(getClass().getClassLoader().getResourceAsStream("serialisation/trips.json"), "UTF-8");
        ArrayList<Trip> trips = gson.fromJson(reader4, new TypeToken<ArrayList<Trip>>(){}.getType());
        reader4.close();

        for (Trip trip: trips){
            trip.deserialise();
        }

        Reader reader5 = new InputStreamReader(getClass().getClassLoader().getResourceAsStream("serialisation/sharedtrips.json"), "UTF-8");
        ArrayList<SharedTrip> sharedTrips = gson.fromJson(reader5, new TypeToken<ArrayList<SharedTrip>>(){}.getType());
        reader5.close();

        for (SharedTrip trip: sharedTrips){
            trip.deserialise();
        }

        Reader reader6 = new InputStreamReader(getClass().getClassLoader().getResourceAsStream("serialisation/users.json"), "UTF-8");
        HashMap<String, User> users = gson.fromJson(reader6, new TypeToken<HashMap<String, User>>(){}.getType());
        reader6.close();
        for (String userkey: users.keySet()){
            users.get(userkey).deserialise();
        }

        Reader reader7 = new InputStreamReader(getClass().getClassLoader().getResourceAsStream("serialisation/drivers.json"), "UTF-8");
        HashMap<String, Driver> drivers = gson.fromJson(reader7, new TypeToken<HashMap<String, Driver>>(){}.getType());
        reader7.close();
        for (String driverkey: drivers.keySet()){
            drivers.get(driverkey).deserialise();
        }

        return new DataManager(rides, stops, routes, trips, sharedTrips, users, drivers);
    }

}
