package edu.purdue.app.weather;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import android.content.Context;
// Currently, Forecast.io API is being used for weather data.
// Example Request: https://api.forecast.io/forecast/0feee70df504bc654228bb08b8b36fb3/40.4240,-86.9290
public class WeatherAPI
{
private static final String API_KEY = "0feee70df504bc654228bb08b8b36fb3"; //API key for api.forecast.io.
private static final String PURDUE_COORDINATES = "40.4240,-86.9290";
private static final String JSON_CACHE_FILENAME = "cachedWeatherJSON.json";
/*
* Requests the weather data from the API. Returns null if the request fails.
*/
protected static String getWeatherData(Context context) {
String cachedJSON = WeatherAPI.readJSONFromCache(context, JSON_CACHE_FILENAME);
if (cachedJSON == null) {
// Cached data is does not exist, request it from API
String weatherData = sendGetRequest("https://api.forecast.io/forecast/"+API_KEY+"/"+PURDUE_COORDINATES);
WeatherAPI.writeJSONToCache(weatherData, context, JSON_CACHE_FILENAME);
return weatherData;
} else {
int cacheTimestamp=0;
try {
JSONObject object = (JSONObject) new JSONTokener(cachedJSON).nextValue();
cacheTimestamp = Integer.parseInt((object.getJSONObject("currently").get("time")+""));
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
Calendar currentCal = Calendar.getInstance();
Calendar cachedCal = Calendar.getInstance();
cachedCal.setTimeInMillis(cacheTimestamp*1000L);
if ((cachedCal.get(Calendar.YEAR)!=currentCal.get(Calendar.YEAR)) || (cachedCal.get(Calendar.MONTH)!=currentCal.get(Calendar.MONTH)) || cachedCal.get(Calendar.DAY_OF_MONTH)!=currentCal.get(Calendar.DAY_OF_MONTH) || (cachedCal.get(Calendar.HOUR_OF_DAY)!=currentCal.get(Calendar.HOUR_OF_DAY))) {
// Cached data is older than an hour, request it from API
String weatherData = sendGetRequest("https://api.forecast.io/forecast/"+API_KEY+"/"+PURDUE_COORDINATES);
WeatherAPI.writeJSONToCache(weatherData, context, JSON_CACHE_FILENAME);
return weatherData;
}
// Cached data is not older than an hour, so return it
return cachedJSON;
}
}
public static void writeJSONToCache(String JSONData, Context context, String fileName) {
try
{
File file = context.getFileStreamPath(fileName);
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream writer = context.openFileOutput(file.getName(), Context.MODE_PRIVATE);
writer.write(JSONData.getBytes());
writer.flush();
writer.close();
} catch (FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}
}
protected static String readJSONFromCache(Context context, String fileName) {
String ret = "";
try {
InputStream inputStream = context.openFileInput(fileName);
if ( inputStream != null ) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String receiveString = "";
StringBuilder stringBuilder = new StringBuilder();
while ( (receiveString = bufferedReader.readLine()) != null ) {
stringBuilder.append(receiveString);
}
inputStream.close();
ret = stringBuilder.toString();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
return ret;
}
/*
* Parses the JSON data contained in {@object}, then clears and updates {@hourlyDataList}.
*
* @param object The JSONObject containing the weather data to be parsed.
* @param hourlyDataList The ArrayList of HourlyForecastData objects that will be updated with the parsed data.
*/
public static void parseHourlyData(JSONObject object, ArrayList<HourlyForecastData> hourlyDataList) throws JSONException {
// Parse the hourly forecast data
hourlyDataList.clear();
JSONArray jsonHourlyData = (JSONArray) object.getJSONObject("hourly").getJSONArray("data");
for (int i=0; i<jsonHourlyData.length() && i<13; i++) {
JSONObject jObject = (JSONObject) jsonHourlyData.getJSONObject(i);
double temp = Double.parseDouble(jObject.get("temperature")+"");
long timeStamp = Long.parseLong((String) jObject.get("time").toString());
Date date = new Date(timeStamp*1000L);
SimpleDateFormat sdf = new SimpleDateFormat("ha", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("GMT-5"));
String time = sdf.format(date);
String summary = (String) jObject.get("summary").toString();
String iconTitle = (String) jObject.get("icon").toString();
hourlyDataList.add(new HourlyForecastData(iconTitle, time, temp, summary));
}
}
/*
* Send a GET request to {@endpoint}
*
* @param endpoint The endpoint to send the GET request to.
*/
private static String sendGetRequest(String endpoint) {
String result = null;
if (endpoint.startsWith("http://") || endpoint.startsWith("https://"))
{
// Send a GET request
try
{
// Send data
URL url = new URL(endpoint);
URLConnection conn = url.openConnection();
// Get the response
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = rd.readLine()) != null)
{
sb.append(line);
}
rd.close();
result = sb.toString();
} catch (Exception e)
{
e.printStackTrace();
return null;
}
}
return result;
}
public static boolean isCachedDataValid(String cachedJSON) {
if (cachedJSON == null) {
return false;
}
int cacheTimestamp=0;
try {
JSONObject object = (JSONObject) new JSONTokener(cachedJSON).nextValue();
cacheTimestamp = Integer.parseInt((object.getJSONObject("currently").get("time")+""));
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
Calendar currentCal = Calendar.getInstance();
Calendar cachedCal = Calendar.getInstance();
cachedCal.setTimeInMillis(cacheTimestamp*1000L);
if ((cachedCal.get(Calendar.YEAR)!=currentCal.get(Calendar.YEAR)) || (cachedCal.get(Calendar.MONTH)!=currentCal.get(Calendar.MONTH)) || cachedCal.get(Calendar.DAY_OF_MONTH)!=currentCal.get(Calendar.DAY_OF_MONTH) || (cachedCal.get(Calendar.HOUR_OF_DAY)!=currentCal.get(Calendar.HOUR_OF_DAY))) {
// Cached data is older than an hour, it is expired
return false;
}
return true;
}
}