using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel.Syndication;
using System.Web.DomainServices;
using System.Web.Ria;
using System.Xml;
using log4net;
using EarthquakeLocator.Web.Model;
namespace EarthquakeLocator.Web.Services
{
/// <summary>
/// Provides earthquake data to client applications.
/// </summary>
[EnableClientAccess()]
public class EarthquakeService : DomainService
{
private static readonly ILog log = LogManager.GetLogger(typeof(EarthquakeService));
// USGS Data Feeds: http://earthquake.usgs.gov/earthquakes/catalogs/
private const string FeedForPreviousDay =
"http://earthquake.usgs.gov/earthquakes/catalogs/1day-M2.5.xml";
private const string FeedForPreviousWeek =
"http://earthquake.usgs.gov/earthquakes/catalogs/7day-M2.5.xml";
/// <summary>
/// Gets the earthquake data for the previous week.
/// </summary>
/// <returns>A queryable collection of <see cref="Earthquake"/> objects.</returns>
public IQueryable<Earthquake> GetEarthquakes()
{
var feed = GetFeed(FeedForPreviousWeek);
var list = new List<Earthquake>();
if ( feed != null )
{
foreach ( var entry in feed.Items )
{
var quake = CreateEarthquake(entry);
if ( quake != null )
{
list.Add(quake);
}
}
}
return list.AsQueryable();
}
/// <summary>
/// Creates an <see cref="Earthquake"/> object for each entry in the Atom feed.
/// </summary>
/// <param name="entry">The Atom entry.</param>
/// <returns></returns>
private Earthquake CreateEarthquake(SyndicationItem entry)
{
Earthquake quake = null;
string title = entry.Title.Text;
string summary = entry.Summary.Text;
string point = GetElementValue<String>(entry, "point");
string depth = GetElementValue<String>(entry, "elev");
string utcTime = null;
string localTime = null;
string depthDesc = null;
double? magnitude = null;
double? latitude = null;
double? longitude = null;
double? depthKm = null;
if ( !String.IsNullOrEmpty(title) && title.StartsWith("M") )
{
title = title.Substring(2, title.IndexOf(',')-3).Trim();
magnitude = TryParse(title);
}
if ( !String.IsNullOrEmpty(point) )
{
var values = point.Split(' ');
if ( values.Length == 2 )
{
latitude = TryParse(values[0]);
longitude = TryParse(values[1]);
}
}
if ( !String.IsNullOrEmpty(depth) )
{
depthKm = TryParse(depth);
if ( depthKm != null )
{
depthKm = Math.Round((-1 * depthKm.Value) / 100, 2);
}
}
if ( !String.IsNullOrEmpty(summary) )
{
summary = summary.Replace("</p>", "");
var values = summary.Split(
new string[] { "<p>" },
StringSplitOptions.RemoveEmptyEntries);
if ( values.Length == 3 )
{
var times = values[1].Split(
new string[] { "<br>" },
StringSplitOptions.RemoveEmptyEntries);
if ( times.Length > 0 )
{
utcTime = times[0];
}
if ( times.Length > 1 )
{
localTime = times[1];
}
depthDesc = values[2];
depthDesc = "Depth: " + depthDesc.Substring(depthDesc.IndexOf(":") + 2);
}
}
if ( latitude != null && longitude != null )
{
quake = new Earthquake()
{
Id = entry.Id,
Title = entry.Title.Text,
Summary = entry.Summary.Text,
Date = entry.LastUpdatedTime.DateTime,
Url = entry.Links.Select(l => Path.Combine(l.BaseUri.OriginalString,
l.Uri.OriginalString)).FirstOrDefault(),
Age = entry.Categories.Where(c => c.Label == "Age")
.Select(c => c.Name).FirstOrDefault(),
Magnitude = magnitude.GetValueOrDefault(),
Latitude = latitude.GetValueOrDefault(),
Longitude = longitude.GetValueOrDefault(),
DepthInKm = depthKm.GetValueOrDefault(),
DepthDesc = depthDesc,
UtcTime = utcTime,
LocalTime = localTime
};
}
return quake;
}
private T GetElementValue<T>(SyndicationItem entry, String name)
{
var el = entry.ElementExtensions.Where(e => e.OuterName == name).FirstOrDefault();
T value = default(T);
if ( el != null )
{
value = el.GetObject<T>();
}
return value;
}
private double? TryParse(String value)
{
double d;
if ( Double.TryParse(value, out d) )
{
return d;
}
return null;
}
/// <summary>
/// Gets the feed at the specified URL.
/// </summary>
/// <param name="url">The URL.</param>
/// <returns>A <see cref="SyndicationFeed"/> object.</returns>
public static SyndicationFeed GetFeed(String url)
{
SyndicationFeed feed = null;
try
{
log.Debug("Loading RSS feed: " + url);
using ( var reader = XmlReader.Create(url) )
{
feed = SyndicationFeed.Load(reader);
}
}
catch ( Exception ex )
{
log.Error("Error occurred while loading RSS feed: " + url, ex);
}
return feed;
}
}
}