/// <summary>
        /// this function create a negotiate packet.
        /// client send the negotiate packet to server to indicate the supported capabilities.
        /// in connection-oriented mode, this is the first packet that client send to server.
        /// </summary>
        /// <param name="negotiateFlags">this flags indicates the capabilities that client supports.</param>
        /// <param name="version">
        /// This structure is used for debugging purposes only. In normal (non-debugging) protocol messages, it is
        /// ignored and does not affect the NTLM message processing.
        /// </param>
        /// <param name="domainName">
        /// DomainName contains the name of the client authentication domain that MUST be encoded using the OEM
        /// character set. This param can not be null.
        /// </param>
        /// <param name="workstationName">
        /// WorkstationName contains the name of the client machine that MUST be encoded using the OEM character
        /// set. Otherwise, this data is not present. This param can not be null.
        /// </param>
        /// <returns>the negotiate packet</returns>
        /// <exception cref="ArgumentNullException">domainName must not be null</exception>
        /// <exception cref="ArgumentNullException">workstationName must not be null</exception>
        /// <exception cref="ArgumentException">
        /// when version is required, the domainName and workstationName must be string.Empty
        /// </exception>
        public NlmpNegotiatePacket CreateNegotiatePacket(
            NegotiateTypes negotiateFlags,
            VERSION version,
            string domainName,
            string workstationName
            )
        {
            #region Parameter validation

            if (NlmpUtility.IsConnectionless(negotiateFlags))
            {
                throw new NotSupportedException("NEGOTIATE message is not supported under Connectionless mode.");
            }

            if (NlmpUtility.IsDomainNameSupplied(negotiateFlags) && (domainName == null))
            {
                throw new ArgumentNullException("domainName");
            }

            if (NlmpUtility.IsWorkstationSupplied(negotiateFlags) && (workstationName == null))
            {
                throw new ArgumentNullException("workstationName");
            }

            if (NlmpUtility.IsVersionRequired(negotiateFlags))
            {
                if (domainName.Length != 0)
                {
                    throw new ArgumentException(
                              "when version is required, the domainName should be string.Empty!", "domainName");
                }

                if (workstationName.Length != 0)
                {
                    throw new ArgumentException(
                              "when version is required, the workstationName should be string.Empty!", "workstationName");
                }
            }
            else
            {
                if (NlmpUtility.IsDomainNameSupplied(negotiateFlags) && domainName.Length == 0)
                {
                    throw new ArgumentException(
                              "when version is not required, the domainName should not be string.Empty!", "domainName");
                }

                if (NlmpUtility.IsWorkstationSupplied(negotiateFlags) && workstationName.Length == 0)
                {
                    throw new ArgumentException(
                              "when version is not required, the workstationName should not be string.Empty!",
                              "workstationName");
                }
            }

            #endregion

            NlmpNegotiatePacket packet = new NlmpNegotiatePacket();

            packet.SetNegotiateFlags(negotiateFlags);

            if (NlmpUtility.IsVersionRequired(negotiateFlags))
            {
                packet.SetVersion(version);
            }

            if (NlmpUtility.IsDomainNameSupplied(negotiateFlags))
            {
                packet.SetDomainName(domainName);
            }

            if (NlmpUtility.IsWorkstationSupplied(negotiateFlags))
            {
                packet.SetWorkstationName(workstationName);
            }

            return(packet);
        }