@SuppressWarnings("unused")
public class PreferredJourney {

    private PreferredStation station1;
    private PreferredStation station2;
    private long             timestamp;
    private int              priority;
    private String           category;
    private String           version;

    public PreferredJourney(PreferredStation station1, PreferredStation station2) {
        this.station1 = station1;
        this.station2 = station2;
        timestamp = DateTime.now().toInstant().getMillis();
        priority = -1;
        category = "";
        version = "";
    }

    public PreferredJourney swapStations() {
        PreferredStation temp = station1;
        station1 = station2;
        station2 = temp;
        return this;
    }

    public PreferredStation getStation1() {
        return station1;
    }

    public void setStation1(PreferredStation station1) {
        this.station1 = station1;
    }

    public PreferredStation getStation2() {
        return station2;
    }

    public void setStation2(PreferredStation station2) {
        this.station2 = station2;
    }

    public long getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(long timestamp) {
        this.timestamp = timestamp;
    }

    public int getPriority() {
        return priority;
    }

    public void setPriority(int priority) {
        this.priority = priority;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    @Override
    public String toString() {
        return "PreferredJourney{" +
                "station1=" + station1 +
                ", station2=" + station2 +
                ", timestamp=" + timestamp +
                ", priority=" + priority +
                ", category='" + category + '\'' +
                ", version='" + version + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        return timestamp == ((PreferredJourney) o).timestamp;
    }
} @SuppressWarnings("unused")
public class PreferredStation {

    private String stationShortId;
    private String stationLongId;
    private String nameShort;
    private String nameLong;

    private Map<String, Journey.Solution> preferredSolutions;

    public PreferredStation() {
        preferredSolutions = new HashMap<>();
    }

    public PreferredStation(Station station) {
        this.stationShortId = station.getStationShortId();
        this.stationLongId = station.getStationLongId();
        this.nameShort = station.getNameShort();
        this.nameLong = station.getNameLong();
        preferredSolutions = new HashMap<>();
    }

    public PreferredStation(String stationShortId, String stationLongId, String nameShort, String nameLong) {
        this.stationShortId = stationShortId;
        this.stationLongId = stationLongId;
        this.nameShort = nameShort;
        this.nameLong = nameLong;
        preferredSolutions = new HashMap<>();
    }

    public String getStationShortId() {
        return stationShortId;
    }

    public void setStationShortId(String stationShortId) {
        this.stationShortId = stationShortId;
    }

    public String getStationLongId() {
        return stationLongId;
    }

    public void setStationLongId(String stationLongId) {
        this.stationLongId = stationLongId;
    }

    public String getNameShort() {
        return nameShort;
    }

    public void setNameShort(String nameShort) {
        this.nameShort = nameShort;
    }

    public String getNameLong() {
        return nameLong;
    }

    public void setNameLong(String nameLong) {
        this.nameLong = nameLong;
    }

    public Map<String, Journey.Solution> getPreferredSolutions() {
        return preferredSolutions;
    }

    public void addPreferredSolutions(String id, Journey.Solution solution) {
        this.preferredSolutions.put(id, solution);
    }

    public void removePreferredSolutions(String id) {
        this.preferredSolutions.remove(id);
    }

    @Override
    public String toString() {
        return "PreferredStation{" +
                "stationShortId='" + stationShortId + '\'' +
                ", stationLongId='" + stationLongId + '\'' +
                ", nameShort='" + nameShort + '\'' +
                ", nameLong='" + nameLong + '\'' +
                ", preferredSolutions=" + preferredSolutions +
                '}';
    }
} public class DateTimeAdapter implements JsonDeserializer<DateTime>, JsonSerializer<DateTime> {
    @Override
    public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        // Timestamp format
        // "2012-06-11T20:06+00200" format
        return DateTime.parse(json.getAsString());
    }

