using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;
using System.Web;
using System.Security.Cryptography;
using System.IO;
using System.Diagnostics;

namespace Chattr
{
    partial class TwitterOAuth
    {
        static private String Authorization = "Authorization";
        static private String Host = "Host";
        static private String realm = "realm";
        static private String oauth_signature = "oauth_signature";

        static private String REQUEST_TOKEN_PATH = "http://twitter.com/oauth/request_token";
        static private String AUTHORIZE_PATH = "http://twitter.com/oauth/authorize";
        static private String ACCESS_TOKEN_PATH = "http://twitter.com/oauth/access_token";
        static public String AUTHORIZE_URL = "https://twitter.com/oauth/authorize";

        static public String URL_ENCODE = "[ !@#\\$\\^&\\*\\(\\)`+=\\[\\]\\{\\}\\|;:'\"<>\\?,/]";
        static public String URL_ENCODE_PAR = "[\\% !@#\\$\\^&\\*\\(\\)`+=\\[\\]\\{\\}\\|;:'\"<>\\?,/]";

        static private String _request_token = "";
        static private String _request_token_secret = "";
        static private String _access_token = "";
        static private String _access_token_secret = "";

        static private String HMAC_sha1(String value, String secret)
        {
            Byte[] key = System.Text.Encoding.ASCII.GetBytes(secret);
            HMACSHA1 hmac_sha1 = new HMACSHA1(key);
            Byte[] hash = hmac_sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(value));
            return Convert.ToBase64String(hash);
        }

        static private Dictionary<String, String> MakeHeader(String method, String url, Dictionary<String, String> header, String body, String tokenSecret)
        {
            String[] urls = url.Split(new String[] { "?" }, StringSplitOptions.None);
            String auth = (String)header[Authorization];
            Dictionary<String, String> headers = new Dictionary<String, String>();
            foreach (String e in auth.Split(new String[] { "," }, StringSplitOptions.None))
            {
                Match a = Regex.Match(e, "(\\S+)=\"(.*)\"");
                if (a.Groups.Count >= 2)
                {
                    headers[a.Groups[1].Value] = a.Groups[2].Value;
                }
            }
            Dictionary<String, String> bodys = new Dictionary<String, String>();
            foreach (String e in body.Split(new String[] { "&" }, StringSplitOptions.None))
            {
                Match a = Regex.Match(e, "(\\S+)=(.*)");
                if (a.Groups.Count >= 2)
                {
                    String value = a.Groups[2].Value.Replace("+", " ");
                    bodys[a.Groups[1].Value] = TwitterAPI.UrlEncode(value, URL_ENCODE);
                }
            }
            if (urls.Length > 1)
            {
                String[] url1 = urls[1].Split(new String[] { "&" }, StringSplitOptions.None);
                foreach (String e in url1)
                {
                    Match a = Regex.Match(e, "(\\S+)=(.*)");
                    if (a.Groups.Count >= 2)
                    {
                        String value = a.Groups[2].Value.Replace("+", " ");
                        bodys[a.Groups[1].Value] = TwitterAPI.UrlEncode(value, URL_ENCODE);
                    }
                }
            }
            ArrayList keys = new ArrayList();
            foreach (String k in headers.Keys)
            {
                int i = 0;
                while (i < keys.Count)
                {
                    if (String.Compare(keys[i].ToString(), k, StringComparison.Ordinal) > 0)
                    {
                        break;
                    }
                    i++;
                }
                if (i < keys.Count)
                {
                    keys.Insert(i, k);
                }
                else
                {
                    keys.Add(k);
                }
            }
            if (bodys.Count > 0)
            {
                foreach (String k in bodys.Keys)
                {
                    int i = 0;
                    while (i < keys.Count)
                    {
                        if (String.Compare(keys[i].ToString(), k, StringComparison.Ordinal) > 0)
                        {
                            break;
                        }
                        i++;
                    }
                    if (i < keys.Count)
                    {
                        keys.Insert(i, k);
                    }
                    else
                    {
                        keys.Add(k);
                    }
                }
            }
            String oauth = "";
            String amp = "";
            foreach (String k in keys)
            {
                if ((k != realm) && (k != oauth_signature))
                {
                    String v;
                    if (!headers.TryGetValue(k, out v))
                    {
                        v = bodys[k];
                    }
                    oauth += amp + k + "=" + v;
                    amp = "&";
                }
            }
            String param = method.ToUpper() + "&" + TwitterAPI.UrlEncode(urls[0], URL_ENCODE_PAR) + "&" + TwitterAPI.UrlEncode(oauth, URL_ENCODE_PAR);
            //Debug.WriteLine(param);
            String sha1Key = CONSUMER_SECRET + "&";
            if (tokenSecret != "")
            {
                sha1Key = sha1Key + tokenSecret;
            }
            String sha1 = HMAC_sha1(param, sha1Key);
            headers[oauth_signature] = TwitterAPI.UrlEncode(sha1, "[+/=]");
            oauth = "OAuth realm=\"" + headers[realm] + "\"";
            //Dictionary<String, String>.KeyCollection hKeys = headers.Keys;
            foreach (String k in headers.Keys)
            {
                if (k != "realm")
                {
                    oauth = oauth + ", " + k + "=\"" + headers[k] + "\"";
                }
            }
            header[Host] = HostOfURL(url);
            header[Authorization] = oauth;
            return header;
        }

