// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Runtime;
using System.ServiceModel.Channels;
using System.ServiceModel.Security;

namespace System.ServiceModel
{
    public sealed class BasicHttpMessageSecurity
    {
        internal const BasicHttpMessageCredentialType DefaultClientCredentialType = BasicHttpMessageCredentialType.UserName;

        private BasicHttpMessageCredentialType _clientCredentialType;

        public BasicHttpMessageSecurity()
        {
            _clientCredentialType = DefaultClientCredentialType;
        }

        public BasicHttpMessageCredentialType ClientCredentialType
        {
            get { return _clientCredentialType; }
            set
            {
                if (!BasicHttpMessageCredentialTypeHelper.IsDefined(value))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                }
                _clientCredentialType = value;
            }
        }

        // if any changes are made to this method, please reflect them in the corresponding TryCrete() method
        internal SecurityBindingElement CreateMessageSecurity(bool isSecureTransportMode)
        {
            SecurityBindingElement result;

            if (isSecureTransportMode)
            {
                MessageSecurityVersion version = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
                switch (_clientCredentialType)
                {
                    case BasicHttpMessageCredentialType.Certificate:
                        result = SecurityBindingElement.CreateCertificateOverTransportBindingElement(version);
                        break;
                    case BasicHttpMessageCredentialType.UserName:
                        result = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
                        result.MessageSecurityVersion = version;
                        break;
                    default:
                        Fx.Assert("Unsupported basic http message credential type");
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
                }
            }
            else
            {
                if (_clientCredentialType != BasicHttpMessageCredentialType.Certificate)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.BasicHttpMessageSecurityRequiresCertificate));
                }
                result = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10, true);
            }

            result.SecurityHeaderLayout = SecurityHeaderLayout.Lax;
            result.SetKeyDerivation(false);

            return result;
        }

        // This method reverses the CreateMessageSecurity(bool) method
        internal static bool TryCreate(SecurityBindingElement sbe, out BasicHttpMessageSecurity security, out bool isSecureTransportMode)
        {
            Fx.Assert(null != sbe, string.Empty);

            security = null;
            isSecureTransportMode = false;

            if (!sbe.IsSetKeyDerivation(false))
                return false;
            if (sbe.SecurityHeaderLayout != SecurityHeaderLayout.Lax)
                return false;
            if (sbe.MessageSecurityVersion != MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10)
                return false;

            BasicHttpMessageCredentialType credentialType;
            if (!SecurityBindingElement.IsMutualCertificateBinding(sbe, true))
            {
                isSecureTransportMode = true;
                if (SecurityBindingElement.IsCertificateOverTransportBinding(sbe))
                {
                    credentialType = BasicHttpMessageCredentialType.Certificate;
                }
                else if (SecurityBindingElement.IsUserNameOverTransportBinding(sbe))
                {
                    credentialType = BasicHttpMessageCredentialType.UserName;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                credentialType = BasicHttpMessageCredentialType.Certificate;
            }
            security = new BasicHttpMessageSecurity();
            security.ClientCredentialType = credentialType;

            return true;
        }
    }
}
