private static Result <EquipmentBuilder> ParseEquipmentField(ref PlayerLexer lexer)
        {
            Token next;

            if (lexer.NextToken().Type != Tokens.Equals)
            {
                return(Result <EquipmentBuilder> .Error());
            }
            if (lexer.NextToken().Type != Tokens.LeftBracket)
            {
                return(Result <EquipmentBuilder> .Error());
            }

            var builder = new EquipmentBuilder();

            while ((next = lexer.NextToken()).Type != Tokens.RightBracket && next.Type != Tokens.Eof &&
                   next.Type != Tokens.None && next.Type != Tokens.Unknown)
            {
                if (!ParseEquipmentPiece(ref lexer, builder, next))
                {
                    return(Result <EquipmentBuilder> .Error());
                }
            }

            if (next.Type != Tokens.RightBracket)
            {
                return(Result <EquipmentBuilder> .Error());
            }

            return(Result <EquipmentBuilder> .Ok(builder));
        }
        private static Result <Position> ParsePositionField(ref PlayerLexer lexer)
        {
            Token         next;
            Result <long> longValue;

            if (!MultiValueVerification(ref lexer, Tokens.Position))
            {
                return(Result <Position> .Error());
            }
            if ((next = lexer.NextToken()).Type != Tokens.Number)
            {
                return(Result <Position> .Error());
            }
            var x = next.Number;

            if (!(longValue = NextNumberValue(ref lexer)).Success)
            {
                return(Result <Position> .Error());
            }
            var y = longValue.Value;

            if (!(longValue = NextNumberValue(ref lexer)).Success)
            {
                return(Result <Position> .Error());
            }
            var z = longValue.Value;

            if (lexer.NextToken().Type != Tokens.RightParenthesis)
            {
                return(Result <Position> .Error());
            }
            return(Result <Position> .Ok(new Position((ushort)x, (ushort)y, (byte)z)));
        }
        private static Result <List <Item> > ParseInventoryField(ref PlayerLexer lexer)
        {
            Token next;

            if (lexer.NextToken().Type != Tokens.Equals)
            {
                return(Result <List <Item> > .Error());
            }
            if (lexer.NextToken().Type != Tokens.LeftBracket)
            {
                return(Result <List <Item> > .Error());
            }

            var items = new List <Item>();

            while ((next = lexer.NextToken()).Type != Tokens.RightBracket && next.Type != Tokens.Eof &&
                   next.Type != Tokens.None && next.Type != Tokens.Unknown)
            {
                switch (next.Type)
                {
                case Tokens.Item:
                    var item = ParseItemValue(ref lexer);
                    if (!item.Success)
                    {
                        return(Result <List <Item> > .Error());
                    }
                    items.Add(item.Value);
                    break;

                case Tokens.Container:
                    var container = ParseItemValue(ref lexer);
                    if (!container.Success)
                    {
                        return(Result <List <Item> > .Error());
                    }
                    if (!ParseContainer(ref lexer, container.Value))
                    {
                        return(Result <List <Item> > .Error());
                    }
                    items.Add(container.Value);
                    break;

                default:
                    return(Result <List <Item> > .Error());
                }
            }

            if (next.Type != Tokens.RightBracket)
            {
                return(Result <List <Item> > .Error());
            }

            return(Result <List <Item> > .Ok(items));
        }
        private static bool ParseEquipmentPiece(ref PlayerLexer lexer, EquipmentBuilder builder, Token token)
        {
            var val = ParseItemValue(ref lexer);

            if (!val.Success)
            {
                return(false);
            }
            switch (token.Type)
            {
            case Tokens.Head:
                builder.Head = val.Value;
                return(true);

            case Tokens.Necklace:
                builder.Necklace = val.Value;
                return(true);

            case Tokens.Backpack:
                builder.Backpack = val.Value;
                return(true);

            case Tokens.Armor:
                builder.Armor = val.Value;
                return(true);

            case Tokens.Right:
                builder.Right = val.Value;
                return(true);

            case Tokens.Left:
                builder.Left = val.Value;
                return(true);

            case Tokens.Legs:
                builder.Legs = val.Value;
                return(true);

            case Tokens.Feet:
                builder.Feet = val.Value;
                return(true);

            case Tokens.Ring:
                builder.Ring = val.Value;
                return(true);

            case Tokens.Ammo:
                builder.Ammunition = val.Value;
                return(true);
            }

            return(false);
        }
        private static Result <Outfit> ParseOutfitField(ref PlayerLexer lexer)
        {
            if (!MultiValueVerification(ref lexer, Tokens.Outfit))
            {
                return(Result <Outfit> .Error());
            }
            Token next;

            if ((next = lexer.NextToken()).Type != Tokens.String)
            {
                return(Result <Outfit> .Error());
            }
            var name = next.StringText;

            if (!Enum.TryParse <Outfits>(name, true, out var outfit))
            {
                return(Result <Outfit> .Error());
            }

            Result <long> longValue;

            if (!(longValue = NextNumberValue(ref lexer)).Success)
            {
                return(Result <Outfit> .Error());
            }
            var head = longValue.Value;

            if (!(longValue = NextNumberValue(ref lexer)).Success)
            {
                return(Result <Outfit> .Error());
            }
            var body = longValue.Value;

            if (!(longValue = NextNumberValue(ref lexer)).Success)
            {
                return(Result <Outfit> .Error());
            }
            var legs = longValue.Value;

            if (!(longValue = NextNumberValue(ref lexer)).Success)
            {
                return(Result <Outfit> .Error());
            }
            var feet = longValue.Value;

            if (lexer.NextToken().Type != Tokens.RightParenthesis)
            {
                return(Result <Outfit> .Error());
            }

            return(Result <Outfit> .Ok(new Outfit(outfit, (byte)head, (byte)body, (byte)legs, (byte)feet)));
        }
        private static Result <string> ParseStringField(ref PlayerLexer lexer)
        {
            Token next;

            if (lexer.NextToken().Type != Tokens.Equals)
            {
                return(Result <string> .Error());
            }
            if ((next = lexer.NextToken()).Type != Tokens.String)
            {
                return(Result <string> .Error());
            }
            return(Result <string> .Ok(next.StringText));
        }
        private static Result <long> ParseNumberField(ref PlayerLexer lexer)
        {
            Token next;

            if (lexer.NextToken().Type != Tokens.Equals)
            {
                return(Result <long> .Error());
            }
            if ((next = lexer.NextToken()).Type != Tokens.Number)
            {
                return(Result <long> .Error());
            }
            return(Result <long> .Ok(next.Number));
        }
        private static bool MultiValueVerification(ref PlayerLexer lexer, Tokens valueType)
        {
            if (lexer.NextToken().Type != Tokens.Equals)
            {
                return(false);
            }

            if (lexer.NextToken().Type != valueType)
            {
                return(false);
            }

            return(lexer.NextToken().Type == Tokens.LeftParenthesis);
        }
        private static Result <long> NextNumberValue(ref PlayerLexer lexer)
        {
            Token next;

            if (lexer.NextToken().Type != Tokens.Comma)
            {
                return(Result <long> .Error());
            }
            if ((next = lexer.NextToken()).Type != Tokens.Number)
            {
                return(Result <long> .Error());
            }
            return(Result <long> .Ok(next.Number));
        }
        private static bool ParseContainer(ref PlayerLexer lexer, Item parent)
        {
            Token next;

            if (lexer.NextToken().Type != Tokens.Equals)
            {
                return(false);
            }
            if (lexer.NextToken().Type != Tokens.LeftBrace)
            {
                return(false);
            }

            while ((next = lexer.NextToken()).Type != Tokens.RightBrace && next.Type != Tokens.Eof &&
                   next.Type != Tokens.None && next.Type != Tokens.Unknown)
            {
                switch (next.Type)
                {
                case Tokens.Item:
                    var item = ParseItemValue(ref lexer);
                    if (!item.Success)
                    {
                        return(false);
                    }
                    parent.AddInside(item.Value);
                    break;

                case Tokens.Container:
                    var container = ParseItemValue(ref lexer);
                    if (!container.Success)
                    {
                        return(false);
                    }
                    ParseContainer(ref lexer, container.Value);
                    parent.AddInside(container.Value);
                    break;

                default:
                    return(false);
                }
            }

            if (next.Type != Tokens.RightBrace)
            {
                return(false);
            }

            return(true);
        }
        private static Result <bool> ParseBoolField(ref PlayerLexer lexer)
        {
            Token next;

            if (lexer.NextToken().Type != Tokens.Equals)
            {
                return(Result <bool> .Error());
            }
            if ((next = lexer.NextToken()).Type == Tokens.True)
            {
                return(Result <bool> .Ok(true));
            }
            if (next.Type == Tokens.False)
            {
                return(Result <bool> .Ok(false));
            }
            return(Result <bool> .Error());
        }
        private static Result <Item> ParseItemValue(ref PlayerLexer lex)
        {
            if (lex.NextToken().Type != Tokens.LeftParenthesis)
            {
                return(Result <Item> .Error());
            }
            var value = lex.NextToken();

            if (value.Type != Tokens.Number)
            {
                return(Result <Item> .Error());
            }
            var next = lex.NextToken();

            if (next.Type == Tokens.RightParenthesis) // 1 arg
            {
                return(Result <Item> .Ok(IoC.Items.Create((ushort)value.Number)));
            }

            // 2 args
            if (next.Type != Tokens.Comma)
            {
                return(Result <Item> .Error());
            }
            var extra = lex.NextToken();

            if (extra.Type != Tokens.Number)
            {
                return(Result <Item> .Error());
            }
            if (lex.NextToken().Type != Tokens.RightParenthesis)
            {
                return(Result <Item> .Error());
            }
            return(Result <Item> .Ok(IoC.Items.Create((ushort)value.Number, (byte)extra.Number)));
        }
        public Player Read(string path)
        {
            var                       fileName  = Path.GetFileName(path);
            var                       read      = File.ReadAllText(path);
            var                       player    = new CharacterBuilder();
            var                       lexer     = new PlayerLexer(read.AsSpan());
            Token                     lastToken = Token.None;
            Token                     token;
            Result <bool>             boolField;
            Result <long>             numberField;
            Result <string>           stringField;
            Result <Position>         posField;
            Result <Outfit>           outfitField;
            Result <EquipmentBuilder> equipmentField;
            Result <List <Item> >     inventoryField;

            while ((token = lexer.NextToken()).Type != Tokens.Eof && token.Type != Tokens.None)
            {
                switch (token.Type)
                {
                case Tokens.Unknown:
                    return(ReportError(fileName, token, lastToken));

                case Tokens.Id:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Id = numberField.Value;
                    break;

                case Tokens.Name:
                    stringField = ParseStringField(ref lexer);
                    if (!stringField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Name = stringField.Value;
                    break;

                case Tokens.Password:
                    stringField = ParseStringField(ref lexer);
                    if (!stringField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Password = stringField.Value;
                    break;

                case Tokens.Position:
                    posField = ParsePositionField(ref lexer);
                    if (!posField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Position = posField.Value;
                    break;

                case Tokens.TemplePosition:
                    posField = ParsePositionField(ref lexer);
                    if (!posField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.TemplePosition = posField.Value;
                    break;

                case Tokens.Outfit:
                    outfitField = ParseOutfitField(ref lexer);
                    if (!outfitField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Outfit = outfitField.Value;
                    break;

                case Tokens.Level:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Level = numberField.Value;
                    break;

                case Tokens.Experience:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Experience = numberField.Value;
                    break;

                case Tokens.Health:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Hitpoints = numberField.Value;
                    break;

                case Tokens.MaxHealth:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.MaxHitpoints = numberField.Value;
                    break;

                case Tokens.Mana:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Mana = numberField.Value;
                    break;

                case Tokens.MaxMana:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.MaxMana = numberField.Value;
                    break;

                case Tokens.Capacity:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Capacity = numberField.Value;
                    break;

                case Tokens.MagicLevel:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.MagicLevel = numberField.Value;
                    break;

                case Tokens.MagicLevelExp:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.MagicLevelExp = numberField.Value;
                    break;

                case Tokens.Fist:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Fist = numberField.Value;
                    break;

                case Tokens.FistExp:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.FistExp = numberField.Value;
                    break;

                case Tokens.Club:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Club = numberField.Value;
                    break;

                case Tokens.ClubExp:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.ClubExp = numberField.Value;
                    break;

                case Tokens.Sword:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Sword = numberField.Value;
                    break;

                case Tokens.SwordExp:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.SwordExp = numberField.Value;
                    break;

                case Tokens.Axe:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Axe = numberField.Value;
                    break;

                case Tokens.AxeExp:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.AxeExp = numberField.Value;
                    break;

                case Tokens.Distance:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Dist = numberField.Value;
                    break;

                case Tokens.DistanceExp:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.DistExp = numberField.Value;
                    break;

                case Tokens.Shielding:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Shield = numberField.Value;
                    break;

                case Tokens.ShieldingExp:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.ShieldExp = numberField.Value;
                    break;

                case Tokens.Fishing:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Fish = numberField.Value;
                    break;

                case Tokens.FishingExp:
                    numberField = ParseNumberField(ref lexer);
                    if (!numberField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.FishExp = numberField.Value;
                    break;

                case Tokens.Equipment:
                    equipmentField = ParseEquipmentField(ref lexer);
                    if (!equipmentField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Equipment = equipmentField.Value;
                    break;

                case Tokens.Inventory:
                    inventoryField = ParseInventoryField(ref lexer);
                    if (!inventoryField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.Inventory = inventoryField.Value;
                    break;

                case Tokens.IsAdmin:
                    boolField = ParseBoolField(ref lexer);
                    if (!boolField.Success)
                    {
                        return(ReportError(fileName, token, lastToken));
                    }
                    player.IsGm = boolField.Value;
                    break;

                default:
                    return(ReportError(fileName, token, lastToken));
                }

                lastToken = token;
            }

            return(player.Build());
        }