using System.Collections.Generic;
using Renci.SshNet.Common;
namespace Renci.SshNet.Security
{
    /// 
    /// Implements key support for host algorithm.
    /// 
    public class KeyHostAlgorithm : HostAlgorithm
    {
        /// 
        /// Gets the key.
        /// 
        public Key Key { get; private set; }
        /// 
        /// Gets the public key data.
        /// 
        public override byte[] Data
        {
            get
            {
                return new SshKeyData(this.Name, this.Key.Public).GetBytes();
            }
        }
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// Host key name.
        /// Host key.
        public KeyHostAlgorithm(string name, Key key)
            : base(name)
        {
            this.Key = key;
        }
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// Host key name.
        /// Host key.
        /// Host key encoded data.
        public KeyHostAlgorithm(string name, Key key, byte[] data)
            : base(name)
        {
            this.Key = key;
            var sshKey = new SshKeyData();
            sshKey.Load(data);
            this.Key.Public = sshKey.Keys;
        }
        /// 
        /// Signs the specified data.
        /// 
        /// The data.
        /// 
        /// Signed data.
        /// 
        public override byte[] Sign(byte[] data)
        {
            return new SignatureKeyData(this.Name, this.Key.Sign(data)).GetBytes();
        }
        /// 
        /// Verifies the signature.
        /// 
        /// The data.
        /// The signature.
        /// 
        ///   True is signature was successfully verifies; otherwise false.
        /// 
        public override bool VerifySignature(byte[] data, byte[] signature)
        {
            var signatureData = new SignatureKeyData();
            signatureData.Load(signature);
            return this.Key.VerifySignature(data, signatureData.Signature);
        }
        private class SshKeyData : SshData
        {
            public BigInteger[] Keys { get; private set; }
            private string Name { get; set; }
            public SshKeyData()
            {
            }
            public SshKeyData(string name, params BigInteger[] keys)
            {
                this.Name = name;
                this.Keys = keys;
            }
            protected override void LoadData()
            {
                this.Name = this.ReadString();
                var keys = new List();
                while (!this.IsEndOfData)
                {
                    keys.Add(this.ReadBigInt());
                }
                this.Keys = keys.ToArray();
            }
            protected override void SaveData()
            {
                this.Write(this.Name);
                foreach (var key in this.Keys)
                {
                    this.Write(key);
                }
            }
        }
        private class SignatureKeyData : SshData
        {
            /// 
            /// Gets or sets the name of the algorithm.
            /// 
            /// 
            /// The name of the algorithm.
            /// 
            private string AlgorithmName { get; set; }
            /// 
            /// Gets or sets the signature.
            /// 
            /// 
            /// The signature.
            /// 
            public byte[] Signature { get; private set; }
            public SignatureKeyData()
            {
            }
            public SignatureKeyData(string name, byte[] signature)
            {
                this.AlgorithmName = name;
                this.Signature = signature;
            }
            /// 
            /// Called when type specific data need to be loaded.
            /// 
            protected override void LoadData()
            {
                this.AlgorithmName = this.ReadString();
                this.Signature = this.ReadBinaryString();
            }
            /// 
            /// Called when type specific data need to be saved.
            /// 
            protected override void SaveData()
            {
                this.Write(this.AlgorithmName);
                this.WriteBinaryString(this.Signature);
            }
        }
    }
}