using System;
using System.Collections;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Net;
using System.IO;
using System.Drawing;
using System.Globalization;
using System.Xml;

/// <summary>
/// Summary description for OlympicsData
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
// [System.Web.Script.Services.ScriptService]
public class OlympicsData : System.Web.Services.WebService
{
    public OlympicsData()
    {
        if (!_initialized)
        {
            _initialized = true;

            _waitTicks = TimeSpan.FromMinutes(1).Ticks;

            // save the flags we have
            DirectoryInfo flagsFolder = new DirectoryInfo(Server.MapPath("Resources/flags"));
            foreach (FileInfo flagfile in flagsFolder.GetFiles())
            {
                MyFlags.Add(flagfile.Name.Replace(".png", "").Replace("-", " "));
            }

            // get latitud/longitud
            // XElement xml = RequestUrl("http://ws.geonames.org/countryInfo?", null);
            XElement xml = null;
            try
            {
                xml = XElement.Load(Server.MapPath("countries.xml"));
            }
            catch (Exception exc)
            { 
            }
            _geoCountries = from row in xml.Descendants("country")
                            select new CountryLatLong()
                            {
                                CountryName = row.Element("countryName").Value,
                                BoxEast = double.Parse(row.Element("bBoxEast").Value, CultureInfo.InvariantCulture),
                                BoxWest = double.Parse(row.Element("bBoxWest").Value, CultureInfo.InvariantCulture),
                                BoxNorth = double.Parse(row.Element("bBoxNorth").Value, CultureInfo.InvariantCulture),
                                BoxSouth = double.Parse(row.Element("bBoxSouth").Value, CultureInfo.InvariantCulture)
                            };
        }
    }

    private static bool _initialized;
    private static IEnumerable<CountryLatLong> _geoCountries;
    private static CountryInfo[] _data;

    private static List<string> MyFlags = new List<string>(); 
    private static TimeSpan _lastUpdate;
    private static long _waitTicks = 0;

    private bool RetrieveDataAgain
    {
        get
        {
            if ((_data == null) || (_lastUpdate == null) )
            {
                return true;
            }
            else
            {
                TimeSpan now = TimeSpan.FromTicks(DateTime.Now.Ticks);
                return (now.Subtract(_lastUpdate).Ticks > _waitTicks);
            }
        }
    }

    [WebMethod]
    public CountryInfo[] GetMedals()
    {
            if (RetrieveDataAgain)
            {
                try
                {
                    XElement xml;
                    if (false)
                    {
                        xml = RequestUrl("http://sports.yahoo.com/olympics/beijing/medals", CleanHtml);
                    }
                    else
                    {
                        xml = XDocument.Load(new StreamReader(Server.MapPath("/Resources/data.xml"))).Elements().First();
                    }

                    var data = from row in xml.Descendants("tr")
                            let varName = row.Elements("td").ElementAt(1).Descendants().ElementAt(0).Attribute("title").Value
                            let latlongInfo = _geoCountries.Where(new Func<CountryLatLong, bool>((cll) => { return (cll.CountryName == varName); }))
                            let cll = latlongInfo.Count() > 0 ? latlongInfo.First() : null
                            let gold = int.Parse(row.Elements("td").ElementAt(2).Value)
                            let silver = int.Parse(row.Elements("td").ElementAt(3).Value)
                            let bronze = int.Parse(row.Elements("td").ElementAt(4).Value)
                            where gold>0 || silver>0|| bronze>0
                            select new CountryInfo() 
                            {
                               CountryName = varName,
                               FlagUrl = MyFlags.Contains(varName) ? BuildImagePath(varName) : string.Empty,
                               GoldMedals = gold,
                               SilverMedals = silver,
                               BronzeMedals = bronze,
                               TotalMedals = gold + silver + bronze,
                               Latitude = cll != null ? cll.Latitude : -70,
                               Longitude = cll != null ? cll.Longitude : -70
                            };
                    _data = data.ToArray();
                    // check point
                    _lastUpdate = TimeSpan.FromTicks(DateTime.Now.Ticks);
                }
                catch (Exception exc) 
                {
                    System.Diagnostics.Debug.Write(exc.ToString());
                }
            }
            return _data;
    }

    //Replace HTML entity references so that we can load into XElement
    private static string CleanHtml(string html) 
    {
        var resHtml = html;

        int start = resHtml.IndexOf("<tbody>");
        int end = resHtml.IndexOf("</tbody>") + 8;
        resHtml = resHtml.Substring(start, end - start);
        resHtml = resHtml.Replace("<tr >", "<tr>");
        resHtml = resHtml.Replace("<tr class=\"odd\">", "<tr>");
        resHtml = resHtml.Replace("&nbsp;", "");
        resHtml = resHtml.Replace("&", "&amp;");
        resHtml = resHtml.Replace("/olympics/beijing/", "");
        resHtml = resHtml.Replace("\n", "");

        return resHtml;
    }

    private static XElement RequestUrl(string url, Func<string, string> prepareResponse)
    {
        XElement xml = null;
        string html = string.Empty;

        // prepare request
        WebRequest req = HttpWebRequest.Create(url);
        req.UseDefaultCredentials = true;

        // process response
        WebResponse response = req.GetResponse();
        using (StreamReader reader = new StreamReader(response.GetResponseStream()))
        {
            html = reader.ReadToEnd();
            reader.Close();
        }

        // prepare html if necessary
        if (prepareResponse != null)
        {
            html = prepareResponse(html);
        }

        // load into XElement
        using (var strReader = new StringReader(html))
        {
            xml = XElement.Load(strReader);
            strReader.Close();
        };

        return xml;
    }

    private string BuildImagePath(string countryName)
    {
        string baseUrl = Context.Request.Url.AbsoluteUri.Substring(0, Context.Request.Url.AbsoluteUri.IndexOf("WSData.asmx"));

        return string.Format("{0}Resources/flags/{1}.png", baseUrl, countryName.Replace(" ", "-"));
    }
}