using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApp1
{
    class Program
    {
        private static readonly string LOGIN_EMAIL = "test@reasonables.com";
        private static readonly string LOGIN_PWD = "AAAABBBB-CCCC-DDDD-EEEE-FFFFGGGGHHHH";        
        private static readonly string SENDER = "";
        private static readonly string STATUS = "Waiting";
        static void Main(string[] args)
        {
            string url = "http://service.shspread.com/Service.asmx?op=SendSMS";
            string soapAction = "http://service.reasonablespread.com/SendSMS";
            string content = "The demo from reasonable";
            String[] phoneNumbers = new string[] { "852XXXXXX" };
            var soapClient = new SoapClient(url, soapAction);
            soapClient.Arguments.Add(new SoapParameter("loginEmail", LOGIN_EMAIL));
            soapClient.Arguments.Add(new SoapParameter("APIKey", LOGIN_PWD));
            soapClient.Arguments.Add(new SoapParameter("SMSContent", content));
            soapClient.Arguments.Add(new SoapParameter("sender", SENDER));
            soapClient.Arguments.Add(new SoapParameter("schedule", DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss")));
            soapClient.Arguments.Add(new SoapParameter("campaignStatus", STATUS));
            soapClient.Arguments.Add(new SoapParameter("phoneSubscribers", phoneNumbers));
            soapClient.Arguments.Add(new SoapParameter("category", ""));
            string result = soapClient.GetResult();
            Console.WriteLine(result);
            Console.ReadKey();
        }
        public static class SoapHelper
        {
            private const string FORMAT_ENVELOPE = @"
                
                
                  
                    <{0} xmlns='{1}'>{2}{0}>
                  
                ";
            private const string FORMAT_PARAMTER = "<{0}>{1}{0}>";
            public static string MakeEnvelope(string soapAction, params SoapParameter[] soapParamters)
            {
                string nameSpace, methodName;
                GetNameSpaceAndMethodName(soapAction, out nameSpace, out methodName);
                string parameters = BuildSoapParameters(soapParamters);
                return string.Format(FORMAT_ENVELOPE, methodName, nameSpace, parameters);
            }
            private static void GetNameSpaceAndMethodName(string soapAction, out string nameSpace, out string methodName)
            {
                var index = soapAction.LastIndexOf(Path.AltDirectorySeparatorChar);
                nameSpace = soapAction.Substring(0, index + 1);
                methodName = soapAction.Substring(index + 1, soapAction.Length - index - 1);
            }
            private static string BuildSoapParameters(IEnumerable parameters)
            {
                var sb = new StringBuilder();
                foreach (var param in parameters)
                {
                    string content = GetObjectContent(param.Value);
                    sb.AppendFormat(FORMAT_PARAMTER, param.Name, content);
                }
                return sb.ToString();
            }
            private static String GetObjectContent(Object graph)
            {
                using (var memoryStream = new MemoryStream())
                {
                    var graphType = graph.GetType();
                    var xmlSerializer = new XmlSerializer(graphType);
                    xmlSerializer.Serialize(memoryStream, graph);
                    var strContent = Encoding.UTF8.GetString(memoryStream.ToArray());
                    var xmlDocument = new XmlDocument();
                    xmlDocument.LoadXml(strContent);
                    if (graphType.IsGenericType && graphType.GetGenericTypeDefinition() == typeof(List<>))
                    {
                        Type itemType = graphType.GetGenericArguments()[0];
                        string graphName = "ArrayOf" + itemType.Name;
                        XmlNode contentNode = xmlDocument.SelectSingleNode(graphName);
                        if (contentNode != null)
                            return contentNode.InnerXml;
                    }
                    if (graphType.Name == "String[]")
                    {
                        String[] contents = (String[])graph;
                        string content = "";
                        foreach (var c in contents)
                        {
                            content = content + ""+ c + "";
                        }
                        if (content != "")
                            return content;
                    }
                    else
                    {
                        XmlNode contentNode;
                        if (graphType.Name == "Byte[]")
                            contentNode = xmlDocument.SelectSingleNode("base64Binary");                        
                        else
                            contentNode = xmlDocument.SelectSingleNode(graphType.Name);
                        if (contentNode != null)
                            return contentNode.InnerXml;
                    }
                    
                    return graph.ToString();
                }
            }
        }
        public sealed class SoapParameter
        {
            public string Name { get; set; }
            public object Value { get; set; }
            public SoapParameter(string name, object value)
            {
                this.Name = name;
                this.Value = value;
            }
        }
        public sealed class SoapClient
        {
            public Uri Uri { get; set; }
            public string SoapAction { get; set; }
            public IList Arguments { get; private set; }
            public ICredentials Credentials { get; set; }
            public SoapClient(string uriString, string soapAction)
            {
                this.Uri = new Uri(uriString);
                this.SoapAction = soapAction;
                this.Arguments = new List();
                this.Credentials = CredentialCache.DefaultNetworkCredentials;
            }
            private WebResponse GetResponse()
            {
                var webRequest = (HttpWebRequest)WebRequest.Create(this.Uri);
                webRequest.Headers.Add("SOAPAction", string.Format("\"{0}\"", this.SoapAction));
                webRequest.ContentType = "text/xml;charset=utf-8";
                webRequest.Accept = "text/xml";
                webRequest.Method = "POST";
                webRequest.Credentials = this.Credentials;
                string envelope = SoapHelper.MakeEnvelope(this.SoapAction, this.Arguments.ToArray())
                            .Replace("\r", "").Replace("\n", "").Trim();
                byte[] bytes = Encoding.UTF8.GetBytes(envelope);
                Stream requestStream = webRequest.GetRequestStream();
                requestStream.Write(bytes, 0, bytes.Length);
                requestStream.Close();
                System.Net.WebResponse webResponse = null;
                try
                {
                    webResponse = webRequest.GetResponse();
                }
                catch (WebException ex)
                {
                    Console.WriteLine("Exception: " + new StreamReader(ex.Response.GetResponseStream()).ReadToEnd());
                }
                return webResponse;
            }
            public string GetResult()
            {
                var webResponse = this.GetResponse();
                if (webResponse == null)
                    return "null";
                Stream responseStream = webResponse.GetResponseStream();
                StreamReader reader = new StreamReader(responseStream);
                return reader.ReadToEnd();
            }
        }
    }
}