using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.Xml;
using System.IO;
using System.Net;
using System.Configuration;
using System.Diagnostics;

namespace XmlRpcProxy
{
    public abstract class ServiceProxy : IService
    {
        private string _url;

        public string Url
        {
            get { return _url; }
            set { _url = value; }
        }

        private string _methodPrefix;

        protected string MethodPrefix
        {
            get { return _methodPrefix; }
            set { _methodPrefix = value; }
        }

        private ICredentials _credentials;

        public ICredentials Credentials
        {
            get { return _credentials; }
            set { _credentials = value; }
        }

        private IWebProxy _proxy;

        public IWebProxy Proxy
        {
            get { return _proxy; }
            set { _proxy = value; }
        }

        public object Invoke(string methodName, object[] args)
        {
            methodName = string.Format("{0}.{1}", _methodPrefix, methodName);
            MethodCall methodCall = new MethodCall(methodName, args);

            XmlSerializer serializer = new XmlSerializer(typeof(MethodCall));

            string url = ConfigurationManager.AppSettings["BaseUrl"];
            if (url == null)
            {
                url = this.Url;
            }

            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
            req.Method = "POST";
            req.AllowAutoRedirect = false;
            req.ContentType = "text/xml";
            req.Credentials = _credentials;
            req.Proxy = _proxy;

            using (Stream reqStream = req.GetRequestStream())
            {
                serializer.Serialize(reqStream, methodCall);
            }

            HttpWebResponse res = (HttpWebResponse)req.GetResponse();
            MethodResponse methodResponse = null;
            XmlSerializer deserializer = new XmlSerializer(typeof(MethodResponse));
            using (Stream resStream = res.GetResponseStream())
            {
                methodResponse = (MethodResponse)deserializer.Deserialize(resStream);
            }
            
            if (methodResponse.Fault != null)
            {
                IDictionary<string, object> faultResult = (IDictionary<string, object>)methodResponse.Fault.Value.Value;
                throw new FaultException((int)faultResult["faultCode"], (string)faultResult["faultString"]);
            }

            ValueContent result = methodResponse.ParamArray[0].Value;

            return result.Value;
        }
    }
}
