File: Recognition\SrgsGrammar\SrgsItem.cs
Web Access
Project: src\src\runtime\src\libraries\System.Speech\src\System.Speech.csproj (System.Speech)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Speech.Internal;
using System.Speech.Internal.SrgsParser;
using System.Text;
using System.Xml;

namespace System.Speech.Recognition.SrgsGrammar
{
    [Serializable]
    [DebuggerDisplay("{DebuggerDisplayString ()}")]
    [DebuggerTypeProxy(typeof(SrgsItemDebugDisplay))]
    public class SrgsItem : SrgsElement, IItem
    {
        #region Constructors
        public SrgsItem()
        {
            _elements = new SrgsElementList();
        }
        public SrgsItem(string text)
            : this()
        {
            Helpers.ThrowIfEmptyOrNull(text, nameof(text));

            _elements.Add(new SrgsText(text));
        }
        public SrgsItem(params SrgsElement[] elements)
            : this()
        {
            ArgumentNullException.ThrowIfNull(elements);

            for (int iElement = 0; iElement < elements.Length; iElement++)
            {
                if (elements[iElement] == null)
                {
                    throw new ArgumentNullException(nameof(elements), SR.Get(SRID.ParamsEntryNullIllegal));
                }
                _elements.Add(elements[iElement]);
            }
        }
        public SrgsItem(int repeatCount)
            : this()
        {
            SetRepeat(repeatCount);
        }
        public SrgsItem(int min, int max)
            : this()
        {
            SetRepeat(min, max);
        }

        //overloads with setting the repeat.
        public SrgsItem(int min, int max, string text)
            : this(text)
        {
            SetRepeat(min, max);
        }
        public SrgsItem(int min, int max, params SrgsElement[] elements)
            : this(elements)
        {
            SetRepeat(min, max);
        }

        #endregion

        #region Public Method
        public void SetRepeat(int count)
        {
            // Negative values are not allowed
            if (count < 0 || count > 255)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }
            _minRepeat = _maxRepeat = count;
        }
        public void SetRepeat(int minRepeat, int maxRepeat)
        {
            // Negative values are not allowed
            if (minRepeat < 0 || minRepeat > 255)
            {
                throw new ArgumentOutOfRangeException(nameof(minRepeat), SR.Get(SRID.InvalidMinRepeat, minRepeat));
            }
            if (maxRepeat != int.MaxValue && (maxRepeat < 0 || maxRepeat > 255))
            {
                throw new ArgumentOutOfRangeException(nameof(maxRepeat), SR.Get(SRID.InvalidMinRepeat, maxRepeat));
            }

            // Max be greater or equal to min
            if (minRepeat > maxRepeat)
            {
                throw new ArgumentException(SR.Get(SRID.MinGreaterThanMax));
            }
            _minRepeat = minRepeat;
            _maxRepeat = maxRepeat;
        }
        public void Add(SrgsElement element)
        {
            ArgumentNullException.ThrowIfNull(element);

            Elements.Add(element);
        }

        #endregion