        static private String HostOfURL(String url)
        {
            Match a = Regex.Match(url, "(?:http|https):\\/\\/(.*?)\\/");
            return a.Groups[1].Value;
        }

        static private String RealmOfURL(String url)
        {
            Match a = Regex.Match(url, "((?:http|https):\\/\\/.*?/)");
            return a.Groups[1].Value;
        }

        static private long Since1970(DateTime date)
        {
            return (long)((date - DateTime.Parse("1970/1/1 00:00:00")).TotalSeconds);
        }

        static private long Timestamp(DateTime date)
        {
            return Since1970(date);
        }

        static private String Nonce(DateTime date)
        {
            return String.Format("{0,8:x}", (int)((Since1970(date) * 1000) + date.Millisecond));
        }

        static public String authorize()
        {
            String oauth_token = request_token();
            if (oauth_token == "")
            {
                return "";
            }
            return AUTHORIZE_PATH + "?oauth_token=" + oauth_token + "&perms=delete";
        }

        static public String request_token()
        {
            DateTime date = DateTime.UtcNow;
            Dictionary<String, String> header = new Dictionary<string,string>();
            header[Host] = HostOfURL(REQUEST_TOKEN_PATH);
            header[Authorization] = "OAuth realm=\"" + RealmOfURL(REQUEST_TOKEN_PATH) + "\", ";
            header[Authorization] += "oauth_timestamp=\"" + Timestamp(date) + "\", ";
            header[Authorization] += "oauth_version=\"1.0\", ";
            header[Authorization] += "oauth_consumer_key=\"" + CONSUMER_KEY + "\", ";
            header[Authorization] += "oauth_signature=\"@\", ";
            header[Authorization] += "oauth_nonce=\"" + Nonce(date) + "\", ";
            header[Authorization] += "oauth_signature_method=\"HMAC-SHA1\"";
            header = MakeHeader("POST", REQUEST_TOKEN_PATH, header, "", "");
            //Debug.WriteLine(header[Authorization]);
            HttpWebResponse res = TwitterAPI.PostWithAuthorization(REQUEST_TOKEN_PATH, header[Authorization], "");
            if (res == null)
            {
                return "";
            }
            _request_token = "";
            _request_token_secret = "";
            Stream str = res.GetResponseStream();
            StreamReader sr = new StreamReader(str, Encoding.UTF8);
            Dictionary<String, String> h = new Dictionary<String, String>();
            String r = sr.ReadToEnd();
            //Debug.WriteLine(r);
            sr.Close();
            foreach (String s in r.Split(new String[] { "&" }, StringSplitOptions.None))
            {
                String[] a = s.Split(new String[] { "=" }, StringSplitOptions.None);
                if (a[0] == "oauth_token")
                {
                    _request_token = a[1];
                }
                if (a[0] == "oauth_token_secret")
                {
                    _request_token_secret = a[1];
                }
            }
            if ((_request_token == "") || (_request_token_secret == ""))
            {
                return "";
            }
            //Debug.WriteLine(_request_token);
            return _request_token;
        }

