/// <summary>
        /// Loads macros from rewindable reader instance.
        /// </summary>
        /// <param name="rewinder">The instance to read data from.</param>
        private void Load(RewindableTextReader rewinder)
        {
            Helper.ThrowIfNull(rewinder);

            string line = null;
            while ((line = rewinder.ReadLine()) != null)
            {
                MacroName macro = MacroName.Create(line);
                switch (macro.Symbol)
                {
                    case "o":
                        LoadGlobalOptions(rewinder);
                        break;
                    case "v":
                        VarFloor var = new VarFloor()
                        {
                            Macro = macro,
                            Variance = ReadTagArray(rewinder, "<VARIANCE>"),
                        };

                        VarFloors.Add(var.Macro.Name, var);
                        break;
                    case "t":
                        Transition trans = new Transition()
                        {
                            Macro = macro,
                            Matrix = ReadTransition(rewinder),
                        };

                        Transitions.Add(trans.Macro.Name, trans);
                        break;
                    case "s":
                        HmmStream stream = ReadStream(rewinder);
                        stream.Name = macro.Name;
                        Streams.Add(macro.Name, stream);
                        break;
                    case "h":
                        HmmModel model = ReadModel(rewinder, Streams, Transitions);
                        model.Macro = macro;
                        Models.Add(macro.Name, model);
                        break;
                    default:
                        throw new InvalidDataException(Helper.NeutralFormat(
                            "Macro name [{0}] is not supported in line [{1}].", macro.Name, macro.Name));
                }
            }
        }
        /// <summary>
        /// Loads global options information from text reader instance.
        /// </summary>
        /// <param name="rewinder">The rewindable text reader to load data from.</param>
        private void LoadGlobalOptions(RewindableTextReader rewinder)
        {
            Helper.ThrowIfNull(rewinder);

            foreach (string line in rewinder.ReadLines(new string[] { MacroName.Indicator }, false))
            {
                string[] items = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                if (items.Length <= 1)
                {
                    throw new InvalidDataException(Helper.NeutralFormat(
                        "The information in global options should be with (<tag> <value>+), but it is [{0}]", line));
                }

                switch (items[0])
                {
                    case "<STREAMINFO>":
                        StreamInfo = ParseSizedArray(ParseIntArray(items.Skip(1)));
                        break;
                    case "<MSDINFO>":
                        MsdInfo = ParseSizedArray(ParseIntArray(items.Skip(1)));
                        break;
                    case "<VECSIZE>":
                        LoadVecSize(items.Skip(1));
                        break;
                    default:
                        throw new InvalidDataException(Helper.NeutralFormat(
                            "The line [{0}] of global options is not supported.", line));
                }
            }
        }
        /// <summary>
        /// Reads one transition instance from text reader instance.
        /// </summary>
        /// <param name="rewinder">The text reader to read double matrix from.</param>
        /// <returns>Transition instance loaded.</returns>
        private static double[,] ReadTransition(RewindableTextReader rewinder)
        {
            Helper.ThrowIfNull(rewinder);
            int size = ParseTagValue(rewinder.ReadLine(), "<TRANSP>");

            double[,] values = ParseDoubleMatrix(
                rewinder.ReadLines(new string[] { "<", MacroName.Indicator }, false).ToArray(), size);

            return values;
        }
        /// <summary>
        /// Reads double matrix from the text reader with the expected tag.
        /// </summary>
        /// <param name="rewinder">Text reader to read array from.</param>
        /// <param name="tag">Expected tag to start in the stream.</param>
        /// <returns>Double matrix from the text reader.</returns>
        private static double[] ReadTagArray(RewindableTextReader rewinder, string tag)
        {
            Helper.ThrowIfNull(rewinder);
            Helper.ThrowIfNull(tag);

            string line = rewinder.ReadLine();
            int size = ParseTagValue(line, tag);

            double[] values = new double[0];
            if (size > 0)
            {
                values = ParseDoubleArray(rewinder.ReadLine());
                if (values.Length != size)
                {
                    throw new InvalidDataException(Helper.NeutralFormat("Mismatched value is found, " +
                        "declared as [{0}], but as [{1}].", size, values.Length));
                }
            }

            return values;
        }
        /// <summary>
        /// Reads one HMM gaussian instance from text reader instance.
        /// </summary>
        /// <param name="rewinder">The text reader to read gaussian from.</param>
        /// <returns>HMM gaussian instance loaded.</returns>
        private static Gaussian ReadGaussian(RewindableTextReader rewinder)
        {
            Helper.ThrowIfNull(rewinder);
            Gaussian gaussian = new Gaussian();

            gaussian.Mean = ReadTagArray(rewinder, "<MEAN>");
            gaussian.Variance = ReadTagArray(rewinder, "<VARIANCE>");

            if (gaussian.Mean.Length != gaussian.Variance.Length)
            {
                throw new InvalidDataException(Helper.NeutralFormat(
                    "The dimension of mean [{0}] should equal with that of variance [{1}].",
                    gaussian.Mean.Length, gaussian.Variance.Length));
            }

            gaussian.Length = gaussian.Mean.Length;

            string line = rewinder.PeekLine();
            if (line != null && line.StartsWith("<GCONST>"))
            {
                string[] items = ParseTagValues(rewinder.ReadLine(), "<GCONST>");
                if (items.Length != 1)
                {
                    throw new InvalidDataException(Helper.NeutralFormat(
                        "Single value is expected for <GCONST>, but it is with line [{0}].", line));
                }

                gaussian.GlobalConstant = float.Parse(items[0], CultureInfo.InvariantCulture);
            }

            return gaussian;
        }
        /// <summary>
        /// Reads one HMM stream instance from text reader instance.
        /// </summary>
        /// <param name="rewinder">The text reader to read stream from.</param>
        /// <returns>HMM stream instance loaded.</returns>
        private static HmmStream ReadStream(RewindableTextReader rewinder)
        {
            Helper.ThrowIfNull(rewinder);
            HmmStream stream = new HmmStream();

            string line = rewinder.PeekLine();
            int streamIndex = 0;
            if (line.StartsWith("<STREAM>"))
            {
                streamIndex = ParseTagValue(rewinder.ReadLine(), "<STREAM>");
            }

            int mixtureNumber = 1;
            line = rewinder.PeekLine();
            if (line.StartsWith("<NUMMIXES>"))
            {
                mixtureNumber = ParseTagValue(rewinder.ReadLine(), "<NUMMIXES>");
            }

            List<Gaussian> gaussians = new List<Gaussian>();
            for (int i = 0; i < mixtureNumber; i++)
            {
                int mixtureIndex = 0;
                float weight = 0.0f;
                line = rewinder.PeekLine();
                if (line.StartsWith("<MIXTURE>"))
                {
                    string[] values = ParseTagValues(rewinder.ReadLine(), "<MIXTURE>");
                    mixtureIndex = int.Parse(values[0], CultureInfo.InvariantCulture);
                    weight = float.Parse(values[1], CultureInfo.InvariantCulture);

                    if (mixtureIndex != i + 1)
                    {
                        throw new InvalidDataException(
                            Helper.NeutralFormat("The mixture index is mis-matched between {0} and {1} in line [{2}]",
                            i, mixtureIndex, line));
                    }
                }

                Gaussian gaussian = ReadGaussian(rewinder);
                gaussian.Weight = weight;
                gaussians.Add(gaussian);
            }

            stream.Gaussians = gaussians.ToArray();

            return stream;
        }
        /// <summary>
        /// Reads one HMM state instance from text reader instance.
        /// </summary>
        /// <param name="rewinder">Rewindable text reader instance to read HMM model from.</param>
        /// <param name="streams">Global HMM streams if any reference.</param>
        /// <returns>HMM state instance loaded.</returns>
        private static HmmState ReadState(RewindableTextReader rewinder, Dictionary<string, HmmStream> streams)
        {
            Helper.ThrowIfNull(rewinder);
            Helper.ThrowIfNull(streams);
            HmmState state = new HmmState();

            int stateIndex = ParseTagValue(rewinder.ReadLine(), "<STATE>");
            string line = rewinder.PeekLine();

            if (line.StartsWith("<SWEIGHTS>"))
            {
                rewinder.ReadLine();
                line = rewinder.ReadLine();
                line = rewinder.PeekLine();
            }

            if (line.StartsWith(MacroName.Indicator))
            {
                MacroName macro = MacroName.Create(rewinder.ReadLine());
                if (macro.Symbol != "s")
                {
                    throw new InvalidDataException(
                        Helper.NeutralFormat("Stream symbol 's' is expected for line [{0}].", line));
                }

                if (!streams.ContainsKey(macro.Name))
                {
                    throw new InvalidDataException(Helper.NeutralFormat(
                        "Referenced macro [{0}] does not exist, used by line [{1}].", macro.Name, line));
                }

                state.Streams.Add(streams[macro.Name]);
            }
            else
            {
                while (line.StartsWith("<STREAM>"))
                {
                    HmmStream stream = ReadStream(rewinder);
                    state.Streams.Add(stream);
                    line = rewinder.PeekLine();
                }
            }

            return state;
        }
        /// <summary>
        /// Reads one HMM model instance from text reader instance.
        /// </summary>
        /// <param name="rewinder">Rewindable text reader instance to read HMM model from.</param>
        /// <param name="streams">Global HMM streams if any reference.</param>
        /// <param name="transition">Global transitions if any reference.</param>
        /// <returns>HMM model instance loaded.</returns>
        private static HmmModel ReadModel(RewindableTextReader rewinder,
            Dictionary<string, HmmStream> streams, Dictionary<string, Transition> transition)
        {
            Helper.ThrowIfNull(rewinder);
            Helper.ThrowIfNull(streams);
            Helper.ThrowIfNull(transition);
            HmmModel model = new HmmModel();

            Ensure(rewinder.ReadLine(), "<BEGINHMM>");

            int stateCount = ParseTagValue(rewinder.ReadLine(), "<NUMSTATES>");

            // Excludes the entrance and existing states
            for (int i = 1; i < stateCount - 1; i++)
            {
                HmmState state = ReadState(rewinder, streams);
                model.States.Add(state);
            }

            if (rewinder.PeekLine().StartsWith("~t"))
            {
                MacroName macro = MacroName.Create(rewinder.ReadLine());
                if (!transition.ContainsKey(macro.Name))
                {
                    throw new InvalidDataException(Helper.NeutralFormat("Transition [{0}] is not found.", macro.Name));
                }

                model.Transition = transition[macro.Name];
            }
            else if (rewinder.PeekLine().StartsWith("<TRANSP>"))
            {
                model.Transition = new Transition()
                {
                    Matrix = ReadTransition(rewinder),
                };
            }

            Ensure(rewinder.ReadLine(), "<ENDHMM>");

            return model;
        }
        /// <summary>
        /// Loads the macros in Master Macro File from text reader instance.
        /// </summary>
        /// <param name="reader">Text reader instance to read macros from.</param>
        /// <returns>MasterMacroFile.</returns>
        public MasterMacroFile Load(TextReader reader)
        {
            Helper.ThrowIfNull(reader);

            Reset();

            using (RewindableTextReader rewinder = new RewindableTextReader(reader))
            {
                Load(rewinder);
            }

            return this;
        }