Drone3D-Team/Drone3D

View on GitHub
app/src/main/java/ch/epfl/sdp/drone3d/service/impl/weather/OpenWeatherWeatherService.kt

Summary

Maintainability
A
0 mins
Test Coverage
A
90%
/*
 * Copyright (C) 2021  Drone3D-Team
 * The license can be found in LICENSE at root of the repository
 */

package ch.epfl.sdp.drone3d.service.impl.weather

import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import ch.epfl.sdp.drone3d.R
import ch.epfl.sdp.drone3d.model.weather.WeatherReport
import ch.epfl.sdp.drone3d.service.api.weather.WeatherService
import com.mapbox.mapboxsdk.geometry.LatLng
import dagger.hilt.android.qualifiers.ApplicationContext
import org.json.JSONObject
import timber.log.Timber
import java.net.URL
import java.util.*
import javax.inject.Inject
import kotlin.concurrent.thread

/**
 * WeatherService implementation using OpenWeather API
 */
class OpenWeatherWeatherService @Inject constructor(@ApplicationContext val context: Context) :
    WeatherService {

    companion object {
        private const val API_ENDPOINT = "https://api.openweathermap.org/data/2.5/weather?"
        private const val TEMP_UNIT = "metric"
        private val NO_DATA = WeatherReport("N/A", "N/A", null, 0.0, 0, 0.0, 0, Date())
    }

    override fun getWeatherReport(location: LatLng): LiveData<WeatherReport> {
        val liveData = MutableLiveData<WeatherReport>()
        thread {
            try {
                val data = fetchAPI(location)
                val report = parseJsonToWeatherReport(data)
                liveData.postValue(report)
            } catch (ex: Exception) {
                ex.printStackTrace()
            }
        }
        return liveData
    }

    /**
     * Parse a json string into a WeatherReport
     */
    private fun parseJsonToWeatherReport(jsonReport: String): WeatherReport {
        var report = NO_DATA
        try {
            /* Extracting JSON returns from the API */
            val jsonObj = JSONObject(jsonReport)
            val main = jsonObj.getJSONObject("main")
            val wind = jsonObj.getJSONObject("wind")
            val weather = jsonObj.getJSONArray("weather").getJSONObject(0)

            val iconId = weather.getString("icon")
            val updatedAt = Date(jsonObj.getLong("dt") * 1000)
            val temperature = main.getDouble("temp")
            val humidity = main.getInt("humidity")
            val windSpeed = wind.getDouble("speed")
            val description = weather.getString("description")
            val keywordDescription = weather.getString("main")
            val visibility = jsonObj.getInt("visibility")


            report = WeatherReport(
                keywordDescription,
                description,
                iconId,
                temperature,
                humidity,
                windSpeed,
                visibility,
                updatedAt
            )
        } catch (e: Exception) {
            Timber.e(e, "Error when getting the weather : $e")
        }
        return report
    }

    /**
     * Fetch OpenWeather API
     */
    private fun fetchAPI(location: LatLng): String {
        val queryUrl = API_ENDPOINT +
                "lat=" + location.latitude +
                "&lon=" + location.longitude +
                "&units=" + TEMP_UNIT +
                "&appid=" + context.getString(R.string.open_weather_api_key)
        return URL(queryUrl).readText()
    }

}