package com.thomasdh.roosterpgplus.Data;
import android.content.Context;
import android.util.Log;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.DeleteBuilder;
import com.thomasdh.roosterpgplus.Database.DatabaseHelper;
import com.thomasdh.roosterpgplus.Database.DatabaseManager;
import com.thomasdh.roosterpgplus.Fragments.RoosterViewFragment;
import com.thomasdh.roosterpgplus.Helpers.Apache.BasicNameValuePair;
import com.thomasdh.roosterpgplus.Helpers.ExceptionHandler;
import com.thomasdh.roosterpgplus.Helpers.HelperFunctions;
import com.thomasdh.roosterpgplus.Helpers.Apache.NameValuePair;
import com.thomasdh.roosterpgplus.Helpers.Apache.URLEncodedUtils;
import com.thomasdh.roosterpgplus.Models.Lesuur;
import org.joda.time.DateTime;
import org.joda.time.DateTimeComparator;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import fj.data.Array;
public class Rooster {
//region Rooster
public static void getRooster(List<NameValuePair> query, RoosterViewFragment.LoadType type, Context context, RoosterCallback callback, ExceptionCallback exceptionCallback) {
if(HelperFunctions.hasInternetConnection(context)) {
if (type == RoosterViewFragment.LoadType.ONLINE) {
getRoosterFromInternet(query, false, context, callback, exceptionCallback, false);
} else if (type == RoosterViewFragment.LoadType.NEWONLINE) {
getRoosterFromInternet(query, true, context, callback, exceptionCallback, false);
} else if(type == RoosterViewFragment.LoadType.REFRESH) {
getRoosterFromInternet(query, false, context, callback, exceptionCallback, false);
} else {
getRoosterFromDatabase(query, context, callback, exceptionCallback, false);
}
} else if(type == RoosterViewFragment.LoadType.OFFLINE || type == RoosterViewFragment.LoadType.NEWONLINE) {
getRoosterFromDatabase(query, context, callback, exceptionCallback, false);
} else {
ExceptionHandler.handleException(new Exception("Kon rooster niet laden, er is geen internetverbinding"), context, ExceptionHandler.HandleType.SIMPLE);
exceptionCallback.onError(null);
}
}
private static void getRoosterFromInternet(List<NameValuePair> query, boolean hasRoosterInDatabase, Context context, RoosterCallback callback, ExceptionCallback exceptionCallback, boolean silent) {
String url = "rooster?"+ URLEncodedUtils.format(query, "utf-8");
WebDownloader.getRooster(url, result -> parseRooster((String) result, query, context, callback, silent), exception -> {
Log.w("RoosterDownloader", "Er ging iets mis met het ophalen van het rooster", (Exception) exception);
if (hasRoosterInDatabase) {
if(!silent) ExceptionHandler.handleException(new Exception("Kon het rooster niet ophalen, oude rooster geladen. (" + ((Exception) exception).getMessage() + ")", (Exception) exception), context, ExceptionHandler.HandleType.SIMPLE);
getRoosterFromDatabase(query, context, callback, exceptionCallback, silent);
} else {
if(!silent) ExceptionHandler.handleException(new Exception("Kon het rooster niet ophalen, geen rooster geladen. (" + ((Exception) exception).getMessage() + ")", (Exception) exception), context, ExceptionHandler.HandleType.SIMPLE);
exceptionCallback.onError(null);
}
}, context);
}
private static void getRoosterFromDatabase(List<NameValuePair> query, Context context, RoosterCallback callback, ExceptionCallback exceptionCallback, boolean silent) {
DatabaseHelper helper = DatabaseManager.getHelper(context);
try {
Dao<Lesuur, ?> dao = helper.getDaoWithCache(Lesuur.class);
String searchQuery = URLEncodedUtils.format(query, "utf-8");
List<Lesuur> lessen = dao.queryForEq("query", searchQuery);
int week = !lessen.isEmpty() ? lessen.get(0).week : 0;
callback.onCallback(lessen, RoosterInfo.getWeekUrenCount(context, week));
} catch (SQLException e) {
Log.e("SQL ERROR", e.getMessage(), e);
if(!silent) ExceptionHandler.handleException(new Exception("Opslagfout, er is geen rooster geladen"), context, ExceptionHandler.HandleType.SIMPLE);
exceptionCallback.onError(e);
} catch (Exception e) {
Log.e("Callback error", e.getMessage(), e);
exceptionCallback.onError(e);
}
}
private static void saveRoosterInDatabase(List<Lesuur> lessen, String query, Context context) {
DatabaseHelper helper = DatabaseManager.getHelper(context);
try {
Dao<Lesuur, ?> dao = helper.getDaoWithCache(Lesuur.class);
// Huidige lessen verwijderen
DeleteBuilder<Lesuur, ?> deleteBuilder = dao.deleteBuilder();
deleteBuilder.where().eq("query", query);
deleteBuilder.delete();
// Nieuwe lessen opslaan
for(Lesuur les : lessen) {
dao.create(les);
}
// SetLoad triggeren
} catch (SQLException e) {
Log.e("SQL ERROR", e.getMessage(), e);
}
}
private static void parseRooster(String JSON, List<NameValuePair> query, Context context, RoosterCallback callback, boolean silent) {
if(context == null) return; // Oude context
try {
String queryString = URLEncodedUtils.format(query, "utf-8");
List<Lesuur> lessen = new ArrayList<>();
int week = 0;
JSONObject rooster = new JSONObject(JSON);
JSONArray JSONlessen = rooster.getJSONArray("lessen");
if(JSONlessen.length() == 0) {
// Er moet iets fout zijn.... dus uit geheugen halen....
getRoosterFromDatabase(query, context, (data, urenCount) -> {
if(urenCount == 0 && !silent) ExceptionHandler.handleException(new Exception("Rooster wordt opnieuw opgehaald... Probeer het later opnieuw."), context, ExceptionHandler.HandleType.SIMPLE);
else ExceptionHandler.handleException(new Exception("Rooster wordt opnieuw opgehaald. Oud rooster wordt getoond"), context, ExceptionHandler.HandleType.SIMPLE);
callback.onCallback(data, urenCount);
}, e -> {
if(!silent) ExceptionHandler.handleException(new Exception("Rooster wordt opnieuw opgehaald... Probeer het later opnieuw"), context, ExceptionHandler.HandleType.SIMPLE);
}, silent);
return;
}
for(int i = 0; i < JSONlessen.length(); i++) {
JSONObject JSONLes = JSONlessen.getJSONObject(i);
Lesuur les = new Lesuur(JSONLes, context, queryString);
lessen.add(les);
week = les.week;
}
int urenCount = rooster.getInt("urenCount");
RoosterInfo.setWeekUrenCount(context, week, urenCount);
callback.onCallback(lessen, urenCount);
saveRoosterInDatabase(lessen, queryString, context);
} catch (JSONException e) {
Log.e("JSON ERROR", e.getMessage(), e);
if(!silent) ExceptionHandler.handleException(new Exception("Fout bij het verwerken van het rooster", e), context, ExceptionHandler.HandleType.SIMPLE);
} catch (Exception e) {
Log.e("Callback error", e.getMessage(), e);
if(!silent) ExceptionHandler.handleException(new Exception("Fout bij het verwerken van het rooster: " + e.getMessage(), e), context, ExceptionHandler.HandleType.SIMPLE);
}
}
//endregion
//region Next uur
public static String getNextLesuurText(Lesuur nextLesuur) {
if(nextLesuur == null) {
return "Geen les gevonden";
} else {
DateFormat format = new SimpleDateFormat("HH:mm");
return String.format("De volgende les is %1$s, %2$s het %3$se uur%4$s en start om %5$s",
nextLesuur.vak,
getDayOfWeek(nextLesuur.dag + 1),
nextLesuur.uur,
"".equals(nextLesuur.lokaal) ? "" : " in " + nextLesuur.lokaal,
format.format(nextLesuur.lesStart));
}
}
public static void getNextLesuur(Context context, NextUurCallback callback) {
Calendar now = Calendar.getInstance();
int currentWeek = now.get(Calendar.WEEK_OF_YEAR);
int weekToGet = RoosterInfo.getCurrentWeek(context);
int currentDay = now.get(Calendar.DAY_OF_WEEK);
int newDay;
if(currentWeek != weekToGet) {
// Het is een veranderde week (vakantie / weekend), dus maandag is de dag en een correctie voor de DB
newDay = Calendar.MONDAY;
DateTime timeToGet = DateTime.now()
.withTime(0, 0, 0, 0);
getNextLesuurInDay(context, weekToGet, newDay, timeToGet, callback);
} else {
// Het is geen weekend, we kijken of er vandaag nog een les komt (zo nee, op naar morgen!)
getNextLesuurInDay(context, weekToGet, currentDay, new DateTime(now), lesuur -> {
if (lesuur == null) { // geen lessen meer
int updatedDay = currentDay + 1;
int updatedWeek = currentWeek;
if (updatedDay == Calendar.SATURDAY) {
updatedDay = Calendar.MONDAY;
updatedWeek++;
}
DateTime timeToGet = DateTime.now()
.withTime(0, 0, 0, 0);
getNextLesuurInDay(context, updatedWeek, updatedDay, timeToGet, callback);
} else {
// We weten de volgende les zowaar... DONE
callback.onCallback(lesuur);
}
});
}
}
private static void getNextLesuurInDay(Context context, int week, int day, DateTime time, NextUurCallback callback) {
Account.initialize(context, false);
List<NameValuePair> query = new ArrayList<>();
query.add(new BasicNameValuePair("week", Integer.toString(week)));
query.add(new BasicNameValuePair("key", Account.getApiKey()));
if (HelperFunctions.hasInternetConnection(context)) {
// Herladen van het rooster FTW
getRoosterFromInternet(query, true, context, (data, urenCount) -> {
RoosterInfo.setLoad("personal"+week, System.currentTimeMillis(), context);
callback.onCallback(getNextLesuurInDayCallback(day, time, Array.iterableArray((ArrayList<Lesuur>) data)));
}, e -> callback.onCallback(getNextLesuurInDayCallback(context, day, time, query)), true);
} else {
callback.onCallback(getNextLesuurInDayCallback(context, day, time, query));
}
}
private static Lesuur getNextLesuurInDayCallback(Context context, int day, DateTime time, List<NameValuePair> query) {
DatabaseHelper helper = DatabaseManager.getHelper(context);
try {
Dao<Lesuur, ?> dao = helper.getDaoWithCache(Lesuur.class);
String searchQuery = URLEncodedUtils.format(query, "utf-8");
Array<Lesuur> lessenThisWeek = Array.iterableArray(dao.queryForEq("query", searchQuery));
return getNextLesuurInDayCallback(day, time, lessenThisWeek);
} catch (SQLException e) {
return null;
}
}
private static Lesuur getNextLesuurInDayCallback(int day, DateTime time, Array<Lesuur> lessenThisWeek) {
Lesuur baseLesuur = new Lesuur();
baseLesuur.uur = 10000; // Vast niet meer uren op een dag...
DateTimeComparator comparator = DateTimeComparator.getTimeOnlyInstance();
Array<Lesuur> lessenThisDay = lessenThisWeek.filter(s -> s.dag == day - 1 && !s.vervallen); // DBcorrectie
Array<Lesuur> futureLessen = lessenThisDay.filter(s -> comparator.compare(new DateTime(s.lesStart).plusMinutes(5), time) >= 0);
if(futureLessen.isEmpty()) {
return null;
}
return futureLessen.foldLeft((newLes, oldLes) -> newLes.uur < oldLes.uur ? newLes : oldLes, baseLesuur);
}
//endregion
public interface RoosterCallback {
void onCallback(Object data, int urenCount);
}
public interface ExceptionCallback {
void onError(Exception e);
}
public interface NextUurCallback {
void onCallback(Lesuur lesuur);
}
private static String getDayOfWeek(int dag) {
switch (dag) {
case Calendar.SUNDAY:
return "zondag";
case Calendar.MONDAY:
return "maandag";
case Calendar.TUESDAY:
return "dinsdag";
case Calendar.WEDNESDAY:
return "woensdag";
case Calendar.THURSDAY:
return "donderdag";
case Calendar.FRIDAY:
return "vrijdag";
case Calendar.SATURDAY:
return "zaterdag";
}
return null;
}
}