public static Routes Load(string pathToFile)
        {
            Routes routes = new Routes();

            using (var doc = new DocumentParser(pathToFile))
            {
                string line = doc.ReadNextLine();

                while (line != null)
                {
                    switch (line)
                    {
                        case "[LUMP]":
                            doc.ReadNextLine();  // level
                            line = doc.ReadNextLine();
                            break;

                        case "[VERSION]":
                            doc.ReadNextLine();  // 2.500000
                            line = doc.ReadNextLine();
                            break;

                        case "[RACE_LAYERS]":
                            line = doc.SkipToNextSection();
                            break;

                        case "[LUA_SCRIPTS]":
                            line = doc.SkipToNextSection();
                            break;

                        case "[RACES]":
                            while (!doc.NextLineIsASection())
                            {
                                routes.races.Add(doc.ReadNextLine());
                            }

                            line = doc.ReadNextLine();
                            break;

                        case "[AINODE]":
                            bool bAINode = true;
                            var node = new AINode();

                            while (bAINode)
                            {
                                line = doc.ReadNextLine();

                                switch (line)
                                {
                                    case "<INDEX>":
                                        node.Index = doc.ReadInt();
                                        break;

                                    case "<TYPE>":
                                        node.Type = doc.ReadInt();
                                        break;

                                    case "<RADIUS>":
                                        node.Radius = doc.ReadFloat();
                                        break;

                                    case "<POS>":
                                        node.Position = doc.ReadVector3();
                                        break;

                                    case "<RACE_LINE>":
                                        node.RaceLine = doc.ReadVector3();
                                        break;

                                    case "<RACE_LINE_OFFSET>":
                                        node.RaceLineOffset = doc.ReadFloat();
                                        break;

                                    default:
                                        bAINode = false;
                                        routes.nodes.Add(node);
                                        if (line != null && !line.StartsWith("[")) { Console.WriteLine("Unexpected [AINODE] line: " + line); }
                                        break;
                                }
                            }
                            break;

                        case "[AILINK]":
                            bool bAILink = true;
                            var link = new AILink();

                            while (bAILink)
                            {
                                line = doc.ReadNextLine();

                                switch (line)
                                {
                                    case "<NODES>":
                                        link.NodeA = doc.ReadInt();
                                        link.NodeB = doc.ReadInt();
                                        break;

                                    case "<WIDTH>":
                                        link.Width = doc.ReadFloat();
                                        break;

                                    case "<VALUE>":
                                        link.Value = doc.ReadNextLine();
                                        break;

                                    case "<ONEWAY>":
                                        link.OneWay = true;
                                        break;

                                    case "<TYPE>":
                                        for (int i = 0; i < routes.races.Count; i++)
                                        {
                                            link.Types.Add(doc.ReadInt());
                                        }
                                        break;

                                    case "<RACE_VALUE>":
                                        link.RaceValueAmount = doc.ReadInt();
                                        link.RaceValue = doc.ReadNextLine();
                                        break;

                                    default:
                                        bAILink = false;
                                        routes.links.Add(link);
                                        if (line != null && !line.StartsWith("[")) { throw new NotImplementedException("Unexpected [AILINK] line: " + line); }
                                        break;
                                }
                            }
                            break;

                        default:
                            Console.WriteLine(pathToFile);
                            throw new NotImplementedException("Unexpected [SECTION]: " + line);
                    }
                }
            }

            return routes;
        }
        public static Accessory Load(string pathToFile)
        {
            Accessory accessory = new Accessory();

            using (var doc = new DocumentParser(pathToFile))
            {
                string line = doc.ReadNextLine();

                while (line != null)
                {
                    switch (line)
                    {
                        case "[LUMP]":
                            doc.ReadNextLine();  // level
                            line = doc.ReadNextLine();
                            break;

                        case "[VERSION]":
                            doc.ReadNextLine();  // 2.500000
                            line = doc.ReadNextLine();
                            break;

                        case "[RACE_LAYERS]":
                            line = doc.SkipToNextSection();
                            break;

                        case "[LUA_SCRIPTS]":
                            line = doc.SkipToNextSection();
                            break;

                        case "[APP_DATA]":
                            if (TestLine("<CustomAccessoryType>", doc.ReadNextLine(), out line))
                            {
                                CustomAccessoryType accessoryType;
                                line = doc.ReadNextLine();

                                if (!Enum.TryParse<CustomAccessoryType>(line, out accessoryType)) { throw new NotImplementedException("Unknown CustomAccessoryType: " + line); }
                                accessory.CustomAccessoryType = accessoryType;

                                switch (accessoryType)
                                {
                                    case CustomAccessoryType.ConveyorAccessory:
                                    case CustomAccessoryType.CopSpawn:
                                    case CustomAccessoryType.ExplodingAccessory:
                                    case CustomAccessoryType.GibletAccessoryType:
                                    case CustomAccessoryType.MultiplayerSpawn:
                                    case CustomAccessoryType.StandardAccessory:
                                    case CustomAccessoryType.StartingGrid:
                                    case CustomAccessoryType.AngularDampedAccessory:
                                    case CustomAccessoryType.Checkpoint:
                                    case CustomAccessoryType.Powerup:
                                    case CustomAccessoryType.ManagedAccessory:
                                    case CustomAccessoryType.RigidBodyAnimation:
                                    case CustomAccessoryType.RockingAccessory:
                                    case CustomAccessoryType.RotatingAccessory:
                                        while (!doc.NextLineIsASection() && !doc.EOF())
                                        {
                                            accessory.customAccessoryProperties.Add(doc.ReadNextLine().Split(' '));
                                        }
                                        break;

                                    default:
                                        Console.WriteLine("Unhandled accessory");
                                        break;
                                }

                                line = doc.ReadNextLine();

                                if (line != null && line.ToLower().StartsWith("accessoryaudio"))
                                {
                                    accessory.CustomAccessoryAudio = line.Replace("accessoryaudio ", "", StringComparison.OrdinalIgnoreCase);
                                    line = doc.ReadNextLine();
                                }
                            }
                            break;

                        case "[ACOLYTE]":
                        case "[ACOYLTE]":
                            bool bAcolyte = true;

                            while (bAcolyte)
                            {
                                line = doc.ReadNextLine();

                                switch (line)
                                {
                                    case "<powerup>":
                                        accessory.Powerup = true;
                                        break;

                                    case "<hidden>":
                                        accessory.Hidden = true;
                                        break;

                                    default:
                                        bAcolyte = false;
                                        if (line != null && !line.StartsWith("[")) { Console.WriteLine("Unexpected [ACOLYTE] line: " + line); }
                                        break;
                                }
                            }
                            break;

                        case "[ANIMATION]":
                            accessory.AnimationType = doc.ReadNextLine();
                            accessory.AnimationFile = doc.ReadNextLine();
                            accessory.AnimationSpeed = doc.ReadFloat();
                            accessory.AnimationPhase = doc.ReadFloat();
                            line = doc.ReadNextLine();
                            break;

                        case "[DYNAMICS]":
                            accessory.dynamics.Add(new AccessoryDynamics(doc));
                            line = doc.ReadNextLine();
                            break;

                        default:
                            Console.WriteLine(pathToFile);
                            throw new NotImplementedException("Unexpected [SECTION]: " + line);
                    }
                }
            }

            return accessory;
        }