package de.apps4ics.mountainnavigation;

import android.location.Location;

import com.survivingwithandroid.weather.lib.WeatherCode;
import com.survivingwithandroid.weather.lib.model.DayForecast;
import com.survivingwithandroid.weather.lib.model.Weather;

import java.util.Arrays;

import de.apps4ics.mountainnavigation.handlers.WeatherHandler;

/**
 * This file is part of MountainNavigation.
 *
 * MountainNavigation is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MountainNavigation is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MountainNavigation.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @copyright Copyright (c) 2016 Vinzenz Rosenkanz <vinzenz.rosenkranz@gmail.com>
 *
 * @author Vinzenz Rosenkranz <vinzenz.rosenkranz@gmail.com>
 */
public class MyWeather {
    private long timestamp;
    private float minTemp;
    private float maxTemp;
    private Location location;
    private String city;
    private long sunrise;
    private long sunset;
    private int weatherId; //OWM id
    private int weatherCode; //OWM code
    private float pressure;
    private float humidity;
    private float windSpeed;
    private float windDir;
    private int clouds; //percent of cloudiness
    private float rain; //rain volume for the last 3 hours
    private float snow; //snow volume for the last 3 hours

    //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.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 MyWeather() {}

    public MyWeather(DayForecast dayForecast) {
        this(dayForecast.weather, dayForecast.timestamp);
    }

    public MyWeather(Weather weather, long timestamp) {
        this.timestamp = timestamp;
        if(weather.location != null) {
            location = new Location("");
            location.setLatitude(weather.location.getLatitude());
            location.setLongitude(weather.location.getLongitude());
            city = weather.location.getCity();
        }
        minTemp = weather.temperature.getMinTemp() > 0 ? weather.temperature.getMinTemp() : -1;
        maxTemp = weather.temperature.getMaxTemp() > 0 ? weather.temperature.getMaxTemp() : -1;
        sunrise = weather.location.getSunrise() > 0 ? weather.location.getSunrise() : -1;
        sunset = weather.location.getSunset() > 0 ? weather.location.getSunset() : -1;
        weatherId = weather.currentCondition.getWeatherId() > 0 ? weather.currentCondition.getWeatherId() : -1;
        weatherCode = weather.currentCondition.getWeatherCode().getCode() > 0 ? weather.currentCondition.getWeatherCode().getCode() : -1;
        pressure = weather.currentCondition.getPressure() > 0 ? weather.currentCondition.getPressure() : -1;
        humidity = weather.currentCondition.getHumidity() > 0 ? weather.currentCondition.getHumidity() : -1;
        windSpeed = weather.wind.getSpeed() > 0 ? weather.wind.getSpeed() : -1;
        windDir = weather.wind.getDeg() > 0 ? weather.wind.getDeg() : -1;
        clouds = weather.clouds.getPerc() > 0 ? weather.clouds.getPerc() : -1;
        rain = weather.rain[0].getAmmount() > 0 ? weather.rain[0].getAmmount() : -1;
        snow = weather.snow.getAmmount() > 0 ? weather.snow.getAmmount() : -1;
    }

    public boolean isSevereWeather(int weatherCode){
        return Arrays.asList(severeWeatherCodes).contains(weatherCode);
    }

    public boolean isAfterSunset(){
        return isAfterSunset(System.currentTimeMillis());
    }

    public boolean isAfterSunset( long time){
        return time > (getSunset() * 1000) && time < (getSunrise() * 1000);
    }

    public boolean isHot(){
        return (isSunny() && !isWindy()) ||
                getMaxTemp() >= WeatherHandler.getMinHotTemp();
    }

    public boolean isSunny(){
        return getWeatherCode() == WeatherCode.SUNNY.getCode();
    }

    public boolean isCold(){
        return getWeatherCode() == WeatherCode.COLD.getCode() ||
                getMinTemp() <= WeatherHandler.getMaxColdTemp();
    }

    public boolean isWindy(){
        return getWeatherCode() == WeatherCode.WINDY.getCode() ||
                (getWindSpeed() >= WeatherHandler.getMinWindySpeed());
    }

    public boolean isDark(long length){
        return isDark(System.currentTimeMillis(), length);
    }

    public boolean isDark(long time, long length){
        return isAfterSunset(time) || isAfterSunset(time + length);
    }

    public boolean isFoggy() {
        return getWeatherCode() == WeatherCode.FOGGY.getCode() || getWeatherCode() == WeatherCode.HAZE.getCode();
    }

    public boolean hasSleet() {
        return getWeatherCode() == WeatherCode.MIXED_RAIN_SNOW.getCode() ||
                getWeatherCode() == WeatherCode.MIXED_RAIN_SLEET.getCode() ||
                getWeatherCode() == WeatherCode.MIXED_SNOW_SLEET.getCode() ||
                getWeatherCode() == WeatherCode.SLEET.getCode();
    }

    public int getClouds() {
        return clouds;
    }

    public float getHumidity() {
        return humidity;
    }

    public Location getLocation() {
        return location;
    }

    public String getCity() { return city; }

    public float getMaxTemp() {
        return maxTemp;
    }

    public float getMinTemp() {
        return minTemp;
    }

    public float getPressure() {
        return pressure;
    }

    public float getRain() {
        return rain;
    }

    public float getSnow() {
        return snow;
    }

    public long getSunrise() {
        return sunrise;
    }

    public long getSunset() {
        return sunset;
    }

    public long getTimestamp() {
        return timestamp;
    }

    public int getWeatherCode() {
        return weatherCode;
    }

    public long getWeatherId() {
        return weatherId;
    }

    public float getWindDir() {
        return windDir;
    }

    public float getWindSpeed() {
        return windSpeed;
    }

    public void setClouds(int clouds) {
        this.clouds = clouds;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public void setHumidity(float humidity) {
        this.humidity = humidity;
    }

    public void setLocation(Location location) {
        this.location = location;
    }

    public void setMaxTemp(float maxTemp) {
        this.maxTemp = maxTemp;
    }

    public void setMinTemp(float minTemp) {
        this.minTemp = minTemp;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }

    public void setSnow(float snow) {
        this.snow = snow;
    }

    public void setRain(float rain) {
        this.rain = rain;
    }

    public void setSunrise(long sunrise) {
        this.sunrise = sunrise;
    }

    public void setSunset(long sunset) {
        this.sunset = sunset;
    }

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

    public void setWeatherCode(int weatherCode) {
        this.weatherCode = weatherCode;
    }

    public void setWeatherId(int weatherId) {
        this.weatherId = weatherId;
    }

    public void setWindDir(float windDir) {
        this.windDir = windDir;
    }

    public void setWindSpeed(float windSpeed) {
        this.windSpeed = windSpeed;
    }
}
