/// <summary> Preps a name according to the Stringprep profile defined in
        /// RFC3491.
        /// *
        /// </summary>
        /// <param name="input">the name to prep.
        /// </param>
        /// <param name="allowUnassigned">true if the name may contain unassigned
        /// code points.
        /// </param>
        /// <returns> the prepped name.
        /// @throws StringprepException If the name cannot be prepped with
        /// this profile.
        /// @throws NullPointerException If the name is null.
        ///
        /// </returns>
        public static string NamePrep(string input, bool allowUnassigned)
        {
            if (input == null)
            {
                throw new System.NullReferenceException();
            }

            StringBuilder s = new StringBuilder(input);

            if (!allowUnassigned && Contains(s, RFC3454.A1))
            {
                throw new StringPrepException(StringPrepException.CONTAINS_UNASSIGNED);
            }

            Filter(s, RFC3454.B1);
            Map(s, RFC3454.B2search, RFC3454.B2replace);

            s = new StringBuilder(NFKC.NormalizeNFKC(s.ToString()));
            // B.3 is only needed if NFKC is not used, right?
            // map(s, RFC3454.B3search, RFC3454.B3replace);

            if (Contains(s, RFC3454.C12) || Contains(s, RFC3454.C22) || Contains(s, RFC3454.C3) || Contains(s, RFC3454.C4) || Contains(s, RFC3454.C5) || Contains(s, RFC3454.C6) || Contains(s, RFC3454.C7) || Contains(s, RFC3454.C8))
            {
                // Table C.9 only contains code points > 0xFFFF which Java
                // doesn't handle
                throw new StringPrepException(StringPrepException.CONTAINS_PROHIBITED);
            }

            // Bidi handling
            bool r = Contains(s, RFC3454.D1);
            bool l = Contains(s, RFC3454.D2);

            // RFC 3454, section 6, requirement 1: already handled above (table C.8)

            // RFC 3454, section 6, requirement 2
            if (r && l)
            {
                throw new StringPrepException(StringPrepException.BIDI_BOTHRAL);
            }

            // RFC 3454, section 6, requirement 3
            if (r)
            {
                if (!Contains(s[0], RFC3454.D1) || !Contains(s[s.Length - 1], RFC3454.D1))
                {
                    throw new StringPrepException(StringPrepException.BIDI_LTRAL);
                }
            }

            return(s.ToString());
        }
        public static string SaslPrep(string input)
        {
            var s = new StringBuilder(input);

            /*
             * This profile specifies:
             *
             * -  non-ASCII space characters [StringPrep, C.1.2] that can be
             *   mapped to SPACE (U+0020), and
             *
             * -  the "commonly mapped to nothing" characters [StringPrep, B.1]
             *   that can be mapped to nothing.
             */

            Map(s, RFC3454.C12, RFC3454.C12replace);
            Filter(s, RFC3454.B1);

            // Bidi handling
            //bool r = Contains(s, RFC3454.D1);
            //bool l = Contains(s, RFC3454.D2);

            /*
             * - Non-ASCII space characters [StringPrep, C.1.2]
             * - ASCII control characters [StringPrep, C.2.1]
             * - Non-ASCII control characters [StringPrep, C.2.2]
             * - Private Use characters [StringPrep, C.3]
             * - Non-character code points [StringPrep, C.4]
             * - Surrogate code points [StringPrep, C.5]
             * - Inappropriate for plain text characters [StringPrep, C.6]
             * - Inappropriate for canonical representation characters
             *  [StringPrep, C.7]
             * - Change display properties or deprecated characters
             *  [StringPrep, C.8]
             * - Tagging characters [StringPrep, C.9]
             */

            if (Contains(s, RFC3454.C12) || Contains(s, RFC3454.C21) || Contains(s, RFC3454.C22) || Contains(s, RFC3454.C3) || Contains(s, RFC3454.C4) || Contains(s, RFC3454.C5) || Contains(s, RFC3454.C6) || Contains(s, RFC3454.C7) || Contains(s, RFC3454.C8))
            {
                // TODO add C9 table
                throw new StringPrepException(StringPrepException.CONTAINS_PROHIBITED);
            }

#if WINDOWS_PHONE || CF || SILVERLIGHT || WINRT
            return(NFKC.NormalizeNFKC(s.ToString()));
#else
            var result = s.ToString();
            return(result.Normalize(NormalizationForm.FormKC));
#endif
        }