
// #define DEBUG

using System;
using System.Text;
using System.Web;
using System.IO;
using System.Web.Hosting;

namespace Fivestops.Oxide
{
    public class OxideWorkerRequest : HttpWorkerRequest
    {
        CausalityRequest m_crRequest;

        public OxideWorkerRequest (CausalityRequest request)
        {
            if (request == null)
            {
                throw (new ArgumentNullException ("request"));
            }

            m_crRequest = request;

            if (m_crRequest.Page == "/exit.w3wp.aspx")
            {
                Environment.Exit (1);
            }
        }

        public override void CloseConnection()
        {
            m_crRequest.Finish();
        }

        public override void EndOfRequest()
        {
            m_crRequest.Finish();
        }

        public override void FlushResponse (bool finalFlush)
        {
            // currently does nothing -- we send our data back as soon as we
            // get it
        }

        public override string GetAppPath()
        {
            return ((string) AppDomain.CurrentDomain.GetData (".hostingVirtualPath"));
        }

        public override string GetAppPathTranslated()
        {
            return ((string) AppDomain.CurrentDomain.GetData (".appPath"));
        }

        public override string GetFilePath()
        {
            string path = m_crRequest.GetVariable ("path");

            string strAppPath = this.GetAppPathTranslated().TrimEnd ('/');

            if (path.StartsWith (strAppPath))
            {
                return (path.Substring (strAppPath.Length));
            }
            else
            {
                return (m_crRequest.GetVariable ("uri"));
            }
        }

        public override string GetFilePathTranslated()
        {
            string path = m_crRequest.GetVariable ("path");

            return (path);
        }

        public override string GetHttpVerbName()
        {
            return (m_crRequest.GetVariable ("method"));
        }

        public override string GetHttpVersion()
        {
            return (m_crRequest.GetVariable ("protocol"));
        }

        public override string GetKnownRequestHeader (int index)
        {
            string strKey = HttpWorkerRequest.GetKnownRequestHeaderName (index);

            // temporarily not passing on Accept-Encoding until we are passing
            // response headers back
            if (strKey == "Accept-Encoding")
            {
                return (null);
            }

            return (GetUnknownRequestHeader (strKey));
        }

        public override string GetLocalAddress()
        {
            return ("(unknown)");
        }

        public override int GetLocalPort()
        {
            return (0);
        }

        public override string GetPathInfo()
        {
            return (m_crRequest.GetVariable ("path_info"));
        }

        // we don't preload anything in this process until it's requested
        public override byte[] GetPreloadedEntityBody()
        {
            return (new byte[0]);
        }

        public override string GetProtocol()
        {
            if (this.IsSecure() == true)
            {
                return ("HTTPS");
            }
            else
            {
                return ("HTTP");
            }
        }

        public override string GetQueryString()
        {
            return (m_crRequest.Query);
        }

        public override byte[] GetQueryStringRawBytes()
        {
            return (Encoding.UTF8.GetBytes (m_crRequest.Query));
        }

        public override string GetRawUrl()
        {
            string strUrl = this.GetUriPath();

            if (this.GetPathInfo() != null && this.GetPathInfo() != string.Empty)
            {
                strUrl += this.GetPathInfo();
            }

            if (this.GetQueryString() != null && this.GetQueryString() != string.Empty)
            {
                strUrl += "?" + this.GetQueryString();
            }

            return (strUrl);
        }

        public override string GetRemoteAddress()
        {
            return (m_crRequest.GetRemoteIP());
        }

        // we don't currently have the remote port.
        public override int GetRemotePort()
        {
            return (0);
        }

        public override string GetUriPath()
        {
            return (m_crRequest.GetVariable ("uri"));
        }

        public override string GetUnknownRequestHeader (string name)
        {
            string strValue = m_crRequest.GetRequestHeader (name.ToLower());

            return (strValue);
        }

        public override bool HeadersSent()
        {
            return (m_crRequest.HeadersSent());
        }

        // THIS IS NOT WINDOWS AWARE
        public override string MapPath (string virtualPath)
        {
            string strPath = this.GetAppPathTranslated();

            // make sure we're dealing with a path within our application
            if (virtualPath.StartsWith (this.GetAppPath()) == false)
            {
                return (null);
            }

            if (virtualPath[0] == '/')
            {
                if (virtualPath.Length == 1)
                {
                    return (strPath);
                }

                virtualPath = virtualPath.Substring (1);
            }

            return (Path.Combine (strPath, virtualPath));
        }

        public override void SendResponseFromMemory (byte[] data, int len)
        {
            if (m_crRequest.Write (data, len) == false)
            {
                // if we can't write, we'll assume the connection is dead.
                HttpContext.Current.ApplicationInstance.CompleteRequest();
            }
        }

        public override void SendResponseFromFile (IntPtr handle, long offset, long length)
        {
            throw (new NotImplementedException ());
        }

        public override void SendResponseFromFile (string filename, long offset, long length)
        {
            throw (new NotImplementedException ());
        }

        public override void SendStatus (int status, string description)
        {
            m_crRequest.SetStatus (status, description);
        }

        public override void SendKnownResponseHeader (int index, string value)
        {
            string strKey = HttpWorkerRequest.GetKnownRequestHeaderName (index);

            this.SendUnknownResponseHeader (strKey, value);
        }

        public override void SendUnknownResponseHeader (string key, string value)
        {
            m_crRequest.SetResponseHeader (key, value);
        }

        public override int ReadEntityBody (byte[] buffer, int size)
        {
            return (m_crRequest.ReadEntityBody (buffer, size));
        }

        public override void SendCalculatedContentLength (int length)
        {
            this.SendUnknownResponseHeader ("Content-Length", length.ToString());
        }

        public override bool IsEntireEntityBodyIsPreloaded()
        {
            return (m_crRequest.IsEntireEntityLoaded());
        }
    }
}