        #region Public Properties
        public Collection<SrgsElement> Elements
        {
            get
            {
                return _elements;
            }
        }
        // The probability that this item will be repeated.
        public float RepeatProbability
        {
            get
            {
                return _repeatProbability;
            }
            set
            {
                if (value < 0.0f || value > 1.0f)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), SR.Get(SRID.InvalidRepeatProbability, value));
                }

                _repeatProbability = value;
            }
        }
        // The minimum number of occurrences this item can/must be repeated.
        public int MinRepeat
        {
            get
            {
                return _minRepeat == NotSet ? 1 : _minRepeat;
            }
        }
        // The maximum number of occurrences this item can/must be repeated.
        public int MaxRepeat
        {
            get
            {
                return _maxRepeat == NotSet ? 1 : _maxRepeat;
            }
        }
        public float Weight
        {
            get
            {
                return _weight;
            }
            set
            {
                if (value <= 0.0f)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), SR.Get(SRID.InvalidWeight, value));
                }

                _weight = value;
            }
        }

        #endregion

        #region Internal Methods

        /// <summary>
        /// Write the XML fragment describing the object.
        /// </summary>
        internal override void WriteSrgs(XmlWriter writer)
        {
            // Write <item weight="1.0" repeat-prob="0.5" repeat="m-n">
            writer.WriteStartElement("item");
            if (!_weight.Equals(1.0f))
            {
                writer.WriteAttributeString("weight", _weight.ToString("0.########", CultureInfo.InvariantCulture));
            }

            if (!_repeatProbability.Equals(0.5f))
            {
                writer.WriteAttributeString("repeat-prob", _repeatProbability.ToString("0.########", CultureInfo.InvariantCulture));
            }

            if (_minRepeat == _maxRepeat)
            {
                // could be because both value are NotSet of equal
                if (_minRepeat != NotSet)
                {
                    writer.WriteAttributeString("repeat", string.Format(CultureInfo.InvariantCulture, "{0}", _minRepeat));
                }
            }
            else if (_maxRepeat == int.MaxValue || _maxRepeat == NotSet)
            {
                // MinValue Set but not Max Value
                writer.WriteAttributeString("repeat", string.Format(CultureInfo.InvariantCulture, "{0}-", _minRepeat));
            }
            else
            {
                // Max Value Set and maybe MinValue
                int minRepeat = _minRepeat == NotSet ? 1 : _minRepeat;
                writer.WriteAttributeString("repeat", string.Format(CultureInfo.InvariantCulture, "{0}-{1}", minRepeat, _maxRepeat));
            }

            // Write <item> body and footer.
            Type? previousElementType = null;

            foreach (SrgsElement element in _elements)
            {
                // Insert space between consecutive SrgsText _elements.
                Type elementType = element.GetType();

                if ((elementType == typeof(SrgsText)) && (elementType == previousElementType))
                {
                    writer.WriteString(" ");
                }

                previousElementType = elementType;
                element.WriteSrgs(writer);
            }

            writer.WriteEndElement();
        }

        internal override string DebuggerDisplayString()
        {
            StringBuilder sb = new();

            if (_elements.Count > 7)
            {
                sb.Append("SrgsItem Count = ");
                sb.Append(_elements.Count.ToString(CultureInfo.InvariantCulture));
            }
            else
            {
                if (_minRepeat != _maxRepeat || _maxRepeat != NotSet)
                {
                    sb.Append('[');
                    if (_minRepeat == _maxRepeat)
                    {
                        sb.Append(_minRepeat.ToString(CultureInfo.InvariantCulture));
                    }
                    else if (_maxRepeat == int.MaxValue || _maxRepeat == NotSet)
                    {
                        // MinValue Set but not Max Value
                        sb.Append(string.Format(CultureInfo.InvariantCulture, "{0},-", _minRepeat));
                    }
                    else
                    {
                        // Max Value Set and maybe MinValue
                        int minRepeat = _minRepeat == NotSet ? 1 : _minRepeat;
                        sb.Append(string.Format(CultureInfo.InvariantCulture, "{0},{1}", minRepeat, _maxRepeat));
                    }
                    sb.Append("] ");
                }

                bool first = true;
                foreach (SrgsElement element in _elements)
                {
                    if (!first)
                    {
                        sb.Append(' ');
                    }
                    sb.Append('{');
                    sb.Append(element.DebuggerDisplayString());
                    sb.Append('}');
                    first = false;
                }
            }
            return sb.ToString();
        }

        #endregion

        #region Protected Properties

        /// <summary>
        /// Allows the Srgs Element base class to implement
        /// features requiring recursion in the elements tree.
        /// </summary>
        internal override SrgsElement[] Children
        {
            get
            {
                SrgsElement[] elements = new SrgsElement[_elements.Count];
                int i = 0;
                foreach (SrgsElement element in _elements)
                {
                    elements[i++] = element;
                }
                return elements;
            }
        }

        #endregion

        #region Private Methods

        #endregion

        #region Private Fields

        private float _weight = 1.0f;

        private float _repeatProbability = 0.5f;

        private int _minRepeat = NotSet;

        private int _maxRepeat = NotSet;

        private SrgsElementList _elements;

        private const int NotSet = -1;

        #endregion

        #region Private Types

        // Used by the debugger display attribute
        internal class SrgsItemDebugDisplay
        {
            public SrgsItemDebugDisplay(SrgsItem item)
            {
                _weight = item._weight;
                _repeatProbability = item._repeatProbability;
                _minRepeat = item._minRepeat;
                _maxRepeat = item._maxRepeat;
                _elements = item._elements;
            }

            public object Weight
            {
                get
                {
                    return _weight;
                }
            }

            public object MinRepeat
            {
                get
                {
                    return _minRepeat;
                }
            }

            public object MaxRepeat
            {
                get
                {
                    return _maxRepeat;
                }
            }

            public object RepeatProbability
            {
                get
                {
                    return _repeatProbability;
                }
            }

            public object Count
            {
                get
                {
                    return _elements.Count;
                }
            }
            [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
            public SrgsElement[] AKeys
            {
                get
                {
                    SrgsElement[] elements = new SrgsElement[_elements.Count];
                    for (int i = 0; i < _elements.Count; i++)
                    {
                        elements[i] = _elements[i];
                    }
                    return elements;
                }
            }

            private float _weight = 1.0f;
            private float _repeatProbability = 0.5f;
            private int _minRepeat = NotSet;
            private int _maxRepeat = NotSet;
            private SrgsElementList _elements;
        }

        #endregion
    }
}