using System;
using System.Windows.Forms;
using System.IO;
using System.Net.Sockets;
using ComponentPro.Net;

namespace ProxySample
{
    public partial class Sample : Form
    {
        private readonly SettingInfo _settings;

        public Sample()
        {
            InitializeComponent();

            // Set timeout values to 15s.
            proxyClient.Timeout = 15000; // 15 secs

            // Load settings from the Registry.
            _settings = SettingInfo.LoadConfig();
            txtUrl.Text = _settings.Url;

            // Get proxy settings.
            txtProxyHost.Text = _settings.ProxyServer;
            txtProxyPort.Text = _settings.ProxyPort.ToString();
            cbxType.SelectedIndex = (int)_settings.ProxyType;

            // Authentication info.
            txtUserName.Text = _settings.ProxyUser;
            txtPassword.Text = _settings.ProxyPassword;
            txtDomain.Text = _settings.ProxyDomain;
            cbxMethod.SelectedIndex = (int)_settings.ProxyMethod;
        }

        /// <summary>
        /// Handles the form's Closed event.
        /// </summary>
        /// <param name="e">The event arguments.</param>
        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);

            // Update settings.
            _settings.ProxyServer = txtProxyHost.Text;
            try
            {
                _settings.ProxyPort = int.Parse(txtProxyPort.Text);
            }
            catch
            {
                _settings.ProxyPort = 1080;
            }
            _settings.ProxyType = (ProxyType)cbxType.SelectedIndex;
            _settings.ProxyUser = txtUserName.Text;
            _settings.ProxyPassword = txtPassword.Text;
            _settings.ProxyDomain = txtDomain.Text;
            _settings.ProxyMethod = (ProxyHttpConnectAuthMethod)cbxMethod.SelectedIndex;
            
            _settings.Url = txtUrl.Text;

            // And save to the Registry.
            _settings.SaveConfig();
        }

        /// <summary>
        /// Enables/disables controls.
        /// </summary>
        /// <param name="enable">Indicates whether to enable or disable the dialog.</param>
        private void EnableDialog(bool enable)
        {
            btnGet.Enabled = enable;
            grbSettings.Enabled = enable;
            grbHost.Enabled = enable;
            Util.EnableCloseButton(this, enable);
        }

        private Uri uri;
        private DateTime _startTime;

        /// <summary>
        /// Handles the Get button's Click event.
        /// </summary>
        /// <param name="sender">The button object.</param>
        /// <param name="e">The event arguments.</param>
        private void btnGet_Click(object sender, EventArgs e)
        {
            if (txtUrl.Text.Length == 0)
            {
                MessageBox.Show("Host Name is required", "Error");
                return;
            }
            
            int proxyPort = 0;
            try
            {
                // Parse the proxy port number.
                proxyPort = int.Parse(txtProxyPort.Text);
            }
            catch (Exception exc)
            {
                MessageBox.Show("Invalid proxy port number: " + exc.Message, "Error");
                return;
            }

            // Disable dialog.
            EnableDialog(false);

            proxyClient.ProxyHost = txtProxyHost.Text;
            proxyClient.ProxyPort = proxyPort;
            proxyClient.ProxyType = (ProxyType)cbxType.SelectedIndex;
            proxyClient.UserName = txtUserName.Text;
            proxyClient.Password = txtPassword.Text;
            proxyClient.Domain = txtDomain.Text;
            proxyClient.AuthenticationMethod = (ProxyHttpConnectAuthMethod)cbxMethod.SelectedIndex;
            
            try
            {
                uri = new Uri(txtUrl.Text);
                lblTime.Text = "Downloading...";

                _startTime = DateTime.Now;
                proxyClient.Connect(uri.Host, uri.Port);
                
                if (proxyClient.Connected)
                {
                    string requestMessage =
                    "GET " + uri.AbsolutePath + " HTTP/1.1\r\n" +
                    "Host: " + uri.Host + "\r\n" +
                    "Connection: close\r\n" +
                    "\r\n";

                    NetworkStream nsr = proxyClient.GetStream();
                    StreamWriter streamWriter = new StreamWriter(nsr);
                    streamWriter.Write(requestMessage);
                    streamWriter.Flush();

                    StreamReader streamReader = new StreamReader(nsr);
                    txtContent.Text = streamReader.ReadToEnd();

                    proxyClient.Disconnect();

                    TimeSpan ts = DateTime.Now - _startTime;
                    lblTime.Text = string.Format("Downloaded in {0} seconds", ts.TotalMilliseconds / 1000.0f);

                    EnableDialog(true);
                }
            }
            catch (Exception exc)
            {
                EnableDialog(true);
                Util.ShowError(exc);
                lblTime.Text = "Ready";
                proxyClient.Disconnect();
            }
        }

        /// <summary>
        /// Handles the combo box proxy type's SelectedIndexChanged event.
        /// </summary>
        /// <param name="sender">The combo box.</param>
        /// <param name="e">The event arguments.</param>
        private void cbx_SelectedIndexChanged(object sender, EventArgs e)
        {
            bool enable = cbxType.SelectedIndex > 0;

            cbxMethod.Enabled = cbxType.SelectedIndex == (int)ProxyType.HttpConnect; // Authentication method is available for HTTP Connect only.
            txtDomain.Enabled = cbxMethod.Enabled && cbxMethod.SelectedIndex == (int)ProxyHttpConnectAuthMethod.Ntlm; // Domain is available for NTLM authentication method only.
            txtUserName.Enabled = enable/* && cbxType.SelectedIndex != (int)ProxyType.SendToProxy*/; // User name and password are ignored with SendToProxy proxy type.
            txtPassword.Enabled = enable/* && cbxType.SelectedIndex != (int)ProxyType.SendToProxy*/;
            txtProxyHost.Enabled = enable; // Proxy host and port are not available in NoProxy type.
            txtProxyPort.Enabled = enable;
        }
    }
}