using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using Renci.SshNet.Common;
using Renci.SshNet.Messages;
using Renci.SshNet.Messages.Transport;
using System.Globalization;
namespace Renci.SshNet.Security
{
    /// 
    /// Represents "diffie-hellman-group1-sha1" algorithm implementation.
    /// 
    public class KeyExchangeDiffieHellmanGroup1Sha1 : KeyExchangeDiffieHellman
    {
        /// 
        /// Gets algorithm name.
        /// 
        public override string Name
        {
            get { return "diffie-hellman-group1-sha1"; }
        }
        /// 
        /// Calculates key exchange hash value.
        /// 
        /// 
        /// Key exchange hash.
        /// 
        protected override byte[] CalculateHash()
        {
            var hashData = new _ExchangeHashData
            {
                ClientVersion = this.Session.ClientVersion,
                ServerVersion = this.Session.ServerVersion,
                ClientPayload = this._clientPayload,
                ServerPayload = this._serverPayload,
                HostKey = this._hostKey,
                ClientExchangeValue = this._clientExchangeValue,
                ServerExchangeValue = this._serverExchangeValue,
                SharedKey = this.SharedKey,
            }.GetBytes();
            return this.Hash(hashData);
        }
        /// 
        /// Starts key exchange algorithm
        /// 
        /// The session.
        /// Key exchange init message.
        public override void Start(Session session, KeyExchangeInitMessage message)
        {
            base.Start(session, message);
            this.Session.RegisterMessage("SSH_MSG_KEXDH_REPLY");
            this.Session.MessageReceived += Session_MessageReceived;
            BigInteger prime;
            var secondOkleyGroup = @"00FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF";
            BigInteger.TryParse(secondOkleyGroup, System.Globalization.NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out prime);
            this._prime = prime;
            this._group = new BigInteger(new byte[] { 2 });
            this.PopulateClientExchangeValue();
            this.SendMessage(new KeyExchangeDhInitMessage(this._clientExchangeValue));
        }
        /// 
        /// Finishes key exchange algorithm.
        /// 
        public override void Finish()
        {
            base.Finish();
            this.Session.MessageReceived -= Session_MessageReceived;
        }
        private void Session_MessageReceived(object sender, MessageEventArgs e)
        {
            var message = e.Message as KeyExchangeDhReplyMessage;
            if (message != null)
            {
                //  Unregister message once received
                this.Session.UnRegisterMessage("SSH_MSG_KEXDH_REPLY");
                this.HandleServerDhReply(message.HostKey, message.F, message.Signature);
                //  When SSH_MSG_KEXDH_REPLY received key exchange is completed
                this.Finish();
            }
        }
        private class _ExchangeHashData : SshData
        {
            public string ServerVersion { get; set; }
            public string ClientVersion { get; set; }
            public byte[] ClientPayload { get; set; }
            public byte[] ServerPayload { get; set; }
            public byte[] HostKey { get; set; }
            public BigInteger ClientExchangeValue { get; set; }
            public BigInteger ServerExchangeValue { get; set; }
            public BigInteger SharedKey { get; set; }
            protected override void LoadData()
            {
                throw new System.NotImplementedException();
            }
            protected override void SaveData()
            {
                this.Write(this.ClientVersion);
                this.Write(this.ServerVersion);
                this.WriteBinaryString(this.ClientPayload);
                this.WriteBinaryString(this.ServerPayload);
                this.WriteBinaryString(this.HostKey);
                this.Write(this.ClientExchangeValue);
                this.Write(this.ServerExchangeValue);
                this.Write(this.SharedKey);
            }
        }
    }
}