//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2018.02.17 at 03:24:36 PM CET
//

package no.api.meteo.jaxb.locationforecast.v1_9;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;

/**
 * This object contains factory methods for each
 * Java content interface and Java element interface
 * generated in the no.api.meteo.jaxb.locationforecast.v1_9 package.
 *
An ObjectFactory allows you to programatically
 * construct new instances of the Java representation
 * for XML content. The Java representation of XML
 * content can consist of schema derived interfaces
 * and classes representing the binding of schema
 * type definitions, element declarations and model
 * groups.  Factory methods for each of these are
 * provided in this class.
 *
 */
@XmlRegistry
public class ObjectFactory {

    private final static QName _LocationTypeMaxTemperature_QNAME = new QName("", "maxTemperature");
    private final static QName _LocationTypeSymbol_QNAME = new QName("", "symbol");
    private final static QName _LocationTypeHighestTemperature_QNAME = new QName("", "highestTemperature");
    private final static QName _LocationTypeWindGust_QNAME = new QName("", "windGust");
    private final static QName _LocationTypeCurrentDirection_QNAME = new QName("", "currentDirection");
    private final static QName _LocationTypeStateOfTheSea_QNAME = new QName("", "stateOfTheSea");
    private final static QName _LocationTypeMeanabsoluteerror_QNAME = new QName("", "meanabsoluteerror");
    private final static QName _LocationTypeMaximumPrecipitation_QNAME = new QName("", "maximumPrecipitation");
    private final static QName _LocationTypeTidalwater_QNAME = new QName("", "tidalwater");
    private final static QName _LocationTypeWaveHeight_QNAME = new QName("", "waveHeight");
    private final static QName _LocationTypePrecipitation_QNAME = new QName("", "precipitation");
    private final static QName _LocationTypeScore_QNAME = new QName("", "score");
    private final static QName _LocationTypeAreaMaxWindSpeed_QNAME = new QName("", "areaMaxWindSpeed");
    private final static QName _LocationTypeSnowDepth_QNAME = new QName("", "snowDepth");
    private final static QName _LocationTypeLowClouds_QNAME = new QName("", "lowClouds");
    private final static QName _LocationTypeMinTemperature_QNAME = new QName("", "minTemperature");
    private final static QName _LocationTypeBias_QNAME = new QName("", "bias");
    private final static QName _LocationTypeTemperature_QNAME = new QName("", "temperature");
    private final static QName _LocationTypeWeather_QNAME = new QName("", "weather");
    private final static QName _LocationTypeHumidity_QNAME = new QName("", "humidity");
    private final static QName _LocationTypeNumberofobservations_QNAME = new QName("", "numberofobservations");
    private final static QName _LocationTypeWindDirection_QNAME = new QName("", "windDirection");
    private final static QName _LocationTypeMaxTemperatureDay_QNAME = new QName("", "maxTemperatureDay");
    private final static QName _LocationTypeWindSpeed_QNAME = new QName("", "windSpeed");
    private final static QName _LocationTypeWavePeriod_QNAME = new QName("", "wavePeriod");
    private final static QName _LocationTypeMinTemperatureNight_QNAME = new QName("", "minTemperatureNight");
    private final static QName _LocationTypeUv_QNAME = new QName("", "uv");
    private final static QName _LocationTypeHighClouds_QNAME = new QName("", "highClouds");
    private final static QName _LocationTypeMaxTemperatureNight_QNAME = new QName("", "maxTemperatureNight");
    private final static QName _LocationTypeWindProbability_QNAME = new QName("", "windProbability");
    private final static QName _LocationTypeMaxWaveHeight_QNAME = new QName("", "maxWaveHeight");
    private final static QName _LocationTypeSurfaceTemperature_QNAME = new QName("", "surfaceTemperature");
    private final static QName _LocationTypePressure_QNAME = new QName("", "pressure");
    private final static QName _LocationTypeCloudiness_QNAME = new QName("", "cloudiness");
    private final static QName _LocationTypeWaveDirection_QNAME = new QName("", "waveDirection");
    private final static QName _LocationTypeSymbolProbability_QNAME = new QName("", "symbolProbability");
    private final static QName _LocationTypeTemperatureProbability_QNAME = new QName("", "temperatureProbability");
    private final static QName _LocationTypeGroundCover_QNAME = new QName("", "groundCover");
    private final static QName _LocationTypeMinTemperatureDay_QNAME = new QName("", "minTemperatureDay");
    private final static QName _LocationTypeMaxWindSpeed_QNAME = new QName("", "maxWindSpeed");
    private final static QName _LocationTypeForestFire_QNAME = new QName("", "forest-fire");
    private final static QName _LocationTypeMediumClouds_QNAME = new QName("", "mediumClouds");
    private final static QName _LocationTypeDewpointTemperature_QNAME = new QName("", "dewpointTemperature");
    private final static QName _LocationTypeLowestTemperature_QNAME = new QName("", "lowestTemperature");
    private final static QName _LocationTypeFog_QNAME = new QName("", "fog");

    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: no.api.meteo.jaxb.locationforecast.v1_9
     *
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link LocationType }
     *
     */
    public LocationType createLocationType() {
        return new LocationType();
    }

    /**
     * Create an instance of {@link Weatherdata }
     *
     */
    public Weatherdata createWeatherdata() {
        return new Weatherdata();
    }

    /**
     * Create an instance of {@link MetaType }
     *
     */
    public MetaType createMetaType() {
        return new MetaType();
    }

    /**
     * Create an instance of {@link ProductType }
     *
     */
    public ProductType createProductType() {
        return new ProductType();
    }

    /**
     * Create an instance of {@link Uv }
     *
     */
    public Uv createUv() {
        return new Uv();
    }

    /**
     * Create an instance of {@link TimeType }
     *
     */
    public TimeType createTimeType() {
        return new TimeType();
    }

    /**
     * Create an instance of {@link ModelType }
     *
     */
    public ModelType createModelType() {
        return new ModelType();
    }

    /**
     * Create an instance of {@link Cloudiness }
     *
     */
    public Cloudiness createCloudiness() {
        return new Cloudiness();
    }

    /**
     * Create an instance of {@link Pressure }
     *
     */
    public Pressure createPressure() {
        return new Pressure();
    }

    /**
     * Create an instance of {@link Tidalwater }
     *
     */
    public Tidalwater createTidalwater() {
        return new Tidalwater();
    }

    /**
     * Create an instance of {@link Precipitation }
     *
     */
    public Precipitation createPrecipitation() {
        return new Precipitation();
    }

    /**
     * Create an instance of {@link Score }
     *
     */
    public Score createScore() {
        return new Score();
    }

    /**
     * Create an instance of {@link Groundcover }
     *
     */
    public Groundcover createGroundcover() {
        return new Groundcover();
    }

    /**
     * Create an instance of {@link Temperature }
     *
     */
    public Temperature createTemperature() {
        return new Temperature();
    }

    /**
     * Create an instance of {@link Windspeed }
     *
     */
    public Windspeed createWindspeed() {
        return new Windspeed();
    }

    /**
     * Create an instance of {@link UnitValue }
     *
     */
    public UnitValue createUnitValue() {
        return new UnitValue();
    }

    /**
     * Create an instance of {@link LocationType.WindDirection }
     *
     */
    public LocationType.WindDirection createLocationTypeWindDirection() {
        return new LocationType.WindDirection();
    }

    /**
     * Create an instance of {@link LocationType.StateOfTheSea }
     *
     */
    public LocationType.StateOfTheSea createLocationTypeStateOfTheSea() {
        return new LocationType.StateOfTheSea();
    }

    /**
     * Create an instance of {@link LocationType.SnowDepth }
     *
     */
    public LocationType.SnowDepth createLocationTypeSnowDepth() {
        return new LocationType.SnowDepth();
    }

    /**
     * Create an instance of {@link LocationType.Weather }
     *
     */
    public LocationType.Weather createLocationTypeWeather() {
        return new LocationType.Weather();
    }

    /**
     * Create an instance of {@link LocationType.Symbol }
     *
     */
    public LocationType.Symbol createLocationTypeSymbol() {
        return new LocationType.Symbol();
    }

    /**
     * Create an instance of {@link LocationType.ForestFire }
     *
     */
    public LocationType.ForestFire createLocationTypeForestFire() {
        return new LocationType.ForestFire();
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "maxTemperature", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeMaxTemperature(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeMaxTemperature_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocationType.Symbol }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "symbol", scope = LocationType.class)
    public JAXBElement<LocationType.Symbol> createLocationTypeSymbol(LocationType.Symbol value) {
        return new JAXBElement<LocationType.Symbol>(_LocationTypeSymbol_QNAME, LocationType.Symbol.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "highestTemperature", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeHighestTemperature(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeHighestTemperature_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Windspeed }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "windGust", scope = LocationType.class)
    public JAXBElement<Windspeed> createLocationTypeWindGust(Windspeed value) {
        return new JAXBElement<Windspeed>(_LocationTypeWindGust_QNAME, Windspeed.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "currentDirection", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeCurrentDirection(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeCurrentDirection_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocationType.StateOfTheSea }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "stateOfTheSea", scope = LocationType.class)
    public JAXBElement<LocationType.StateOfTheSea> createLocationTypeStateOfTheSea(LocationType.StateOfTheSea value) {
        return new JAXBElement<LocationType.StateOfTheSea>(_LocationTypeStateOfTheSea_QNAME, LocationType.StateOfTheSea.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "meanabsoluteerror", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeMeanabsoluteerror(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeMeanabsoluteerror_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Precipitation }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "maximumPrecipitation", scope = LocationType.class)
    public JAXBElement<Precipitation> createLocationTypeMaximumPrecipitation(Precipitation value) {
        return new JAXBElement<Precipitation>(_LocationTypeMaximumPrecipitation_QNAME, Precipitation.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Tidalwater }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "tidalwater", scope = LocationType.class)
    public JAXBElement<Tidalwater> createLocationTypeTidalwater(Tidalwater value) {
        return new JAXBElement<Tidalwater>(_LocationTypeTidalwater_QNAME, Tidalwater.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "waveHeight", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeWaveHeight(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeWaveHeight_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Precipitation }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "precipitation", scope = LocationType.class)
    public JAXBElement<Precipitation> createLocationTypePrecipitation(Precipitation value) {
        return new JAXBElement<Precipitation>(_LocationTypePrecipitation_QNAME, Precipitation.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Score }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "score", scope = LocationType.class)
    public JAXBElement<Score> createLocationTypeScore(Score value) {
        return new JAXBElement<Score>(_LocationTypeScore_QNAME, Score.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Windspeed }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "areaMaxWindSpeed", scope = LocationType.class)
    public JAXBElement<Windspeed> createLocationTypeAreaMaxWindSpeed(Windspeed value) {
        return new JAXBElement<Windspeed>(_LocationTypeAreaMaxWindSpeed_QNAME, Windspeed.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocationType.SnowDepth }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "snowDepth", scope = LocationType.class)
    public JAXBElement<LocationType.SnowDepth> createLocationTypeSnowDepth(LocationType.SnowDepth value) {
        return new JAXBElement<LocationType.SnowDepth>(_LocationTypeSnowDepth_QNAME, LocationType.SnowDepth.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Cloudiness }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "lowClouds", scope = LocationType.class)
    public JAXBElement<Cloudiness> createLocationTypeLowClouds(Cloudiness value) {
        return new JAXBElement<Cloudiness>(_LocationTypeLowClouds_QNAME, Cloudiness.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "minTemperature", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeMinTemperature(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeMinTemperature_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "bias", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeBias(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeBias_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "temperature", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeTemperature(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeTemperature_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocationType.Weather }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "weather", scope = LocationType.class)
    public JAXBElement<LocationType.Weather> createLocationTypeWeather(LocationType.Weather value) {
        return new JAXBElement<LocationType.Weather>(_LocationTypeWeather_QNAME, LocationType.Weather.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "humidity", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeHumidity(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeHumidity_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "numberofobservations", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeNumberofobservations(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeNumberofobservations_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocationType.WindDirection }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "windDirection", scope = LocationType.class)
    public JAXBElement<LocationType.WindDirection> createLocationTypeWindDirection(LocationType.WindDirection value) {
        return new JAXBElement<LocationType.WindDirection>(_LocationTypeWindDirection_QNAME, LocationType.WindDirection.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "maxTemperatureDay", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeMaxTemperatureDay(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeMaxTemperatureDay_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Windspeed }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "windSpeed", scope = LocationType.class)
    public JAXBElement<Windspeed> createLocationTypeWindSpeed(Windspeed value) {
        return new JAXBElement<Windspeed>(_LocationTypeWindSpeed_QNAME, Windspeed.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "wavePeriod", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeWavePeriod(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeWavePeriod_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "minTemperatureNight", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeMinTemperatureNight(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeMinTemperatureNight_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Uv }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "uv", scope = LocationType.class)
    public JAXBElement<Uv> createLocationTypeUv(Uv value) {
        return new JAXBElement<Uv>(_LocationTypeUv_QNAME, Uv.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Cloudiness }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "highClouds", scope = LocationType.class)
    public JAXBElement<Cloudiness> createLocationTypeHighClouds(Cloudiness value) {
        return new JAXBElement<Cloudiness>(_LocationTypeHighClouds_QNAME, Cloudiness.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "maxTemperatureNight", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeMaxTemperatureNight(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeMaxTemperatureNight_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "windProbability", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeWindProbability(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeWindProbability_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "maxWaveHeight", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeMaxWaveHeight(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeMaxWaveHeight_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "surfaceTemperature", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeSurfaceTemperature(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeSurfaceTemperature_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Pressure }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "pressure", scope = LocationType.class)
    public JAXBElement<Pressure> createLocationTypePressure(Pressure value) {
        return new JAXBElement<Pressure>(_LocationTypePressure_QNAME, Pressure.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Cloudiness }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "cloudiness", scope = LocationType.class)
    public JAXBElement<Cloudiness> createLocationTypeCloudiness(Cloudiness value) {
        return new JAXBElement<Cloudiness>(_LocationTypeCloudiness_QNAME, Cloudiness.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "waveDirection", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeWaveDirection(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeWaveDirection_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "symbolProbability", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeSymbolProbability(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeSymbolProbability_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "temperatureProbability", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeTemperatureProbability(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeTemperatureProbability_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Groundcover }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "groundCover", scope = LocationType.class)
    public JAXBElement<Groundcover> createLocationTypeGroundCover(Groundcover value) {
        return new JAXBElement<Groundcover>(_LocationTypeGroundCover_QNAME, Groundcover.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "minTemperatureDay", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeMinTemperatureDay(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeMinTemperatureDay_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Windspeed }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "maxWindSpeed", scope = LocationType.class)
    public JAXBElement<Windspeed> createLocationTypeMaxWindSpeed(Windspeed value) {
        return new JAXBElement<Windspeed>(_LocationTypeMaxWindSpeed_QNAME, Windspeed.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocationType.ForestFire }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "forest-fire", scope = LocationType.class)
    public JAXBElement<LocationType.ForestFire> createLocationTypeForestFire(LocationType.ForestFire value) {
        return new JAXBElement<LocationType.ForestFire>(_LocationTypeForestFire_QNAME, LocationType.ForestFire.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Cloudiness }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "mediumClouds", scope = LocationType.class)
    public JAXBElement<Cloudiness> createLocationTypeMediumClouds(Cloudiness value) {
        return new JAXBElement<Cloudiness>(_LocationTypeMediumClouds_QNAME, Cloudiness.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "dewpointTemperature", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeDewpointTemperature(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeDewpointTemperature_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "lowestTemperature", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeLowestTemperature(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeLowestTemperature_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Cloudiness }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "fog", scope = LocationType.class)
    public JAXBElement<Cloudiness> createLocationTypeFog(Cloudiness value) {
        return new JAXBElement<Cloudiness>(_LocationTypeFog_QNAME, Cloudiness.class, LocationType.class, value);
    }

}


/*
 * Copyright (c) 2011-2015 Amedia Utvikling AS.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package no.api.meteo.service.textforecast;

import no.api.meteo.MeteoException;
import no.api.meteo.client.MeteoClient;
import no.api.meteo.client.MeteoData;
import no.api.meteo.client.MeteoResponse;
import no.api.meteo.entity.core.MeteoServiceVersion;
import no.api.meteo.entity.core.service.textforecast.Weather;
import no.api.meteo.entity.core.service.textforecast.query.ForecastQuery;
import no.api.meteo.service.AbstractMeteoService;
import no.api.meteo.service.MeteoDataParser;

public class TextforecastService extends AbstractMeteoService {

    private final MeteoDataParser<Weather> parser;

    public TextforecastService(MeteoClient meteoClient) {
        super(meteoClient, "textforecast", new MeteoServiceVersion(1, 6));
        parser = new TextforecastParser();
    }

    /**
     * Fetch a textforecast for a named forecast
     *
     * @param query
     *         One of the predefined available textforecasts.
     *
     * @return A MeteoData object containing response information and textforecast converted into an Weather object.
     *
     * @throws MeteoException
     *         If a problem occurred while fetching or parsing the MET data.
     */
    public MeteoData<Weather> fetchContent(ForecastQuery query) throws MeteoException {
        MeteoResponse response = getMeteoClient().fetchContent(
                createServiceUriBuilder()
                        .addParameter("forecast", query.getName())
                        .addParameter("language", query.getLanguage().getValue())
                        .build());
        return new MeteoData<>(parser.parse(response.getData()), response);
    }

}


/*
 * Copyright (c) 2011-2015 Amedia Utvikling AS.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package no.api.meteo.service.locationforecast.extras;

import lombok.extern.slf4j.Slf4j;
import no.api.meteo.MeteoException;
import no.api.meteo.entity.core.service.locationforecast.LocationForecast;
import no.api.meteo.entity.extras.MeteoExtrasForecast;
import no.api.meteo.entity.extras.MeteoExtrasForecastDay;
import no.api.meteo.entity.extras.MeteoExtrasLongTermForecast;

import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static no.api.meteo.util.MeteoDateUtils.METZONE;
import static no.api.meteo.util.MeteoDateUtils.getNow;
import static no.api.meteo.util.MeteoDateUtils.toZeroHMSN;
import static no.api.meteo.util.MeteoDateUtils.toZeroMSN;

@Slf4j
public class LongtermForecastHelper extends AbstractForecastHelper {

    private final LongtermTimeSeries series;

    /**
     * Construct a new instance of this helper without any title set.
     *
     * @param locationForecast
     *         The location forecast this helper will work on.
     */
    public LongtermForecastHelper(LocationForecast locationForecast) {
        super(locationForecast);
        this.series = new LongtermTimeSeries();
    }

    /**
     * Create a longterm forecast, but only with a small subset of the weather data fields. Typically for use in simple
     * weather reports where you only show the predicted weather icon and temperature, and not all the weather details.
     *
     * @return A long term forecast, which is a week in our view of the world.
     *
     * @throws MeteoException
     *         If an error occurred while creating the simple longterm forecast.
     */
    public MeteoExtrasLongTermForecast createSimpleLongTermForecast() throws MeteoException {
        List<MeteoExtrasForecastDay> forecastDays = new ArrayList<>();
        ZonedDateTime dt = getNow();
        for (int i = 0; i <= 6; i++) {
            ZonedDateTime dti = dt.plusDays(i);
            if (getIndexer().hasForecastsForDay(dti)) {
                MeteoExtrasForecastDay mefd = createSimpleForcastForDay(dti);
                if (mefd != null && mefd.getForecasts().size() > 0) {
                    forecastDays.add(mefd);
                }
            }
        }
        return new MeteoExtrasLongTermForecast(forecastDays);
    }

    /**
     * Create a longterm forecast.
     *
     * @return A long term forecast, which is a week in our view of the world. But how many days you will get in this
     * forecast depends on the given location forecast. So from 0-7 can be expected.
     */
    public MeteoExtrasLongTermForecast createLongTermForecast() {
        List<MeteoExtrasForecastDay> forecastDays = new ArrayList<>();
        ZonedDateTime dt = toZeroHMSN(getLocationForecast().getCreated().plusDays(1));

        for (int i = 0; i < series.getSeries().size(); i++) {
            createLongTermForecastDay(dt.plusDays(i), series.getSeries().get(i))
                    .ifPresent(forecastDays::add);

        }

        return new MeteoExtrasLongTermForecast(forecastDays);
    }

    private Optional<MeteoExtrasForecastDay> createLongTermForecastDay(ZonedDateTime dt,
                                                                       LongtermTimeSeries.LongtermTimeSerie serie) {
        if (!getIndexer().hasForecastsForDay(dt)) {
            return Optional.empty();
        }

        List<MeteoExtrasForecast> forecasts = new ArrayList<>();
        for (LongtermTimeSeries.FromTo fromTo : serie.getFromTos()) {
            getForecastForPeriod(dt.plusHours(fromTo.getFrom()),
                                 dt.plusHours(fromTo.getTo()))
                    .ifPresent(forecasts::add);
        }
        return forecasts.size() > 0
                ? Optional.of(new MeteoExtrasForecastDay(dt.toLocalDate(), forecasts))
                : Optional.empty();
    }

    public MeteoExtrasForecastDay createSimpleForcastForDay(ZonedDateTime dateTime) {
        ZonedDateTime dt = toZeroMSN(dateTime.withZoneSameInstant(METZONE));
        List<MeteoExtrasForecast> forecasts = new ArrayList<>();
        //findNearestForecast(dt.withHour(12)).ifPresent(forecasts::add);
        return new MeteoExtrasForecastDay(dt.toLocalDate(), forecasts);
    }

}


/*
 * Copyright (c) 2011-2015 Amedia Utvikling AS.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package no.api.meteo.entity.core;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import net.sf.oval.constraint.NotNegative;
import net.sf.oval.constraint.NotNull;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Data
@JsonIgnoreProperties(ignoreUnknown = false)
public class Location {

    private static Pattern P = Pattern.compile("(\\d{1,3}\\.\\d{1,3}),(\\d{1,3}\\.\\d{1,3})(,\\d{1,4})?");

    @JsonProperty
    private final String name;

    @NotNull
    @NotNegative
    @JsonProperty
    private final Double longitude;

    @NotNull
    @NotNegative
    @JsonProperty
    private final Double latitude;

    @NotNegative
    @JsonProperty
    private final Integer altitude;

    @JsonCreator
    public Location(@JsonProperty("longitude") Double longitude,
                    @JsonProperty("latitude") Double latitude,
                    @JsonProperty("altitude") Integer altitude,
                    @JsonProperty("name") String name) {
        this.longitude = longitude;
        this.latitude = latitude;
        this.altitude = altitude;
        this.name = name;
    }

    /**
     * Create an untitled Location from coordinate string.
     *
     * @param coordinates Coordinate string on the format longitude,latitude,altitude. Eg: 20.3,123.3,123 or 20.3,123.3
     * @return Instance of the location with the coordinates from the input string.
     */
    public static Location fromCoordinates(String coordinates) {
        if (coordinates == null) {
            throw new IllegalArgumentException("Cannot create Location from null input.");
        }
        Matcher m = P.matcher(coordinates);
        if (!m.matches()) {
            throw new IllegalArgumentException(
                    coordinates + " must be on the pattern (longitude,latitude,altitude) : " + P.pattern());
        }

        try {
            Double longitude = Double.valueOf(m.group(1));
            Double latitude = Double.valueOf(m.group(2));
            Integer altitude = 0;
            if (m.group(3) != null) {
                altitude = Integer.valueOf(m.group(3).substring(1));
            }
            return new Location(longitude, latitude, altitude, "");
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException(
                    coordinates + " must be on the pattern (longitude,latitude,altitude) : " + P.pattern());
        }

    }
}


/*
 * Copyright (c) 2011-2015 Amedia Utvikling AS.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package no.api.meteo.service.textforecast.available;

import no.api.meteo.MeteoException;
import no.api.meteo.client.MeteoClient;
import no.api.meteo.client.MeteoData;
import no.api.meteo.client.MeteoResponse;
import no.api.meteo.entity.core.MeteoServiceVersion;
import no.api.meteo.entity.core.service.textforecast.available.Available;
import no.api.meteo.service.AbstractMeteoService;
import no.api.meteo.service.MeteoDataParser;

/**
 * Service object for fetching data for the Textforcast/Available service at https://api.met.no.
 *
 * https://api.met.no/weatherapi/textforecast/1.6/documentation
 */
public class AvailableTextforecastsService extends AbstractMeteoService {

    private final MeteoDataParser<Available> parser;

    public AvailableTextforecastsService(MeteoClient meteoClient) {
        super(meteoClient, "textforecast", new MeteoServiceVersion(1, 6));
        parser = new AvailableTextforecastsParser();
    }

    /**
     * Fetch a list of all available textforecasts.
     *
     * @return A MeteoData object containing response information and available textforecasts converted into an
     * Available object.
     *
     * @throws MeteoException
     *         If a problem occurred while fetching or parsing the MET data.
     */
    public MeteoData<Available> fetchContent() throws MeteoException {
        MeteoResponse response = getMeteoClient().fetchContent(
                createServiceUriBuilder().addParameter("available", null).skipQuestionMarkInUrl().build());
        return new MeteoData<>(parser.parse(response.getData()), response);
    }

}


//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2018.02.17 at 03:24:39 PM CET
//

package no.api.meteo.jaxb.probabilityforecast.v1_1;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;

/**
 * This object contains factory methods for each
 * Java content interface and Java element interface
 * generated in the no.api.meteo.jaxb.probabilityforecast.v1_1 package.
 *
An ObjectFactory allows you to programatically
 * construct new instances of the Java representation
 * for XML content. The Java representation of XML
 * content can consist of schema derived interfaces
 * and classes representing the binding of schema
 * type definitions, element declarations and model
 * groups.  Factory methods for each of these are
 * provided in this class.
 *
 */
@XmlRegistry
public class ObjectFactory {

    private final static QName _LocationTypeSymbol_QNAME = new QName("", "symbol");
    private final static QName _LocationTypeHighestTemperature_QNAME = new QName("", "highestTemperature");
    private final static QName _LocationTypeCurrentDirection_QNAME = new QName("", "currentDirection");
    private final static QName _LocationTypeStateOfTheSea_QNAME = new QName("", "stateOfTheSea");
    private final static QName _LocationTypeMaximumPrecipitation_QNAME = new QName("", "maximumPrecipitation");
    private final static QName _LocationTypeTidalwater_QNAME = new QName("", "tidalwater");
    private final static QName _LocationTypeWaveHeight_QNAME = new QName("", "waveHeight");
    private final static QName _LocationTypePrecipitation_QNAME = new QName("", "precipitation");
    private final static QName _LocationTypeSnowDepth_QNAME = new QName("", "snowDepth");
    private final static QName _LocationTypeLowClouds_QNAME = new QName("", "lowClouds");
    private final static QName _LocationTypeTemperature_QNAME = new QName("", "temperature");
    private final static QName _LocationTypeWeather_QNAME = new QName("", "weather");
    private final static QName _LocationTypeHumidity_QNAME = new QName("", "humidity");
    private final static QName _LocationTypeWindDirection_QNAME = new QName("", "windDirection");
    private final static QName _LocationTypeMaxTemperatureDay_QNAME = new QName("", "maxTemperatureDay");
    private final static QName _LocationTypeWindSpeed_QNAME = new QName("", "windSpeed");
    private final static QName _LocationTypeWavePeriod_QNAME = new QName("", "wavePeriod");
    private final static QName _LocationTypeMinTemperatureNight_QNAME = new QName("", "minTemperatureNight");
    private final static QName _LocationTypeUv_QNAME = new QName("", "uv");
    private final static QName _LocationTypeHighClouds_QNAME = new QName("", "highClouds");
    private final static QName _LocationTypeMaxTemperatureNight_QNAME = new QName("", "maxTemperatureNight");
    private final static QName _LocationTypeProbability_QNAME = new QName("", "probability");
    private final static QName _LocationTypeMaxWaveHeight_QNAME = new QName("", "maxWaveHeight");
    private final static QName _LocationTypeSurfaceTemperature_QNAME = new QName("", "surfaceTemperature");
    private final static QName _LocationTypePressure_QNAME = new QName("", "pressure");
    private final static QName _LocationTypeCloudiness_QNAME = new QName("", "cloudiness");
    private final static QName _LocationTypeWaveDirection_QNAME = new QName("", "waveDirection");
    private final static QName _LocationTypeGroundCover_QNAME = new QName("", "groundCover");
    private final static QName _LocationTypeMinTemperatureDay_QNAME = new QName("", "minTemperatureDay");
    private final static QName _LocationTypeMaxWindSpeed_QNAME = new QName("", "maxWindSpeed");
    private final static QName _LocationTypeForestFire_QNAME = new QName("", "forest-fire");
    private final static QName _LocationTypeMediumClouds_QNAME = new QName("", "mediumClouds");
    private final static QName _LocationTypeDewpointTemperature_QNAME = new QName("", "dewpointTemperature");
    private final static QName _LocationTypeLowestTemperature_QNAME = new QName("", "lowestTemperature");
    private final static QName _LocationTypeFog_QNAME = new QName("", "fog");

    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: no.api.meteo.jaxb.probabilityforecast.v1_1
     *
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link LocationType }
     *
     */
    public LocationType createLocationType() {
        return new LocationType();
    }

    /**
     * Create an instance of {@link Weatherdata }
     *
     */
    public Weatherdata createWeatherdata() {
        return new Weatherdata();
    }

    /**
     * Create an instance of {@link MetaType }
     *
     */
    public MetaType createMetaType() {
        return new MetaType();
    }

    /**
     * Create an instance of {@link ProductType }
     *
     */
    public ProductType createProductType() {
        return new ProductType();
    }

    /**
     * Create an instance of {@link Uv }
     *
     */
    public Uv createUv() {
        return new Uv();
    }

    /**
     * Create an instance of {@link Probability }
     *
     */
    public Probability createProbability() {
        return new Probability();
    }

    /**
     * Create an instance of {@link TimeType }
     *
     */
    public TimeType createTimeType() {
        return new TimeType();
    }

    /**
     * Create an instance of {@link ModelType }
     *
     */
    public ModelType createModelType() {
        return new ModelType();
    }

    /**
     * Create an instance of {@link Cloudiness }
     *
     */
    public Cloudiness createCloudiness() {
        return new Cloudiness();
    }

    /**
     * Create an instance of {@link Pressure }
     *
     */
    public Pressure createPressure() {
        return new Pressure();
    }

    /**
     * Create an instance of {@link Tidalwater }
     *
     */
    public Tidalwater createTidalwater() {
        return new Tidalwater();
    }

    /**
     * Create an instance of {@link Precipitation }
     *
     */
    public Precipitation createPrecipitation() {
        return new Precipitation();
    }

    /**
     * Create an instance of {@link Groundcover }
     *
     */
    public Groundcover createGroundcover() {
        return new Groundcover();
    }

    /**
     * Create an instance of {@link Temperature }
     *
     */
    public Temperature createTemperature() {
        return new Temperature();
    }

    /**
     * Create an instance of {@link Windspeed }
     *
     */
    public Windspeed createWindspeed() {
        return new Windspeed();
    }

    /**
     * Create an instance of {@link UnitValue }
     *
     */
    public UnitValue createUnitValue() {
        return new UnitValue();
    }

    /**
     * Create an instance of {@link LocationType.WindDirection }
     *
     */
    public LocationType.WindDirection createLocationTypeWindDirection() {
        return new LocationType.WindDirection();
    }

    /**
     * Create an instance of {@link LocationType.StateOfTheSea }
     *
     */
    public LocationType.StateOfTheSea createLocationTypeStateOfTheSea() {
        return new LocationType.StateOfTheSea();
    }

    /**
     * Create an instance of {@link LocationType.SnowDepth }
     *
     */
    public LocationType.SnowDepth createLocationTypeSnowDepth() {
        return new LocationType.SnowDepth();
    }

    /**
     * Create an instance of {@link LocationType.Weather }
     *
     */
    public LocationType.Weather createLocationTypeWeather() {
        return new LocationType.Weather();
    }

    /**
     * Create an instance of {@link LocationType.Symbol }
     *
     */
    public LocationType.Symbol createLocationTypeSymbol() {
        return new LocationType.Symbol();
    }

    /**
     * Create an instance of {@link LocationType.ForestFire }
     *
     */
    public LocationType.ForestFire createLocationTypeForestFire() {
        return new LocationType.ForestFire();
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocationType.Symbol }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "symbol", scope = LocationType.class)
    public JAXBElement<LocationType.Symbol> createLocationTypeSymbol(LocationType.Symbol value) {
        return new JAXBElement<LocationType.Symbol>(_LocationTypeSymbol_QNAME, LocationType.Symbol.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "highestTemperature", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeHighestTemperature(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeHighestTemperature_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "currentDirection", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeCurrentDirection(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeCurrentDirection_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocationType.StateOfTheSea }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "stateOfTheSea", scope = LocationType.class)
    public JAXBElement<LocationType.StateOfTheSea> createLocationTypeStateOfTheSea(LocationType.StateOfTheSea value) {
        return new JAXBElement<LocationType.StateOfTheSea>(_LocationTypeStateOfTheSea_QNAME, LocationType.StateOfTheSea.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Precipitation }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "maximumPrecipitation", scope = LocationType.class)
    public JAXBElement<Precipitation> createLocationTypeMaximumPrecipitation(Precipitation value) {
        return new JAXBElement<Precipitation>(_LocationTypeMaximumPrecipitation_QNAME, Precipitation.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Tidalwater }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "tidalwater", scope = LocationType.class)
    public JAXBElement<Tidalwater> createLocationTypeTidalwater(Tidalwater value) {
        return new JAXBElement<Tidalwater>(_LocationTypeTidalwater_QNAME, Tidalwater.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "waveHeight", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeWaveHeight(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeWaveHeight_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Precipitation }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "precipitation", scope = LocationType.class)
    public JAXBElement<Precipitation> createLocationTypePrecipitation(Precipitation value) {
        return new JAXBElement<Precipitation>(_LocationTypePrecipitation_QNAME, Precipitation.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocationType.SnowDepth }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "snowDepth", scope = LocationType.class)
    public JAXBElement<LocationType.SnowDepth> createLocationTypeSnowDepth(LocationType.SnowDepth value) {
        return new JAXBElement<LocationType.SnowDepth>(_LocationTypeSnowDepth_QNAME, LocationType.SnowDepth.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Cloudiness }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "lowClouds", scope = LocationType.class)
    public JAXBElement<Cloudiness> createLocationTypeLowClouds(Cloudiness value) {
        return new JAXBElement<Cloudiness>(_LocationTypeLowClouds_QNAME, Cloudiness.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "temperature", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeTemperature(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeTemperature_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocationType.Weather }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "weather", scope = LocationType.class)
    public JAXBElement<LocationType.Weather> createLocationTypeWeather(LocationType.Weather value) {
        return new JAXBElement<LocationType.Weather>(_LocationTypeWeather_QNAME, LocationType.Weather.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "humidity", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeHumidity(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeHumidity_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocationType.WindDirection }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "windDirection", scope = LocationType.class)
    public JAXBElement<LocationType.WindDirection> createLocationTypeWindDirection(LocationType.WindDirection value) {
        return new JAXBElement<LocationType.WindDirection>(_LocationTypeWindDirection_QNAME, LocationType.WindDirection.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "maxTemperatureDay", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeMaxTemperatureDay(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeMaxTemperatureDay_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Windspeed }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "windSpeed", scope = LocationType.class)
    public JAXBElement<Windspeed> createLocationTypeWindSpeed(Windspeed value) {
        return new JAXBElement<Windspeed>(_LocationTypeWindSpeed_QNAME, Windspeed.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "wavePeriod", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeWavePeriod(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeWavePeriod_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "minTemperatureNight", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeMinTemperatureNight(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeMinTemperatureNight_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Uv }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "uv", scope = LocationType.class)
    public JAXBElement<Uv> createLocationTypeUv(Uv value) {
        return new JAXBElement<Uv>(_LocationTypeUv_QNAME, Uv.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Cloudiness }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "highClouds", scope = LocationType.class)
    public JAXBElement<Cloudiness> createLocationTypeHighClouds(Cloudiness value) {
        return new JAXBElement<Cloudiness>(_LocationTypeHighClouds_QNAME, Cloudiness.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "maxTemperatureNight", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeMaxTemperatureNight(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeMaxTemperatureNight_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Probability }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "probability", scope = LocationType.class)
    public JAXBElement<Probability> createLocationTypeProbability(Probability value) {
        return new JAXBElement<Probability>(_LocationTypeProbability_QNAME, Probability.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "maxWaveHeight", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeMaxWaveHeight(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeMaxWaveHeight_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "surfaceTemperature", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeSurfaceTemperature(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeSurfaceTemperature_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Pressure }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "pressure", scope = LocationType.class)
    public JAXBElement<Pressure> createLocationTypePressure(Pressure value) {
        return new JAXBElement<Pressure>(_LocationTypePressure_QNAME, Pressure.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Cloudiness }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "cloudiness", scope = LocationType.class)
    public JAXBElement<Cloudiness> createLocationTypeCloudiness(Cloudiness value) {
        return new JAXBElement<Cloudiness>(_LocationTypeCloudiness_QNAME, Cloudiness.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link UnitValue }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "waveDirection", scope = LocationType.class)
    public JAXBElement<UnitValue> createLocationTypeWaveDirection(UnitValue value) {
        return new JAXBElement<UnitValue>(_LocationTypeWaveDirection_QNAME, UnitValue.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Groundcover }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "groundCover", scope = LocationType.class)
    public JAXBElement<Groundcover> createLocationTypeGroundCover(Groundcover value) {
        return new JAXBElement<Groundcover>(_LocationTypeGroundCover_QNAME, Groundcover.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "minTemperatureDay", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeMinTemperatureDay(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeMinTemperatureDay_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Windspeed }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "maxWindSpeed", scope = LocationType.class)
    public JAXBElement<Windspeed> createLocationTypeMaxWindSpeed(Windspeed value) {
        return new JAXBElement<Windspeed>(_LocationTypeMaxWindSpeed_QNAME, Windspeed.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocationType.ForestFire }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "forest-fire", scope = LocationType.class)
    public JAXBElement<LocationType.ForestFire> createLocationTypeForestFire(LocationType.ForestFire value) {
        return new JAXBElement<LocationType.ForestFire>(_LocationTypeForestFire_QNAME, LocationType.ForestFire.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Cloudiness }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "mediumClouds", scope = LocationType.class)
    public JAXBElement<Cloudiness> createLocationTypeMediumClouds(Cloudiness value) {
        return new JAXBElement<Cloudiness>(_LocationTypeMediumClouds_QNAME, Cloudiness.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "dewpointTemperature", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeDewpointTemperature(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeDewpointTemperature_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Temperature }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "lowestTemperature", scope = LocationType.class)
    public JAXBElement<Temperature> createLocationTypeLowestTemperature(Temperature value) {
        return new JAXBElement<Temperature>(_LocationTypeLowestTemperature_QNAME, Temperature.class, LocationType.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Cloudiness }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "fog", scope = LocationType.class)
    public JAXBElement<Cloudiness> createLocationTypeFog(Cloudiness value) {
        return new JAXBElement<Cloudiness>(_LocationTypeFog_QNAME, Cloudiness.class, LocationType.class, value);
    }

}


//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2018.02.17 at 03:46:58 PM CET
//

package no.api.meteo.jaxb.textforecast.v1_6;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;

/**
 * This object contains factory methods for each
 * Java content interface and Java element interface
 * generated in the no.api.meteo.jaxb.textforecast.v1_6 package.
 *
An ObjectFactory allows you to programatically
 * construct new instances of the Java representation
 * for XML content. The Java representation of XML
 * content can consist of schema derived interfaces
 * and classes representing the binding of schema
 * type definitions, element declarations and model
 * groups.  Factory methods for each of these are
 * provided in this class.
 *
 */
@XmlRegistry
public class ObjectFactory {

    private final static QName _Productdescription_QNAME = new QName("", "productdescription");
    private final static QName _Header_QNAME = new QName("", "header");
    private final static QName _Comment_QNAME = new QName("", "comment");
    private final static QName _Title_QNAME = new QName("", "title");

    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: no.api.meteo.jaxb.textforecast.v1_6
     *
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link Locationlist }
     *
     */
    public Locationlist createLocationlist() {
        return new Locationlist();
    }

    /**
     * Create an instance of {@link Img }
     *
     */
    public Img createImg() {
        return new Img();
    }

    /**
     * Create an instance of {@link Br }
     *
     */
    public Br createBr() {
        return new Br();
    }

    /**
     * Create an instance of {@link Blank }
     *
     */
    public Blank createBlank() {
        return new Blank();
    }

    /**
     * Create an instance of {@link Hr }
     *
     */
    public Hr createHr() {
        return new Hr();
    }

    /**
     * Create an instance of {@link Tab }
     *
     */
    public Tab createTab() {
        return new Tab();
    }

    /**
     * Create an instance of {@link Productheader }
     *
     */
    public Productheader createProductheader() {
        return new Productheader();
    }

    /**
     * Create an instance of {@link Displaytime }
     *
     */
    public Displaytime createDisplaytime() {
        return new Displaytime();
    }

    /**
     * Create an instance of {@link Repeat }
     *
     */
    public Repeat createRepeat() {
        return new Repeat();
    }

    /**
     * Create an instance of {@link Location }
     *
     */
    public Location createLocation() {
        return new Location();
    }

    /**
     * Create an instance of {@link Parameter }
     *
     */
    public Parameter createParameter() {
        return new Parameter();
    }

    /**
     * Create an instance of {@link Text }
     *
     */
    public Text createText() {
        return new Text();
    }

    /**
     * Create an instance of {@link Value }
     *
     */
    public Value createValue() {
        return new Value();
    }

    /**
     * Create an instance of {@link Variable }
     *
     */
    public Variable createVariable() {
        return new Variable();
    }

    /**
     * Create an instance of {@link In }
     *
     */
    public In createIn() {
        return new In();
    }

    /**
     * Create an instance of {@link Forecast }
     *
     */
    public Forecast createForecast() {
        return new Forecast();
    }

    /**
     * Create an instance of {@link Newitem }
     *
     */
    public Newitem createNewitem() {
        return new Newitem();
    }

    /**
     * Create an instance of {@link Weather }
     *
     */
    public Weather createWeather() {
        return new Weather();
    }

    /**
     * Create an instance of {@link Guielement }
     *
     */
    public Guielement createGuielement() {
        return new Guielement();
    }

    /**
     * Create an instance of {@link Guilist }
     *
     */
    public Guilist createGuilist() {
        return new Guilist();
    }

    /**
     * Create an instance of {@link Guilistelement }
     *
     */
    public Guilistelement createGuilistelement() {
        return new Guilistelement();
    }

    /**
     * Create an instance of {@link Time }
     *
     */
    public Time createTime() {
        return new Time();
    }

    /**
     * Create an instance of {@link Subtitle }
     *
     */
    public Subtitle createSubtitle() {
        return new Subtitle();
    }

    /**
     * Create an instance of {@link Forecasttype }
     *
     */
    public Forecasttype createForecasttype() {
        return new Forecasttype();
    }

    /**
     * Create an instance of {@link Slocation }
     *
     */
    public Slocation createSlocation() {
        return new Slocation();
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "productdescription")
    public JAXBElement<String> createProductdescription(String value) {
        return new JAXBElement<String>(_Productdescription_QNAME, String.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "header")
    public JAXBElement<String> createHeader(String value) {
        return new JAXBElement<String>(_Header_QNAME, String.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "comment")
    public JAXBElement<String> createComment(String value) {
        return new JAXBElement<String>(_Comment_QNAME, String.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "", name = "title")
    public JAXBElement<String> createTitle(String value) {
        return new JAXBElement<String>(_Title_QNAME, String.class, null, value);
    }

}


/*
 * Copyright (c) 2011-2015 Amedia Utvikling AS.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package no.api.meteo.service.locationforecast.extras;

import no.api.meteo.entity.core.service.locationforecast.PointForecast;
import no.api.meteo.entity.extras.BeaufortLevel;

import java.text.DecimalFormat;
import java.util.Optional;

import static no.api.meteo.entity.extras.BeaufortLevel.findUnitById;

/**
 * Helper class for wind symbols.
 */
public final class WindSymbolHelper {

    private static final DecimalFormat idFormat = new DecimalFormat("00");

    private WindSymbolHelper() {
        throw new UnsupportedOperationException();
    }

    /**
     * Create name for a wind symbol.
     *
     * This will be created as a mix of the Beaufort wind speed id and the wind direction. This name can be used to
     * identify what wind icon that should be used for a forecast.
     *
     * @param pointForecast
     *         The point forecast to create a wind symbol name for.
     *
     * @return A wind symbol name. null if wind information was missing from the given point forecast.
     */
    public static Optional<String> createWindSymbolName(PointForecast pointForecast) {
        if (pointForecast == null || pointForecast.getWindDirection() == null || pointForecast.getWindSpeed() == null) {
            return Optional.empty();
        }
        return Optional.of(
                pointForecast.getWindDirection().getName().toLowerCase()
                        + idFormat.format(pointForecast.getWindSpeed().getBeaufort()));
    }

    /**
     * Find matching Beaufort level for a given point forecast.
     *
     * This provides you with extra information about the wind speed specified in the forecast.
     *
     * @param pointForecast
     *         Point forecast containing information about the wind speed.
     *
     * @return Matching Beaufort level object. null if wind speed information is missing from the given
     * forecast.
     */
    public static Optional<BeaufortLevel> findBeaufortLevel(PointForecast pointForecast) {
        if (pointForecast == null || pointForecast.getWindSpeed() == null) {
            return Optional.empty();
        }
        return Optional.ofNullable(findUnitById(pointForecast.getWindSpeed().getBeaufort()));
    }

}


/*
 * Copyright (c) 2011-2015 Amedia Utvikling AS.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package no.api.meteo.util;

import no.api.meteo.MeteoException;

import java.net.URI;
import java.net.URISyntaxException;

/**
 * Util class for dealing with different net issues.
 */
public final class MeteoNetUtils {

    private MeteoNetUtils() {
        throw new UnsupportedOperationException();
    }

    /**
     * Wrap the construction of URL's to avoid throwing of checked MalformedURLException. Instead MeteoException
     * is thrown.
     *
     * @param uri The url string to be used as the spec for the create URL object.
     * @return URL object created from the given url spec.
     * @throws no.api.meteo.MeteoException If a URL couldn't be created from the given url spec.
     */
    public static URI createUri(String uri) throws MeteoException {
        if (uri == null) {
            throw new MeteoException("URI is null");
        }
        try {
            return new URI(uri);
        } catch (URISyntaxException e) {
            throw new MeteoException(e);
        }
    }

}


/*
 * Copyright (c) 2011-2015 Amedia Utvikling AS.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package no.api.meteo.entity.core.service.sunrise;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import no.api.meteo.util.jackson.LocalDateDeserializer;
import no.api.meteo.util.jackson.LocalDateSerializer;

import java.time.LocalDate;
import java.time.ZonedDateTime;

@Value
@Slf4j
public final class SunriseDate {

    @JsonProperty
    @JsonSerialize(using = LocalDateSerializer.class)
    @JsonDeserialize(using = LocalDateDeserializer.class)
    private final LocalDate date;

    @JsonProperty
    private final Sun sun;

    @JsonProperty
    private final Moon moon;

    @JsonCreator
    public SunriseDate(@JsonProperty("date") LocalDate date,
                       @JsonProperty("sun") Sun sun,
                       @JsonProperty("moon") Moon moon) {
        this.date = date;
        this.sun = sun;
        this.moon = moon;
    }

    public boolean isPolarNight() {
        return getSun().getNeverRise();
    }

    public boolean isNight(ZonedDateTime time) {
        return isPolarNight() || !isSun(time);
    }

    /**
     * Check if the sun is shining for a given time.
     *
     * @param currentDate
     *         The time (date) to be checked.
     *
     * @return true if the sun has raised, else false.
     */
    public boolean isSun(ZonedDateTime currentDate) {
        if (getSun().getNeverRise()) {
            return false;
        } else if (getSun().getNeverSet()) {
            return true;
        }
        return timeWithinPeriod(currentDate);
    }

    private boolean timeWithinPeriod(ZonedDateTime currentDate) {
        if (currentDate.equals(getSun().getRise())) {
            return true;
        } else if (currentDate.equals(getSun().getSet())) {
            return true;
        } else if (getSun().getRise() != null && getSun().getSet() != null) {
            return currentDate.isAfter(getSun().getRise()) && currentDate.isBefore(getSun().getSet());
        } else if (getSun().getRise() != null) {
            return currentDate.isAfter(getSun().getRise());
        } else {
            log.error("Something went wrong. Couldn't check if time is within period as getSet == null. Returning true.");
            return true;
        }
    }
}


/*
 * Copyright (c) 2011-2015 Amedia Utvikling AS.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package no.api.meteo.service.locationforecast.extras;

import lombok.extern.slf4j.Slf4j;
import no.api.meteo.entity.core.service.locationforecast.Forecast;
import no.api.meteo.entity.core.service.locationforecast.PeriodForecast;
import no.api.meteo.entity.core.service.locationforecast.PointForecast;

import java.time.Duration;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static no.api.meteo.util.MeteoDateUtils.cloneZonedDateTime;
import static no.api.meteo.util.MeteoDateUtils.toZeroMSN;

@Slf4j
class MeteoForecastIndexer {

    private final List<Forecast> forecasts;

    private Map<HourMatcher, List<ScoreForecast>> hourIndex;

    private Map<DayIndexKey, List<PeriodForecast>> dayIndex;

    MeteoForecastIndexer(List<Forecast> forecasts) {
        this.forecasts = forecasts;
        init();
    }

    /**
     * Get the PointForecast that matches the given time.
     *
     * @param dateTime
     *         Date object used to find a matching PointForecast.
     *
     * @return A matching PointForecast if found, else null.
     */
    Optional<PointForecast> getPointForecast(ZonedDateTime dateTime) {
        for (Forecast forecast : forecasts) {
            if (forecast instanceof PointForecast) {
                PointForecast pointForecast = (PointForecast) forecast;
                if (createHourIndexKey(dateTime)
                        .equals(createHourIndexKey(cloneZonedDateTime(pointForecast.getFrom())))) {
                    return Optional.of(pointForecast);
                }
            }
        }
        return Optional.empty();
    }

    Optional<PeriodForecast> getExactFitPeriodForecast(ZonedDateTime from, ZonedDateTime to) {
        if (from == null || to == null) {
            return Optional.empty();
        }

        List<PeriodForecast> forecastsList = dayIndex.get(new DayIndexKey(from));
        if (forecastsList == null) {
            return Optional.empty();
        }

        for (PeriodForecast forecast : forecastsList) {
            if (forecast.getFrom().equals(from) && forecast.getTo().equals(to)) {
                return Optional.of(forecast);
            }
        }
        return Optional.empty();
    }

    /*List<PeriodForecast> getMatchingPeriodForecasts(ZonedDateTime from) {
        List<PeriodForecast> periodForecasts = new ArrayList<>();
        List<ScoreForecast> scoreForecasts = getMatchingScoreForecasts(from);
        if (scoreForecasts == null) {
            return periodForecasts;
        }
        periodForecasts.addAll(
                scoreForecasts
                        .stream()
                        .map(ScoreForecast::getPeriodForecast)
                        .collect(Collectors.toList()));
        return periodForecasts;
    }*/

    /*List<ScoreForecast> getMatchingScoreForecasts(ZonedDateTime from) {
        return hourIndex.get(createHourIndexKey(cloneZonedDateTime(from)));
    }*/

    /*
    * Find the period forecast that is the tightest fit for a point forecast.
    *
    *
We use two rules to decide what the "tightest fit" is. First we look at the time span within a PeriodForecast.
    * Secondly we look at the distance from the start of the PeriodForecast to the PointForecast. The sum of these two
    * numbers gives a tightScore. The period forecast with the lowest tightScore is considered to be the tightest
    * fit.

    *
    *
Example

    *
    *
Lets says we have a PeriodForecast with from time set to 12:00 PM and toTime set to 04:00 PM. This gives us a 4
    * hour span.

    *
    *

    *  12:00 PM.................................................................................04:00 PM
    *
    *  12:00 PM...............01:00 PM
    *

    *
    *
Then we have a PointForecast for 01:00 PM. The distance from 01:00 PM to 12:00 PM is 1 hour. When we add the
    * span (4) and the distance (1) we get the tightScore (5).

    *
    */
    Optional<PeriodForecast> getTightestFitPeriodForecast(ZonedDateTime from) {
        return  getXScoreForecast(from, false).map(ScoreForecast::getPeriodForecast);
    }

    boolean hasForecastsForDay(ZonedDateTime from) {
        return dayIndex.containsKey(new DayIndexKey(from));
    }

    /*
    * Find the period forecast that is the widest fit for a point forecast.
    *
    *
We use the exact same kind of logic to find the widest fit as we do for the tightest fit. The only change is
    * that we invert the span tightScore. Meaning that a large span will tightScore lower than a small span

    *
    */
    Optional<PeriodForecast> getWidestFitPeriodForecast(ZonedDateTime from) {
        if (from == null) {
            return Optional.empty();
        }
        return getWidestFitScoreForecast(from).map(ScoreForecast::getPeriodForecast);
    }

    /**
     * Find the period forecast that has the best fitted forecast for a given period.
     *
     * This means a forecast covering the requested period, with to and from time closest possible to that period. If
     * this function only can find a period forecast that covers parts of the requested period, then the forecast
     * covering the most will be used.
     */
    Optional<PeriodForecast> getBestFitPeriodForecast(ZonedDateTime from, ZonedDateTime to) {
        if (from == null || to == null) {
            return Optional.empty();
        }

        // Making sure that we remove minutes, seconds and milliseconds from the request timestamps
        ZonedDateTime requestFrom = toZeroMSN(from);
        ZonedDateTime requestTo = toZeroMSN(to);

        //  Get list of period forecasts for the requested day. Return empty if date isn't present
        List<PeriodForecast> forecastsList = dayIndex.get(new DayIndexKey(requestFrom));
        if (forecastsList == null) {
            return Optional.empty();
        }

        PeriodForecast chosenForecast = null;
        long score = 0;
        long tmpScore = 0;

        for (PeriodForecast forecast : forecastsList) {
            ZonedDateTime actualFrom = cloneZonedDateTime(forecast.getFrom());

            ZonedDateTime actualTo = cloneZonedDateTime(forecast.getTo());

            if (requestFrom.equals(actualFrom) && requestTo.equals(actualTo)) {
                return Optional.of(forecast);
            } else if (
                    (requestFrom.isBefore(actualFrom) && requestTo.isBefore(actualFrom)) ||
                            (requestFrom.isAfter(actualTo) && requestTo.isAfter(actualTo)) ||
                            actualTo.isEqual(actualFrom)) {
                continue; // this period is outside the requested period or this is a point forecast.
            } else if (requestFrom.isBefore(actualFrom) && requestTo.isBefore(actualTo)) {
                tmpScore = hoursBetween(requestTo, actualFrom);
            } else if ((actualFrom.isBefore(requestFrom) || actualFrom.isEqual(requestFrom)) &&
                    actualTo.isBefore(requestTo)) {
                tmpScore = hoursBetween(actualTo, requestFrom);
            } else if (actualFrom.isAfter(requestFrom) &&
                    (actualTo.isBefore(requestTo) || actualTo.isEqual(requestTo))) {
                tmpScore = hoursBetween(actualTo, actualFrom);
            } else if (actualFrom.isBefore(requestFrom) && actualTo.isAfter(requestTo)) {
                tmpScore = hoursBetween(requestTo, requestFrom);
            } else {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd:HH:mm");
                log.warn("Unhandled forecast Requested period:" + requestFrom.format(formatter) + "--" +
                                 requestTo.format(formatter) + ", Actual period: " +
                                 actualFrom.format(formatter) + "--" + actualTo.format(formatter));
            }

            tmpScore = Math.abs(tmpScore);

            if ((score == 0 && tmpScore > 0) || tmpScore > score) {
                score = tmpScore;
                chosenForecast = forecast;
            }
        }

        return Optional.ofNullable(chosenForecast);
    }

    Optional<ScoreForecast> getWidestFitScoreForecast(ZonedDateTime time) {
        return getXScoreForecast(time, true);
    }

    private Optional<ScoreForecast> getXScoreForecast(ZonedDateTime time, boolean widest) {
        if (time == null) {
            return Optional.empty();
        }
        HourMatcher hourMatcher = createHourIndexKey(cloneZonedDateTime(time));
        if (!hourIndex.containsKey(hourMatcher)) {
            return Optional.empty();
        }
        List<ScoreForecast> scoreForecasts = hourIndex.get(hourMatcher);
        ScoreForecast forecast = null;
        for (ScoreForecast scoreForecast : scoreForecasts) {
            if (forecast == null) {
                forecast = scoreForecast;
            } else {
                long lowestScore = (widest ? forecast.getPointWideScore() : forecast.getPointTightScore());
                long forecastScore = (widest ? scoreForecast.getPointWideScore() : scoreForecast.getPointTightScore());
                if (forecastScore < lowestScore) {
                    forecast = scoreForecast;
                }
            }
        }
        return Optional.ofNullable(forecast);
    }

    private void init() {
        hourIndex = new HashMap<>();
        dayIndex = new HashMap<>();
        // Handle hour index
        // Handle period index
        forecasts.stream()
                .filter(forecast -> forecast instanceof PeriodForecast)
                .forEach(forecast -> {
                    PeriodForecast periodForecast = (PeriodForecast) forecast;

                    // Handle hour index
                    List<HourMatcher> indexKeys = createIndexKeysFromPeriodForecast(periodForecast);
                    for (HourMatcher hourMatcher : indexKeys) {
                        ScoreForecast scoreForecast =
                                new ScoreForecast(periodForecast, calculatePointScore(periodForecast, hourMatcher, 1),
                                                  calculatePointScore(periodForecast, hourMatcher, -1));
                        addForecastToHourIndex(hourMatcher, scoreForecast);
                    }

                    // Handle period index
                    DayIndexKey dayIndexKey = new DayIndexKey(cloneZonedDateTime(periodForecast.getFrom()));
                    addForecastToPeriodIndex(dayIndexKey, periodForecast);
                });
    }

    private long calculatePointScore(PeriodForecast periodForecast, HourMatcher hourMatcher, int spanWeight) {
        ZonedDateTime periodFrom = cloneZonedDateTime(periodForecast.getFrom());
        ZonedDateTime periodTo = cloneZonedDateTime(periodForecast.getTo());
        return (hoursBetween(periodFrom, periodTo) * spanWeight) +
                hoursBetween(periodFrom, hourMatcher.getDateTime());
    }

    private long hoursBetween(ZonedDateTime from, ZonedDateTime to) {
        return Duration.between(from.toInstant(), to.toInstant()).toHours();
    }

    private List<HourMatcher> createIndexKeysFromPeriodForecast(PeriodForecast periodForecast) {
        List<HourMatcher> keyList = new ArrayList<>();
        ZonedDateTime from = cloneZonedDateTime(periodForecast.getFrom());
        ZonedDateTime activeTime = cloneZonedDateTime(periodForecast.getTo());
        while (activeTime.isAfter(from)) {
            keyList.add(createHourIndexKey(activeTime));
            activeTime = activeTime.minusHours(1);
        }
        keyList.add(createHourIndexKey(from));
        return keyList;
    }

    private void addForecastToHourIndex(HourMatcher key, ScoreForecast scoreForecast) {
        if (hourIndex.containsKey(key)) {
            hourIndex.get(key).add(scoreForecast);
        } else {
            List<ScoreForecast> indexList = new ArrayList<>();
            indexList.add(scoreForecast);
            hourIndex.put(key, indexList);
        }
    }

    private void addForecastToPeriodIndex(DayIndexKey key, PeriodForecast periodForecast) {
        if (dayIndex.containsKey(key)) {
            dayIndex.get(key).add(periodForecast);
        } else {
            List<PeriodForecast> indexList = new ArrayList<>();
            indexList.add(periodForecast);
            dayIndex.put(key, indexList);
        }
    }

    private HourMatcher createHourIndexKey(ZonedDateTime pointInTime) {
        return new HourMatcher(pointInTime);
    }

}


/*
 * Copyright (c) 2011-2015 Amedia Utvikling AS.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package no.api.meteo.service.textlocation;

import no.api.meteo.MeteoException;
import no.api.meteo.client.MeteoClient;
import no.api.meteo.client.MeteoData;
import no.api.meteo.client.MeteoResponse;
import no.api.meteo.entity.core.MeteoServiceVersion;
import no.api.meteo.entity.core.service.textlocation.TextLocationWeather;
import no.api.meteo.service.AbstractMeteoService;
import no.api.meteo.service.MeteoDataParser;

/**
 * This service returns textforecasts and warnings for a geographical point or area. This includes text from other
 * sources than met.no
 */
public class TextLocationService extends AbstractMeteoService {

    private final MeteoDataParser<TextLocationWeather> parser;

    public TextLocationService(MeteoClient meteoClient) {
        super(meteoClient, "textlocation", new MeteoServiceVersion(1, 0));
        parser = new TextLocationParser();
    }

    /**
     * Fetch textforecasts and warnings for a geographical point or area, in Norwegian.
     *
     * @param longitude
     *         The longitude for the geographical point.
     * @param latitude
     *         The latitude for the geographical point.
     *
     * @return A MeteoData object containing response information and textforecast converted into an TextLocationWeather
     * object.
     *
     * @throws MeteoException
     *         If a problem occurred while fetching or parsing the MET data.
     */
    public MeteoData<TextLocationWeather> fetchContent(double longitude, double latitude)
            throws MeteoException {
        return fetchContent(longitude, latitude, TextLocationLanguage.NB);

    }

    /**
     * Fetch textforecasts and warnings for a geographical point or area.
     *
     * @param longitude
     *         The longitude for the geographical point.
     * @param latitude
     *         The latitude for the geographical point.
     * @param language
     *         The chosen language for the forecast. Note that textforecasts in english are available for only some
     *         areas and some types ( e.g textforecasts for the coastal areas ).
     *
     * @return A MeteoData object containing response information and textforecast converted into an TextLocationWeather
     * object.
     *
     * @throws MeteoException
     *         If a problem occurred while fetching or parsing the MET data.
     */
    public MeteoData<TextLocationWeather> fetchContent(double longitude, double latitude, TextLocationLanguage language)
            throws MeteoException {
        MeteoResponse response = getMeteoClient().fetchContent(
                createServiceUriBuilder()
                        .addParameter("latitude", latitude)
                        .addParameter("longitude", longitude)
                        .addParameter("language", language.getValue())
                        .build());
        return new MeteoData<>(parser.parse(response.getData()), response);
    }

}