        static public String access_token(String pin)
        {
            DateTime date = DateTime.UtcNow;
            Dictionary<String, String> header = new Dictionary<string,string>();
            header[Host] = HostOfURL(REQUEST_TOKEN_PATH);
            header[Authorization] = "OAuth realm=\"" + RealmOfURL(REQUEST_TOKEN_PATH) + "\", ";
            header[Authorization] += "oauth_timestamp=\"" + Timestamp(date) + "\", ";
            header[Authorization] += "oauth_version=\"1.0\", ";
            header[Authorization] += "oauth_consumer_key=\"" + CONSUMER_KEY + "\", ";
            header[Authorization] += "oauth_token=\"" + _request_token + "\", ";
            header[Authorization] += "oauth_signature=\"@\", ";
            header[Authorization] += "oauth_verifier=\"" + pin + "\", ";
            header[Authorization] += "oauth_nonce=\"" + Nonce(date) + "\", ";
            header[Authorization] += "oauth_signature_method=\"HMAC-SHA1\"";
            header = MakeHeader("POST", ACCESS_TOKEN_PATH, header, "", "");
            //Debug.WriteLine(header[Authorization]);
            HttpWebResponse res = TwitterAPI.PostWithAuthorization(ACCESS_TOKEN_PATH, header[Authorization], _request_token_secret);
            if (res == null)
            {
                return "";
            }
            _access_token = "";
            _access_token_secret = "";
            Stream str = res.GetResponseStream();
            StreamReader sr = new StreamReader(str, Encoding.UTF8);
            Dictionary<String, String> h = new Dictionary<String, String>();
            String r = sr.ReadToEnd();
            //Debug.WriteLine(r);
            sr.Close();
            foreach (String s in r.Split(new String[] { "&" }, StringSplitOptions.None))
            {
                String[] a = s.Split(new String[] { "=" }, StringSplitOptions.None);
                if (a[0] == "oauth_token")
                {
                    _access_token = a[1];
                }
                if (a[0] == "oauth_token_secret")
                {
                    _access_token_secret = a[1];
                }
            }
            if ((_access_token == "") || (_access_token_secret == ""))
            {
                return "";
            }
            //Debug.WriteLine(_access_token + ":" + _access_token_secret);
            return _access_token + ":" + _access_token_secret;
        }

        static public String OAuthHeader(String method, String url, String body, String access_token, String access_token_secret)
        {
            //Debug.WriteLine(body);
            DateTime date = DateTime.UtcNow;
            Dictionary<String, String> header = new Dictionary<string,string>();
            header[Host] = HostOfURL(REQUEST_TOKEN_PATH);
            header[Authorization] = "OAuth realm=\"" + RealmOfURL(url) + "\", ";
            header[Authorization] += "oauth_timestamp=\"" + Timestamp(date) + "\", ";
            header[Authorization] += "oauth_version=\"1.0\", ";
            header[Authorization] += "oauth_consumer_key=\"" + CONSUMER_KEY + "\", ";
            header[Authorization] += "oauth_signature=\"@\", ";
            header[Authorization] += "oauth_token=\"" + access_token + "\", ";
            header[Authorization] += "oauth_signature_method=\"HMAC-SHA1\", ";
            header[Authorization] += "oauth_nonce=\"" + Nonce(date) + "\"";

            header = MakeHeader(method, url, header, body, access_token_secret);
            //Debug.WriteLine(header[Authorization]);
            return header[Authorization];
        }
    }
}
