/*
* Copyright (C) 2014 Francesco Azzola - Surviving with Android (http://www.survivingwithandroid.com)
*
* 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 com.survivingwithandroid.weather.lib.provider.yahooweather;
import android.location.Location;
import com.survivingwithandroid.weather.lib.WeatherCode;
import com.survivingwithandroid.weather.lib.WeatherConfig;
import com.survivingwithandroid.weather.lib.exception.ApiKeyRequiredException;
import com.survivingwithandroid.weather.lib.exception.WeatherLibException;
import com.survivingwithandroid.weather.lib.model.BaseWeather;
import com.survivingwithandroid.weather.lib.model.City;
import com.survivingwithandroid.weather.lib.model.CurrentWeather;
import com.survivingwithandroid.weather.lib.model.DayForecast;
import com.survivingwithandroid.weather.lib.model.HistoricalWeather;
import com.survivingwithandroid.weather.lib.model.Weather;
import com.survivingwithandroid.weather.lib.model.WeatherForecast;
import com.survivingwithandroid.weather.lib.model.WeatherHourForecast;
import com.survivingwithandroid.weather.lib.provider.IWeatherCodeProvider;
import com.survivingwithandroid.weather.lib.provider.IWeatherProvider;
import com.survivingwithandroid.weather.lib.request.Params;
import com.survivingwithandroid.weather.lib.request.WeatherRequest;
import com.survivingwithandroid.weather.lib.util.WeatherUtility;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.StringReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.UnknownFormatConversionException;
public class YahooWeatherProvider implements IWeatherProvider {
private static String YAHOO_GEO_URL = "http://where.yahooapis.com/v1";
private static String YAHOO_WEATHER_URL = "http://weather.yahooapis.com/forecastrss";
private static final String YAHOO_IMG_URL = "http://l.yimg.com/a/i/us/we/52/";
private WeatherConfig config;
private BaseWeather.WeatherUnit units = new BaseWeather.WeatherUnit();
private IWeatherCodeProvider codeProvider;
@Override
public List<City> getCityResultList(String data) throws WeatherLibException {
List<City> result = new ArrayList<City>();
try {
// String query =makeQueryCityURL(data);
//Log.d("Swa", "URL [" + query + "]");
//yahooHttpConn= (HttpURLConnection) (new URL(query)).openConnection();
//yahooHttpConn.connect();
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setInput(new StringReader(data));
int event = parser.getEventType();
City cty = null;
String tagName = null;
String currentTag = null;
// We start parsing the XML
while (event != XmlPullParser.END_DOCUMENT) {
tagName = parser.getName();
if (event == XmlPullParser.START_TAG) {
if (tagName.equals("place")) {
// place Tag Found so we create a new CityResult
cty = new City.CityBuilder().build();
// Log.d("Swa", "New City found");
}
currentTag = tagName;
// Log.d("Swa", "Tag ["+tagName+"]");
} else if (event == XmlPullParser.TEXT) {
// We found some text. let's see the tagName to know the tag related to the text
if ("woeid".equals(currentTag))
cty.setId(parser.getText());
else if ("name".equals(currentTag))
cty.setName(parser.getText());
else if ("country".equals(currentTag))
cty.setCountry(parser.getText());
// We don't want to analyze other tag at the moment
} else if (event == XmlPullParser.END_TAG) {
if ("place".equals(tagName))
result.add(cty);
}
event = parser.next();
}
} catch (Throwable t) {
//t.printStackTrace();
// Log.e("Error in getCityList", t.getMessage());
throw new WeatherLibException(t);
}
return result;
}
@Override
public WeatherHourForecast getHourForecastWeather(String data) throws WeatherLibException {
throw new UnsupportedOperationException();
}
@Override
public CurrentWeather getCurrentCondition(String data) throws WeatherLibException {
// Log.d("SwA", "Response ["+resp+"]");
//Log.d("App", "Data [" + data + "]");
CurrentWeather cWeather = new CurrentWeather();
Weather weather = new Weather();
try {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setInput(new StringReader(data));
String tagName = null;
String currentTag = null;
int event = parser.getEventType();
boolean isFirstDayForecast = true;
while (event != XmlPullParser.END_DOCUMENT) {
tagName = parser.getName();
if (event == XmlPullParser.START_TAG) {
if (tagName.equals("yweather:wind")) {
// Iss#4
weather.wind.setChill(Integer.parseInt(parser.getAttributeValue(null, "chill")));
weather.wind.setDeg(Integer.parseInt(parser.getAttributeValue(null, "direction")));
weather.wind.setSpeed(WeatherUtility.string2Float(parser.getAttributeValue(null, "speed")));
} else if (tagName.equals("yweather:atmosphere")) {
// Iss#4
weather.currentCondition.setHumidity(Integer.parseInt(parser.getAttributeValue(null, "humidity")));
weather.currentCondition.setVisibility(WeatherUtility.string2Float(parser.getAttributeValue(null, "visibility")));
weather.currentCondition.setPressure(WeatherUtility.string2Float(parser.getAttributeValue(null, "pressure")));
weather.currentCondition.setPressureTrend(Integer.parseInt(parser.getAttributeValue(null, "rising")));
} else if (tagName.equals("yweather:forecast")) {
// Log.d("SwA", "Tag [Fore]");
if (isFirstDayForecast) {
//weather.forecast.code = Integer.parseInt(parser.getAttributeValue(null, "code"));
weather.temperature.setMinTemp(Integer.parseInt(parser.getAttributeValue(null, "low")));
weather.temperature.setMaxTemp(Integer.parseInt(parser.getAttributeValue(null, "high")));
isFirstDayForecast = false;
}
} else if (tagName.equals("yweather:condition")) {
// Log.d("SwA", "Tag [Condition]");
weather.currentCondition.setWeatherId(Integer.parseInt(parser.getAttributeValue(null, "code")));
weather.currentCondition.setIcon("" + weather.currentCondition.getWeatherId());
// Convert the code
if (codeProvider != null) {
try {
weather.currentCondition.setWeatherCode(codeProvider.getWeatherCode(String.valueOf(weather.currentCondition.getWeatherId())));
}
catch(Throwable t) {
weather.currentCondition.setWeatherCode(WeatherCode.NOT_AVAILABLE);
}
}
weather.currentCondition.setCondition(parser.getAttributeValue(null, "text"));
weather.temperature.setTemp(Integer.parseInt(parser.getAttributeValue(null, "temp")));
//result.condition.date = parser.getAttributeValue(null, "date");
} else if (tagName.equals("yweather:location")) {
weather.location.setCity(parser.getAttributeValue(null, "city"));
weather.location.setRegion(parser.getAttributeValue(null, "region"));
weather.location.setCountry(parser.getAttributeValue(null, "country"));
} else if (tagName.equals("image"))
currentTag = "image";
else if (tagName.equals("url")) {
if (currentTag == null) {
// result.imageUrl = parser.getAttributeValue(null, "src");
}
} else if (tagName.equals("lastBuildDate")) {
currentTag = "update";
} else if (tagName.equals("yweather:astronomy")) {
String val = parser.getAttributeValue(null, "sunrise");
SimpleDateFormat sdf = new SimpleDateFormat("h:mm a", Locale.ENGLISH);
if (val != null) {
java.util.Date d = sdf.parse(val);
weather.location.setSunrise(d.getTime());
}
val = parser.getAttributeValue(null, "sunset");
if (val != null) {
java.util.Date d = sdf.parse(val);
weather.location.setSunset(d.getTime());
}
}
} else if (event == XmlPullParser.END_TAG) {
if ("image".equals(currentTag)) {
currentTag = null;
}
}
/*
else if (event == XmlPullParser.TEXT) {
if ("update".equals(currentTag))
//result.lastUpdate = parser.getText();
}
*/
event = parser.next();
}
} catch (Throwable t) {
t.printStackTrace();
throw new WeatherLibException(t);
}
cWeather.setUnit(units);
cWeather.weather = weather;
return cWeather;
}
@Override
public String getQueryCityURL(String cityNamePattern) throws ApiKeyRequiredException {
if (config.ApiKey == null)
throw new ApiKeyRequiredException();
// We remove spaces in cityName
cityNamePattern = cityNamePattern.replaceAll(" ", "%20");
return YAHOO_GEO_URL + "/places.q('" + cityNamePattern + "%2A');count=" + config.maxResult + "?appid=" + config.ApiKey;
}
/*
@Override
public String getQueryCurrentWeatherURL(String cityId) throws ApiKeyRequiredException {
if (config.ApiKey == null)
throw new ApiKeyRequiredException();
return YAHOO_WEATHER_URL + "?w=" + cityId + "&u=" + (WeatherUtility.isMetric(config.unitSystem) ? "c" : "f");
}
*/
/*
@Override
public String getQueryForecastWeatherURL(String cityId) throws ApiKeyRequiredException {
if (config.ApiKey == null)
throw new ApiKeyRequiredException();
return YAHOO_WEATHER_URL + "?w=" + cityId + "&u=" + (WeatherUtility.isMetric(config.unitSystem) ? "c" : "f");
}
*/
@Override
public HistoricalWeather getHistoricalWeather(String data) throws WeatherLibException {
throw new UnsupportedOperationException();
}
@Override
public String getQueryCityURLByLocation(Location location) throws ApiKeyRequiredException {
if (config.ApiKey == null)
throw new ApiKeyRequiredException();
return YAHOO_GEO_URL + "/places.q('" + location.getLatitude() + "," + location.getLongitude() + "')?appid=" + config.ApiKey;
}
@Override
public String getQueryCityURLByCoord(double lon, double lat) throws ApiKeyRequiredException {
if (config.ApiKey == null)
throw new ApiKeyRequiredException();
return YAHOO_GEO_URL + "/places.q('" + lat + "," + lon + "')?appid=" + config.ApiKey;
}
@Override
public String getQueryImageURL(String icon) throws ApiKeyRequiredException {
return YAHOO_IMG_URL + icon + ".gif";
}
/*
@Override
public String getQueryHourForecastWeatherURL(String cityId) throws ApiKeyRequiredException {
throw new UnsupportedOperationException();
}
*/
@Override
public WeatherForecast getForecastWeather(String data) throws WeatherLibException {
WeatherForecast forecast = new WeatherForecast();
try {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setInput(new StringReader(data));
String tagName = null;
String currentTag = null;
int event = parser.getEventType();
boolean isFirstDayForecast = true;
while (event != XmlPullParser.END_DOCUMENT) {
tagName = parser.getName();
if (event == XmlPullParser.START_TAG) {
if (tagName.equals("yweather:forecast")) {
DayForecast df = new DayForecast();
df.forecastTemp.max = Integer.parseInt(parser.getAttributeValue(null, "high"));
df.forecastTemp.min = Integer.parseInt(parser.getAttributeValue(null, "low")); // Bug fixing
df.weather.currentCondition.setWeatherId(Integer.parseInt(parser.getAttributeValue(null, "code")));
if (codeProvider != null) {
try {
df.weather.currentCondition.setWeatherCode(codeProvider.getWeatherCode(String.valueOf(df.weather.currentCondition.getWeatherId())));
} catch (Throwable t) {
df.weather.currentCondition.setWeatherCode(WeatherCode.NOT_AVAILABLE);
}
}
df.weather.currentCondition.setCondition(parser.getAttributeValue(null, "text"));
df.weather.currentCondition.setIcon("" + df.weather.currentCondition.getWeatherId());
forecast.addForecast(df);
} else if (tagName.equals("yweather:units")) {
// Log.d("SwA", "Tag [units]");
units.tempUnit = "°" + parser.getAttributeValue(null, "temperature");
units.pressureUnit = parser.getAttributeValue(null, "pressure");
units.distanceUnit = parser.getAttributeValue(null, "distance");
units.speedUnit = parser.getAttributeValue(null, "speed");
forecast.setUnit(units);
}
} else if (event == XmlPullParser.END_TAG) {
if ("image".equals(currentTag)) {
currentTag = null;
}
}
event = parser.next();
}
} catch (Throwable t) {
t.printStackTrace();
throw new WeatherLibException(t);
}
return forecast;
}
@Override
public void setConfig(WeatherConfig config) {
this.config = config;
units = WeatherUtility.createWeatherUnit(config.unitSystem);
}
@Override
public void setWeatherCodeProvider(IWeatherCodeProvider codeProvider) {
this.codeProvider = codeProvider;
}
/*
@Override
public String getQueryHistoricalWeatherURL(String cityId, Date startDate, Date endDate) throws ApiKeyRequiredException {
throw new UnsupportedOperationException();
}
*/
@Override
public String getQueryLayerURL(String cityId, Params params) throws ApiKeyRequiredException {
return null;
}
// New methods
@Override
public String getQueryCurrentWeatherURL(WeatherRequest request) throws ApiKeyRequiredException {
if (config.ApiKey == null)
throw new ApiKeyRequiredException();
if (request.getCityId() == null)
throw new UnsupportedOperationException("Can't use lon and lat");
return YAHOO_WEATHER_URL + "?w=" + request.getCityId()
+ "&u=" + (WeatherUtility.isMetric(config.unitSystem) ? "c" : "f")
+ "&d=1";
}
@Override
public String getQueryForecastWeatherURL(WeatherRequest request) throws ApiKeyRequiredException {
if (config.ApiKey == null)
throw new ApiKeyRequiredException();
if (request.getCityId() == null)
throw new UnsupportedOperationException("Can't use lon and lat");
return YAHOO_WEATHER_URL + "?w=" + request.getCityId()
+ "&u=" + (WeatherUtility.isMetric(config.unitSystem) ? "c" : "f")
+ "&d=" + config.numDays;
}
@Override
public String getQueryHourForecastWeatherURL(WeatherRequest request) throws ApiKeyRequiredException {
throw new UnsupportedOperationException();
}
@Override
public String getQueryHistoricalWeatherURL(WeatherRequest request, Date startDate, Date endDate) throws ApiKeyRequiredException {
throw new UnsupportedOperationException();
}
}