    @Override
    public JsonElement serialize(DateTime time, Type typeOfT, JsonSerializationContext context) {
        return new JsonPrimitive(time.toString("yyyy-MM-dd'T'HH:mmZ"));
    }
} public class PostProcessingEnabler implements TypeAdapterFactory {

    public interface PostProcessable {
        void postProcess();
    }

    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);

        return new TypeAdapter<T>() {
            public void write(JsonWriter out, T value) throws IOException {
                delegate.write(out, value);
            }

            public T read(JsonReader in) throws IOException {
                T obj = delegate.read(in);
                if (obj instanceof PostProcessable) {
                    ((PostProcessable) obj).postProcess();
                }
                return obj;
            }
        };
    }
} public enum ENUM_SNACKBAR_ACTIONS {

    NONE, REFRESH, SELECT_DEPARTURE, SELECT_ARRIVAL, SELECT_TRAIN_NUMBER, ACCEPT

} public class DatabaseHelper {

    public static List<String> getAll() {
        return Stream
                .of(MyApplication.database.stationDao().getAll())
                .map(Station::getNameFancy).collect(Collectors.toList());
    }


    public static List<String> getElementByNameFancy(String stationName) {
        return Stream
                .of(MyApplication.database.stationDao().getAllByNameFancy("" + stationName + "%", "%_" + stationName + "%"))
                .map(Station::getNameFancy).collect(Collectors.toList());
    }

    public static List<String> getElementByNameShort(String stationName) {
        return Stream
                .of(MyApplication.database.stationDao().getAllByNameShort(stationName))
                .map(Station::getNameLong).collect(Collectors.toList());
    }

    public static boolean isThisJourneyPreferred(PreferredStation departureStation, PreferredStation arrivalStation, Context context) {
        return departureStation != null &&
                arrivalStation != null &&
                PreferredStationsPreferences.isJourneyAlreadyPreferred(
                        context,
                        departureStation,
                        arrivalStation);
    }

    public static boolean isStationNameValid(String stationName) {
        return MyApplication.database.stationDao().isStationNameValid(stationName);
    }

    public static Station getStation4DatabaseObject(String stationName) {
        return MyApplication.database.stationDao().getByWhateverName(stationName);
    }
} public class PreferredStationsPreferences {

    public static boolean isJourneyAlreadyPreferred(Context context, PreferredJourney preferredJourney) {
        return isJourneyAlreadyPreferred(context, preferredJourney.getStation1().getStationShortId(), preferredJourney.getStation2().getStationShortId());
    }

    public static boolean isJourneyAlreadyPreferred(Context context, PreferredStation departureStation, PreferredStation arrivalStation) {
        return isJourneyAlreadyPreferred(context, departureStation.getStationShortId(), arrivalStation.getStationShortId());
    }

    public static boolean isJourneyAlreadyPreferred(Context context, String id1, String id2) {
        return isJourneyAlreadySaved(context, FAVOURITES, id1, id2);
    }
//    ------------------------------------------------------------------------------------------------------------------------

    public static void setPreferredJourney(Context context, PreferredJourney journey) {
        setSavedJourney(context, FAVOURITES, journey);
        RecentStationsPreferences.removeRecentJourney(context, journey);
    }

//    ------------------------------------------------------------------------------------------------------------------------

    public static boolean isPossibleToSaveMorePreferredJourneys(Context context) {
        return getAllPreferredJourneys(context).size() < 5;
    }

//    ------------------------------------------------------------------------------------------------------------------------

    public static boolean isPossibleToSaveMorePreferredSolutions(PreferredStation station) {
        return station.getPreferredSolutions().size() < 3;
    }

//    ------------------------------------------------------------------------------------------------------------------------

    public static boolean isSolutionAlreadyPreferred(Context context, PreferredJourney journey, Journey.Solution solution) {
        if (isJourneyAlreadyPreferred(context, journey)) {
            String           id      = buildPreferredSolutionId(solution);
            PreferredStation station;
            try {
                station = getRightStationInPreferredJourney(journey, solution);
            } catch (Exception e) {
                FirebaseCrash.report(new Exception("COULDNT SET SOLUTION AS PREFERRED CAUSE OF THE FUCKIN NULLPOINTER (WHEN COMING FROM NOTIFICATION OF NON-COMPLETE SOLUTION)"));
                return false;
            }
            return station.getPreferredSolutions().get(id) != null;
        }
        return false;
    }

    private static PreferredStation getRightStationInPreferredJourney(PreferredJourney journey, Journey.Solution solution) {
        if (solution.getDepartureStationId().equals(journey.getStation1().getStationLongId())) {
            return journey.getStation1();
        } else {
            return journey.getStation2();
        }
    }

//    ------------------------------------------------------------------------------------------------------------------------

    public static void setPreferredSolution(Context context, PreferredJourney journey, Journey.Solution solution) throws IndexOutOfBoundsException, NoSuchElementException {
        if (isJourneyAlreadyPreferred(context, journey)) {

            PreferredStation station;
            try {
                station = getRightStationInPreferredJourney(journey, solution);
            } catch (Exception e) {
                FirebaseCrash.report(new Exception("COULDNT SET SOLUTION AS PREFERRED CAUSE OF THE FUCKIN NULLPOINTER (WHEN COMING FROM NOTIFICATION OF NON-COMPLETE SOLUTION)"));
                return;
            }

            if (!isPossibleToSaveMorePreferredSolutions(station)) {
                throw new IndexOutOfBoundsException("Impossible to save more than 3 solutions for this journey station");
            }

            if (!isSolutionAlreadyPreferred(context, journey, solution)) {
                PreferredJourney newJourney = getPreferredJourney(context, journey);
                if (solution.getDepartureStationId().equals(journey.getStation1().getStationLongId())) {
                    newJourney.getStation1().addPreferredSolutions(buildPreferredSolutionId(solution), solution);
                } else {
                    newJourney.getStation2().addPreferredSolutions(buildPreferredSolutionId(solution), solution);
                }
                setPreferredJourney(context, newJourney);
            }

        } else {
            throw new NoSuchElementException("Impossible to save solution of a non-preferred journey");
        }
    }

//    ------------------------------------------------------------------------------------------------------------------------

    public static void removePreferredJourney(Context context, PreferredStation departureStation, PreferredStation arrivalStation) {
        removePreferredJourney(context, departureStation.getStationShortId(), arrivalStation.getStationShortId());
    }

    public static void removePreferredJourney(Context context, String id1, String id2) {
        removeSavedJourney(context, FAVOURITES, id1, id2);
    }

//    ------------------------------------------------------------------------------------------------------------------------

    public static void removePreferredSolution(Context context, PreferredJourney journey, Journey.Solution solution) {
        if (isSolutionAlreadyPreferred(context, journey, solution)) {
            PreferredJourney newJourney = getPreferredJourney(context, journey);
            if (solution.getDepartureStationId().equals(journey.getStation1().getStationLongId())) {
                newJourney.getStation1().removePreferredSolutions(buildPreferredSolutionId(solution));
            } else {
                newJourney.getStation2().removePreferredSolutions(buildPreferredSolutionId(solution));
            }
            setPreferredJourney(context, newJourney);
        }
    }

    //    ------------------------------------------------------------------------------------------------------------------------

    public static List<PreferredJourney> getAllPreferredJourneys(Context context) {
        return getAllSavedJourneys(context, FAVOURITES);
    }

    public static PreferredJourney getPreferredJourney(Context context, PreferredJourney journey) {
        return getSavedJourney(context, FAVOURITES, journey);
    }

//    ------------------------------------------------------------------------------------------------------------------------

    public static String buildPreferredJourneyId(PreferredJourney preferredJourney) {
        return buildPreferredJourneyId(preferredJourney.getStation1().getStationShortId(), preferredJourney.getStation2().getStationShortId());
    }

    public static String buildPreferredJourneyId(PreferredStation departureStation, PreferredStation arrivalStation) {
        return buildPreferredJourneyId(departureStation.getStationShortId(), arrivalStation.getStationShortId());
    }

    public static String buildPreferredJourneyId(String id1, String id2) {
        return buildSavedJourneyId(FAVOURITES, id1, id2);
    }

//    ------------------------------------------------------------------------------------------------------------------------

    public static String buildPreferredSolutionId(Journey.Solution solution) {
        String id = "";
        if (solution.hasChanges()) {
            String separator = "";
            for (Journey.Solution.Change c : solution.getChangesList()) {
                id += (separator + (c.getTrainId()));
                separator = SEPARATOR;
            }
        } else {
            id = solution.getTrainId();
        }
        return id;
    }

//    ------------------------------------------------------------------------------------------------------------------------
} public class RecentStationsPreferences {

    public static boolean isJourneyAlreadyRecent(Context context, PreferredJourney preferredJourney) {
        return isJourneyAlreadyRecent(context, preferredJourney.getStation1().getStationShortId(), preferredJourney.getStation2().getStationShortId());
    }

    public static boolean isJourneyAlreadyRecent(Context context, PreferredStation departureStation, PreferredStation arrivalStation) {
        return isJourneyAlreadyRecent(context, departureStation.getStationShortId(), arrivalStation.getStationShortId());
    }

    public static boolean isJourneyAlreadyRecent(Context context, String id1, String id2) {
        return isJourneyAlreadySaved(context, RECENT, id1, id2);
    }

//    ------------------------------------------------------------------------------------------------------------------------

    public static void setRecentJourney(Context context, PreferredJourney journey) {
        if (!isJourneyAlreadyRecent(context, journey)) {
            List<PreferredJourney> list = getAllRecentJourneys(context);
            if (!isPossibleToSaveMoreRecentJourneys(list.size())) {
                removeRecentJourney(context, list.get(list.size() - 1).getStation1(), list.get(list.size() - 1).getStation2());
            }
            setSavedJourney(context, RECENT, journey);
        }
    }

//    ------------------------------------------------------------------------------------------------------------------------

    public static boolean isPossibleToSaveMoreRecentJourneys(Context context) {
        return isPossibleToSaveMoreRecentJourneys(getAllRecentJourneys(context).size());
    }

    public static boolean isPossibleToSaveMoreRecentJourneys(int size) {
        return size < 3;
    }


//    ------------------------------------------------------------------------------------------------------------------------

    public static void removeRecentJourney(Context context, PreferredJourney preferredJourney) {
        removeRecentJourney(context, preferredJourney.getStation1().getStationShortId(), preferredJourney.getStation2().getStationShortId());
    }

    public static void removeRecentJourney(Context context, PreferredStation departureStation, PreferredStation arrivalStation) {
        removeRecentJourney(context, departureStation.getStationShortId(), arrivalStation.getStationShortId());
    }

    public static void removeRecentJourney(Context context, String id1, String id2) {
        removeSavedJourney(context, RECENT, id1, id2);
    }

//    ------------------------------------------------------------------------------------------------------------------------

    public static List<PreferredJourney> getAllRecentJourneys(Context context) {
        return getAllSavedJourneys(context, RECENT);
    }

    public static PreferredJourney getRecentJourney(Context context, PreferredJourney journey) {
        return getSavedJourney(context, RECENT, journey);
    }

//    ------------------------------------------------------------------------------------------------------------------------

    public static String buildRecentJourneyId(PreferredJourney preferredJourney) {
        return buildRecentJourneyId(preferredJourney.getStation1().getStationShortId(), preferredJourney.getStation2().getStationShortId());
    }

    public static String buildRecentJourneyId(PreferredStation departureStation, PreferredStation arrivalStation) {
        return buildRecentJourneyId(departureStation.getStationShortId(), arrivalStation.getStationShortId());
    }

    public static String buildRecentJourneyId(String id1, String id2) {
        return buildSavedJourneyId(RECENT, id1, id2);
    }

} public static final String I_STATIONS     = "stations"; public static final String I_TIME         = "time"; public static final String I_TRAIN         = "train"; public static Station getStation4DatabaseObject(String stationName) {
    return MyApplication.database.stationDao().getByWhateverName(stationName);
} public static boolean isStationNameValid(String stationName) {
    return MyApplication.database.stationDao().isStationNameValid(stationName);
} public static boolean isThisJourneyPreferred(PreferredStation departureStation, PreferredStation arrivalStation, Context context) {
    return departureStation != null &&
            arrivalStation != null &&
            PreferredStationsPreferences.isJourneyAlreadyPreferred(
                    context,
                    departureStation,
                    arrivalStation);
}
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import com.jaus.albertogiunta.justintrain_oraritreni.data.PreferredJourney;
import com.jaus.albertogiunta.justintrain_oraritreni.data.PreferredStation;
import com.jaus.albertogiunta.justintrain_oraritreni.networking.DateTimeAdapter;
import com.jaus.albertogiunta.justintrain_oraritreni.networking.PostProcessingEnabler;
import com.jaus.albertogiunta.justintrain_oraritreni.utils.constants.ENUM_SNACKBAR_ACTIONS;
import com.jaus.albertogiunta.justintrain_oraritreni.utils.helpers.DatabaseHelper;
import com.jaus.albertogiunta.justintrain_oraritreni.utils.sharedPreferences.PreferredStationsPreferences;
import com.jaus.albertogiunta.justintrain_oraritreni.utils.sharedPreferences.RecentStationsPreferences;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import java.util.Locale;
import io.reactivex.Single;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import trikita.log.Log;
import static com.jaus.albertogiunta.justintrain_oraritreni.utils.constants.CONST_INTENT.I_STATIONS;
import static com.jaus.albertogiunta.justintrain_oraritreni.utils.constants.CONST_INTENT.I_TIME;
import static com.jaus.albertogiunta.justintrain_oraritreni.utils.constants.CONST_INTENT.I_TRAIN;
import static com.jaus.albertogiunta.justintrain_oraritreni.utils.helpers.DatabaseHelper.getStation4DatabaseObject;
import static com.jaus.albertogiunta.justintrain_oraritreni.utils.helpers.DatabaseHelper.isStationNameValid;
import static com.jaus.albertogiunta.justintrain_oraritreni.utils.helpers.DatabaseHelper.isThisJourneyPreferred;
package com.jaus.albertogiunta.justintrain_oraritreni.journeySearch;








