Represents a selection window in a message script.
Inheritance: IDialog
        // TODO: maybe move the parsing functions to a seperate class
        /// <summary>
        /// Creates a <see cref="MessageScript"/> from a <see cref="MessageScriptBinary"/>.
        /// </summary>
        public static MessageScript FromBinary(MessageScriptBinary binary, FormatVersion version = FormatVersion.Detect, Encoding encoding = null)
        {
            if (binary == null)
            {
                throw new ArgumentNullException(nameof(binary));
            }

            if (binary.DialogHeaders == null)
            {
                throw new ArgumentNullException(nameof(binary));
            }

            // Create new script instance & set user id, format version
            var instance = new MessageScript
            {
                Id            = binary.Header.UserId,
                FormatVersion = version == FormatVersion.Detect ? ( FormatVersion)binary.FormatVersion : version,
                Encoding      = encoding
            };

            // Convert the binary messages to their counterpart
            var labelOccurences = new Dictionary <string, int>();

            foreach (var messageHeader in binary.DialogHeaders)
            {
                IDialog              message;
                IReadOnlyList <int>  pageStartAddresses;
                IReadOnlyList <byte> buffer;
                int pageCount;

                switch (messageHeader.Kind)
                {
                case BinaryDialogKind.Message:
                {
                    var binaryMessage = (BinaryMessageDialog)messageHeader.Data.Value;
                    pageStartAddresses = binaryMessage.PageStartAddresses;
                    buffer             = binaryMessage.TextBuffer;
                    pageCount          = binaryMessage.PageCount;

                    // check for duplicates
                    var name = ResolveName(labelOccurences, binaryMessage.Name);

                    if (binaryMessage.SpeakerId == 0xFFFF)
                    {
                        message = new MessageDialog(name);
                    }
                    else if ((binaryMessage.SpeakerId & 0x8000) == 0x8000)
                    {
                        Trace.WriteLine(binaryMessage.SpeakerId.ToString("X4"));

                        message = new MessageDialog(name, new VariableSpeaker(binaryMessage.SpeakerId & 0x0FFF));
                    }
                    else
                    {
                        if (binary.SpeakerTableHeader.SpeakerNameArray.Value == null)
                        {
                            throw new InvalidDataException("Speaker name array is null while being referenced");
                        }

                        TokenText speakerName = null;
                        if (binaryMessage.SpeakerId < binary.SpeakerTableHeader.SpeakerCount)
                        {
                            speakerName = ParseSpeakerText(binary.SpeakerTableHeader.SpeakerNameArray
                                                           .Value[binaryMessage.SpeakerId].Value, instance.FormatVersion, encoding == null ? Encoding.ASCII : encoding);
                        }

                        message = new MessageDialog(name, new NamedSpeaker(speakerName));
                    }
                }
                break;

                case BinaryDialogKind.Selection:
                {
                    var binaryMessage = ( BinarySelectionDialog )messageHeader.Data.Value;
                    pageStartAddresses = binaryMessage.OptionStartAddresses;
                    buffer             = binaryMessage.TextBuffer;
                    pageCount          = binaryMessage.OptionCount;
                    var name = ResolveName(labelOccurences, binaryMessage.Name);
                    message = new SelectionDialog(name, (SelectionDialogPattern)binaryMessage.Pattern);
                }
                break;

                default:
                    throw new InvalidDataException("Unknown message type");
                }

                if (pageCount != 0)
                {
                    // Parse the line data
                    ParsePages(message, pageStartAddresses, buffer, instance.FormatVersion, encoding == null ? Encoding.ASCII : encoding);
                }

                // Add it to the message list
                instance.Dialogs.Add(message);
            }

            return(instance);
        }