package de.apps4ics.mountainnavigation.handlers;
import android.app.Activity;
import android.app.FragmentManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.util.Log;
import com.survivingwithandroid.weather.lib.WeatherClient;
import com.survivingwithandroid.weather.lib.WeatherCode;
import com.survivingwithandroid.weather.lib.WeatherConfig;
import com.survivingwithandroid.weather.lib.exception.WeatherLibException;
import com.survivingwithandroid.weather.lib.exception.WeatherProviderInstantiationException;
import com.survivingwithandroid.weather.lib.model.DayForecast;
import com.survivingwithandroid.weather.lib.model.HistoricalHourWeather;
import com.survivingwithandroid.weather.lib.model.HistoricalWeather;
import com.survivingwithandroid.weather.lib.model.Weather;
import com.survivingwithandroid.weather.lib.model.WeatherForecast;
import com.survivingwithandroid.weather.lib.provider.openweathermap.OpenweathermapProviderType;
import com.survivingwithandroid.weather.lib.request.WeatherRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import de.apps4ics.mountainnavigation.InformDialog;
import de.apps4ics.mountainnavigation.InformListDialog;
import de.apps4ics.mountainnavigation.MainActivity;
import de.apps4ics.mountainnavigation.MyWeather;
import de.apps4ics.mountainnavigation.R;
import de.apps4ics.mountainnavigation.WeatherDatabase;
import de.apps4ics.mountainnavigation.adapters.WarningListAdapter;
/**
* Created by Vinz on 06.03.2016.
*/
public class WeatherHandler {
private static final String API_KEY = "fd4034defae557fd5f2fdaaf73c3402c"; //OpenWeatherMap API Key
private Context context;
private WeatherDatabase weatherDb;
private WeatherClient weatherClient;
private Weather todaysWeather;
private Weather tomorrowsWeather;
private HistoricalWeather histWeather;
private DayForecast todaysForecast;
private DayForecast tomorrowsForecast;
private final static float MIN_HOT_TEMP_DEFAULT = 30.0f;
private final static float MAX_COLD_TEMP_DEFAULT = 10.0f;
private static float MIN_HOT_TEMP;
private static float MAX_COLD_TEMP;
private static float minWindySpeed;
private static Activity activity;
private static FragmentManager fragmentManager;
//TODO split into severe weather and foggy, windy, sunny, ...
private static final Integer[] severeWeatherCodes = new Integer[]{
WeatherCode.TORNADO.getCode(),
WeatherCode.TROPICAL_STORM.getCode(),
WeatherCode.HURRICANE.getCode(),
WeatherCode.SEVERE_THUNDERSTORMS.getCode(),
WeatherCode.THUNDERSTORMS.getCode(),
WeatherCode.MIXED_RAIN_SNOW.getCode(),
WeatherCode.MIXED_RAIN_SLEET.getCode(),
WeatherCode.MIXED_SNOW_SLEET.getCode(),
WeatherCode.FREEZING_DRIZZLE.getCode(),
WeatherCode.FREEZING_RAIN.getCode(),
WeatherCode.HEAVY_SHOWERS.getCode(),
WeatherCode.SNOW_FLURRIES.getCode(),
WeatherCode.LIGHT_SNOW_SHOWERS.getCode(),
WeatherCode.BLOWING_SNOW.getCode(),
WeatherCode.SNOW.getCode(),
WeatherCode.HAIL.getCode(),
WeatherCode.SLEET.getCode(),
WeatherCode.FOGGY.getCode(),
WeatherCode.HAZE.getCode(),
WeatherCode.WINDY.getCode(),
WeatherCode.COLD.getCode(),
WeatherCode.SUNNY.getCode(),
WeatherCode.MIXED_RAIN_AND_HAIL.getCode(),
WeatherCode.ISOLATED_THUNDERSTORMS.getCode(),
WeatherCode.SCATTERED_THUNDERSTORMS.getCode(),
WeatherCode.HEAVY_SNOW.getCode(),
WeatherCode.SCATTERED_SNOW_SHOWERS.getCode(),
WeatherCode.THUNDERSHOWERS.getCode(),
WeatherCode.SNOW_SHOWERS.getCode(),
WeatherCode.ISOLATED_THUDERSHOWERS.getCode(),
WeatherCode.TORNADO.getCode()
};
public WeatherHandler(Context context) {
weatherDb = new WeatherDatabase(context);
this.context = context;
try {
activity = (Activity) context;
fragmentManager = activity.getFragmentManager();
} catch(ClassCastException e) {
Log.e(MainActivity.TAG, "Could not get fragment manager!");
//TODO close app?
}
WeatherClient.ClientBuilder weatherBuilder = new WeatherClient.ClientBuilder();
WeatherConfig weatherConfig = new WeatherConfig();
weatherConfig.unitSystem = WeatherConfig.UNIT_SYSTEM.M;
weatherConfig.ApiKey = API_KEY;
weatherConfig.lang = MainActivity.getRes().getString(R.string.lang_identifier);
weatherConfig.numDays = 2;
SharedPreferences sharedPrefs = MainActivity.getSharedPrefs();
Resources res = MainActivity.getRes();
MIN_HOT_TEMP = Float.parseFloat(sharedPrefs.getString(res.getString(R.string.settings_hint_min_hot_temp_key), String.valueOf(MIN_HOT_TEMP_DEFAULT)));
MAX_COLD_TEMP = Float.parseFloat(sharedPrefs.getString(res.getString(R.string.settings_hint_max_cold_temp_key), String.valueOf(MAX_COLD_TEMP_DEFAULT)));
minWindySpeed = 8; //http://www.wettergefahren-fruehwarnung.de/Artikel/beaufort.html
if(weatherConfig.unitSystem.equals(WeatherConfig.UNIT_SYSTEM.I)){
MIN_HOT_TEMP = celsiusToFahrenheit(MIN_HOT_TEMP);
MAX_COLD_TEMP = celsiusToFahrenheit(MAX_COLD_TEMP);
}
weatherClient = null;
try {
weatherClient = weatherBuilder.attach(context)
.provider(new OpenweathermapProviderType())
.httpClient(com.survivingwithandroid.weather.lib.client.okhttp.WeatherDefaultClient.class)
.config(weatherConfig)
.build();
} catch (WeatherProviderInstantiationException e) {
e.printStackTrace();
}
}
/**
*
* @param offset number of days (in the past) to search for result in the cache, only for getCurrentWeatherCached
*/
public MyWeather getCurrentWeather(double lat, double lon, int offset) {
if(MainActivity.hasInternet()) return getCurrentWeatherOnline(lat, lon);
else return getCurrentWeatherCached(lat, lon, offset);
}
private MyWeather getCurrentWeatherOnline(double lat, double lon) {
//return new MyWeather();
return null;
}
private MyWeather getCurrentWeatherCached(double lat, double lon, int offset) {
//return new MyWeather();
return null;
}
public void getForecast(double lat, double lon, int days) {
getForecast(lat, lon, days, 0);
}
public void getForecast(double lat, double lon, int days, int offset) {
//TODO Move this to the not-yet-implemented upload method
weatherClient.getForecastWeather(new WeatherRequest(lon, lat), new WeatherClient.ForecastWeatherEventListener() {
@Override
public void onWeatherRetrieved(WeatherForecast forecast) {
todaysForecast = forecast.getForecast(0);
tomorrowsForecast = forecast.getForecast(1);
todaysWeather = todaysForecast.weather;
tomorrowsWeather = tomorrowsForecast.weather;
Log.d(MainActivity.TAG, "City [" + todaysWeather.location.getCity() + "] Current temp: " + todaysWeather.temperature.getTemp());
String title = String.format("Weather for %s in %s", todaysWeather.location.getCity(), todaysWeather.location.getCountry());
String msg = String.format("%1$.1f%2$s (%3$.1f%4$s/%5$.1f%6$s)\nSunrise: %7$s\nSunset: %8$s\nWeatherCode: %9$d\nWeatherId: %10$d",
todaysForecast.forecastTemp.day,
forecast.getUnit().tempUnit,
todaysForecast.forecastTemp.min,
forecast.getUnit().tempUnit,
todaysForecast.forecastTemp.max,
forecast.getUnit().tempUnit,
MainActivity.df_hm.format(new Date(todaysWeather.location.getSunrise() * 1000)),
MainActivity.df_hm.format(new Date(todaysWeather.location.getSunset() * 1000)),
todaysWeather.currentCondition.getWeatherCode().getCode(),
todaysWeather.currentCondition.getWeatherId());
Log.d(MainActivity.TAG, title + ": " + msg);
displayHints();
displaySevereWeather();
}
@Override
public void onWeatherError(WeatherLibException wle) {
Log.e(MainActivity.TAG, "Weather error - parsing data");
wle.printStackTrace();
}
@Override
public void onConnectionError(Throwable t) {
Log.e(MainActivity.TAG, "Connection Error");
t.printStackTrace();
}
});
}
public List<MyWeather> getForecastOnline(double lat, double lon, int days, int step) {
return null;
}
public List<MyWeather> getForecastCached(double lat, double lon, int days, int step, int offset) {
return null;
}
public List<MyWeather> getHistoricalWeather(float lat, float lon, long start, long end){
return getHistoricalWeather(lat, lon, start, end, 3);
}
public List<MyWeather> getHistoricalWeather(float lat, float lon, long start, long end, int step){
ArrayList<MyWeather> weathers = new ArrayList<>();
Date startDate = new Date(start / 1000); //OWM uses seconds instead of milliseconds
Date endDate = new Date(end / 1000);
histWeather = null;
weatherClient.getHistoricalWeather(new WeatherRequest(lon, lat), startDate, endDate, new WeatherClient.HistoricalWeatherEventListener() {
@Override
public void onWeatherRetrieved(HistoricalWeather historicalWeather) {
//TODO check if it was sunny/rainy and set fountain options based on this
histWeather = historicalWeather;
}
@Override
public void onWeatherError(WeatherLibException wle) {
Log.e(MainActivity.TAG, "Weather error - parsing data");
wle.printStackTrace();
}
@Override
public void onConnectionError(Throwable t) {
Log.e(MainActivity.TAG, "Connection Error");
t.printStackTrace();
}
});
for(HistoricalHourWeather hhw : histWeather.getHoistoricalData()) {
weathers.add(new MyWeather(hhw.weather, hhw.timestamp));
}
return weathers;
}
private void insertIntoDatabase(Weather weather) {
insertIntoDatabase(weather, 0);
}
private void insertIntoDatabase(Weather weather, long timestamp) {
insertIntoDatabase(new MyWeather(weather, timestamp));
}
private void insertIntoDatabase(MyWeather weather) {
weatherDb.insertWeather(weather);
}
private void displayHints() {
Resources res = MainActivity.getRes();
//TODO add more hints
if (MainActivity.showWeatherHints()) {
List<String> titles = new ArrayList<>();
List<String> descs = new ArrayList<>();
List<String> infos = new ArrayList<>();
if (isSunny()) {
titles.add(res.getString(R.string.hint_dialog_titles_sunny));
descs.add(res.getString(R.string.hint_dialog_msgs_sunny));
infos.add("");
}
if (isHot()) {
titles.add(res.getString(R.string.hint_dialog_titles_hot));
descs.add(res.getString(R.string.hint_dialog_msgs_hot));
infos.add(res.getString(R.string.hint_dialog_info_hot));
}
if (isCold()) {
titles.add(res.getString(R.string.hint_dialog_titles_cold));
descs.add(res.getString(R.string.hint_dialog_msgs_cold));
infos.add("");
}
if (isWindy()) {
titles.add(res.getString(R.string.hint_dialog_titles_windy));
descs.add(res.getString(R.string.hint_dialog_msgs_windy));
infos.add("");
}
if (isAfterSunset()) {
titles.add(res.getString(R.string.hint_dialog_titles_sunset));
descs.add(res.getString(R.string.hint_dialog_msgs_sunset));
infos.add("");
}
if (titles.size() > 0 && descs.size() > 0) {
String[] titleArr = new String[titles.size()];
String[] descArr = new String[descs.size()];
String[] infosArr = new String[infos.size()];
titleArr = titles.toArray(titleArr);
descArr = descs.toArray(descArr);
infosArr = infos.toArray(infosArr);
WarningListAdapter warningAdapter = new WarningListAdapter(activity, titleArr, descArr, infosArr);
InformListDialog weatherHintDialog = new InformListDialog(MainActivity.getRes().getString(R.string.hint_dialog_title), warningAdapter);
weatherHintDialog.show(fragmentManager, "Warning Hint Dialog");
}
}
}
private void displaySevereWeather() {
if (isSevereWeather(todaysWeather.currentCondition.getWeatherCode().getCode())) {
Log.d(MainActivity.TAG, "It is severe weather! :(");
Resources res = context.getResources();
String warnMsg = String.format(res.getString(R.string.weather_warning_dialog_msg), todaysWeather.location.getCity(), todaysWeather.currentCondition.getWeatherCode().getLabel(context));
InformDialog informAlertDialog = new InformDialog(res.getString(R.string.weather_warning_dialog_title), warnMsg);
informAlertDialog.show(fragmentManager, "Inform Dialog - Weather Warning");
}
}
private boolean isSevereWeather(int weatherCode){
return Arrays.asList(severeWeatherCodes).contains(weatherCode);
}
private boolean isAfterSunset(){
return isAfterSunset(System.currentTimeMillis());
}
private boolean isAfterSunset(long time){
return time > (todaysWeather.location.getSunset() * 1000) && time < (tomorrowsWeather.location.getSunrise() * 1000);
}
private boolean isHot(){
return todaysWeather.currentCondition.getWeatherCode().getCode() == WeatherCode.SUNNY.getCode() ||
(todaysWeather.temperature.getTemp() >= MIN_HOT_TEMP || todaysWeather.temperature.getMaxTemp() >= MIN_HOT_TEMP);
}
private boolean isSunny(){
return todaysWeather.currentCondition.getWeatherCode().getCode() == WeatherCode.SUNNY.getCode();
}
private boolean isCold(){
return todaysWeather.currentCondition.getWeatherCode().getCode() == WeatherCode.COLD.getCode() ||
(todaysWeather.temperature.getTemp() <= MAX_COLD_TEMP || todaysWeather.temperature.getMinTemp() <= MAX_COLD_TEMP);
}
private boolean isWindy(){
return todaysWeather.currentCondition.getWeatherCode().getCode() == WeatherCode.WINDY.getCode() ||
(todaysWeather.wind.getSpeed() >= minWindySpeed);
}
private boolean isDark(long length){
return isDark(System.currentTimeMillis(), length);
}
private boolean isDark(long time, long length){
return isAfterSunset(time) || isAfterSunset(time + length);
}
public static float celsiusToFahrenheit(float c) {
return c * 9.0f/5.0f + 32;
}
public static float fahrenheitToCelsius(float f) {
return (f - 32.0f) * 5.0f/9.0f;
}
}