class JourneySearchPresenter implements JourneySearchContract.Presenter {

    private JourneySearchActivity view;
    private PreferredStation      departureStation;
    private PreferredStation      arrivalStation;
    private String                trainNumber;
    private DateTime              dateTime;

    Gson gson = new GsonBuilder()
            .registerTypeAdapter(DateTime.class, new DateTimeAdapter())
            .registerTypeAdapterFactory(new PostProcessingEnabler())
            .create();

    JourneySearchPresenter(JourneySearchActivity view) {
        this.view = view;
        this.dateTime = DateTime.now().minusMinutes(10);
        this.trainNumber = "";
    }

    @Override
    public void unsubscribe() {
        view = null;
    }

    @Override
    public void setState(Bundle bundle) {
        if (bundle != null) {
            // Restore value of members from saved state
            PreferredJourney journey = gson.fromJson(bundle.getString(I_STATIONS), PreferredJourney.class);
            this.departureStation = this.departureStation != null ? this.departureStation : journey != null ? journey.getStation1() : null;
            this.arrivalStation = this.arrivalStation != null ? this.arrivalStation : journey != null ? journey.getStation2() : null;
            view.setStationNames(departureStation, arrivalStation);
            setFavouriteButtonStatus();
            this.dateTime = new DateTime(bundle.getLong(I_TIME, DateTime.now().minusMinutes(10).getMillis()));
            setDateTime();
        } else {
            if (this.departureStation != null) {
                view.setDepartureStationNames(departureStation.getNameLong());
            }
            if (this.arrivalStation != null) {
                view.setArrivalStationNames(arrivalStation.getNameLong());
            }
            if (this.departureStation != null && this.arrivalStation != null) {
                setFavouriteButtonStatus();
            }
        }
    }

    @Override
    public Bundle getState(Bundle bundle) {
        if (bundle == null) bundle = new Bundle();
        bundle.putString(I_STATIONS, gson.toJson(new PreferredJourney(departureStation, arrivalStation)));
        bundle.putLong(I_TIME, dateTime.getMillis());
        return bundle;
    }

    @Override
    public Bundle getTrainSearchState(Bundle bundle) {
        if (bundle == null) bundle = new Bundle();
        bundle.putString(I_TRAIN, trainNumber);
        return bundle;
    }

    @Override
    public void onDepartureStationNameChanged(String name) {
        departureStation = new PreferredStation(DatabaseHelper.getStation4DatabaseObject(name));