/// <summary>
        /// Resolves the model field interfaces of a data model configurationfrom a ParsedPartial.
        /// </summary>
        /// <param name="parsedFragment">The partially parsed extension.</param>
        /// <returns>The field interfaces of the data model configuration.</returns>
        public static Typo3ExtensionGenerator.Model.Configuration.Interface.Interface Resolve( Fragment parsedFragment )
        {
            Typo3ExtensionGenerator.Model.Configuration.Interface.Interface @interface =
            new Typo3ExtensionGenerator.Model.Configuration.Interface.Interface {
                                                                              Target = parsedFragment.Parameters, SourceFragment = parsedFragment
                                                                            };

              if( parsedFragment.Fragments.Any() ) {
            foreach( Fragment setting in parsedFragment.Fragments ) {
              @interface.Settings.Add( new KeyValuePair<string, string>( setting.Keyword, setting.Parameters ) );
            }
              }

              // Parse any settings we know
              for( int settingIndex = 0; settingIndex < @interface.Settings.Count; settingIndex++ ) {
            KeyValuePair<string, string> setting = @interface.Settings[ settingIndex ];
            if( setting.Key == Keywords.ConfigurationDirectives.InterfaceDirectives.Exclude ) {
              @interface.Exclude = ParseHelper.ParseBool( setting.Value );

            } else if( setting.Key == Keywords.Title ) {
              @interface.Title = setting.Value;

            } else if( setting.Key == Keywords.ConfigurationDirectives.InterfaceDirectives.Representation ) {
              @interface.DisplayTypeTarget = setting.Value;
              DisplayTypeResolver.Resolve( parsedFragment, @interface, setting.Value );

            } else if( setting.Key == Keywords.ConfigurationDirectives.InterfaceDirectives.DefaultValue ) {
              @interface.DefaultValue = setting.Value;
            }
              }

              return @interface;
        }
        /// <summary>
        /// Resolves the models of an extension from a ParsedPartial.
        /// </summary>
        /// <param name="parsedFragment">The partially parsed extension.</param>
        /// <returns>The models of the extension</returns>
        public static List<Repository> Resolve( Fragment parsedFragment )
        {
            IEnumerable<Fragment> repositoryPartials = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclareRepository );
              if( !repositoryPartials.Any() ) return null;

              List<Repository> repositories = new List<Repository>();
              foreach( Fragment repositoryPartial in repositoryPartials ) {
            Repository repository = new Repository {
                                                 TargetModelName = repositoryPartial.Parameters,
                                                 SourceFragment = repositoryPartial,
                                               };
            repositories.Add( repository );
            if( repositoryPartial.Fragments.Any() ) {
              foreach( Fragment dataMember in repositoryPartial.Fragments ) {
            if( dataMember.Keyword == Keywords.PluginDirectives.Action ) {
              Action action = ActionResolver.ResolveAction( dataMember );
              repository.Methods.Add( action );

            } else if( dataMember.Keyword == Keywords.Implementation) {
              repository.Implementation = dataMember.Parameters;

            } else if( dataMember.Keyword == Keywords.InternalType ) {
              repository.InternalType = dataMember.Parameters;
            }
              }
            }
              }

              return repositories;
        }
        /// <summary>
        /// Resolves a palette definition of data model configuration of an extension from a ParsedPartial.
        /// </summary>
        /// <param name="parsedFragment">The partially parsed extension.</param>
        /// <returns>The palette definition.</returns>
        /// <exception cref="ParserException">Palette does not define an interface.</exception>
        public static Palette Resolve( Fragment parsedFragment )
        {
            // Check if the palette defines an interface
              Fragment interfacePartial = parsedFragment.Fragments.SingleOrDefault( p => p.Keyword == Keywords.DefineInterface );
              if( null == interfacePartial ) {
            throw new ParserException( string.Format( "Palette '{0}' does not define an interface.", parsedFragment.Parameters ), parsedFragment.SourceDocument );
              }

              Palette parsedPalette = new Palette {
            Name           = parsedFragment.Parameters,
            Interface      = interfacePartial.Parameters,
            Visibility     = Palette.PaletteVisibility.Default,
            SourceFragment = interfacePartial
              };

              if( parsedFragment.Fragments.Any() ) {
            foreach( Fragment configurationDirective in parsedFragment.Fragments ) {
              // Find configuration directives
              if( Keywords.ConfigurationDirectives.Visibility.Hidden == configurationDirective.Keyword ) {
            parsedPalette.Visibility = Palette.PaletteVisibility.ShowNever;

              } else if( Keywords.ConfigurationDirectives.Visibility.Show == configurationDirective.Keyword ) {
            if( Keywords.ConfigurationDirectives.Visibility.Always == configurationDirective.Parameters ) {
              parsedPalette.Visibility = Palette.PaletteVisibility.ShowAlways;
            }
              }
            }
              }

              return parsedPalette;
        }
        /// <summary>
        /// Resolves the models of an extension from a ParsedPartial.
        /// </summary>
        /// <param name="parsedFragment">The partially parsed extension.</param>
        /// <returns>The models of the extension</returns>
        public static List<DataModel> Resolve( Fragment parsedFragment )
        {
            IEnumerable<Fragment> modelPartials = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclareModel );
              if( !modelPartials.Any() ) return null;

              List<DataModel> dataModels = new List<DataModel>();
              foreach( Fragment modelPartial in modelPartials ) {
            DataModel dataModel = new DataModel {Name = modelPartial.Parameters, SourceFragment = modelPartial};
            dataModels.Add( dataModel );
            if( modelPartial.Fragments.Any() ) {
              foreach( Fragment dataMember in modelPartial.Fragments ) {
            if( dataMember.Keyword == Keywords.InternalType ) {
              dataModel.InternalType = dataMember.Parameters;

            } else {
              dataModel.Members.Add(
                new DataModel.DataModelMember {Name = dataMember.Keyword, Value = dataMember.Parameters} );
            }
              }
            }
              }

              // Resolve any foreign key references
              ForeignKeyResolver.Resolve( dataModels );

              return dataModels;
        }
        /// <summary>
        /// Resolves the plugins of an extension from a fragment.
        /// </summary>
        /// <param name="parsedFragment">The partially parsed extension.</param>
        /// <returns>The plugins of the extension</returns>
        /// <exception cref="GeneratorException">A plugin must contain exactly one model.</exception>
        public static List<Typo3ExtensionGenerator.Model.Plugin.Plugin> Resolve( Fragment parsedFragment )
        {
            IEnumerable<Fragment> pluginPartials = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclarePlugin );
              if( !pluginPartials.Any() ) return null;

              List<Typo3ExtensionGenerator.Model.Plugin.Plugin> plugins = new List<Typo3ExtensionGenerator.Model.Plugin.Plugin>();
              foreach( Fragment pluginPartial in pluginPartials ) {
            // Construct the plugin with the given name
            Typo3ExtensionGenerator.Model.Plugin.Plugin plugin = new Typo3ExtensionGenerator.Model.Plugin.Plugin
                                                             {Name = pluginPartial.Parameters,SourceFragment = pluginPartial };

            // Find the data models that are defined for this plugin
            List<DataModel> dataModels = ModelResolver.Resolve( pluginPartial );
            if( null == dataModels || dataModels.Count > 1 ) {
              throw new GeneratorException( "A plugin must contain exactly one model.", pluginPartial.SourceDocument );
            }
            plugin.Model = dataModels[ 0 ];
            plugin.Model.Name = "flexform";

            // Resolve plugin
            foreach( Fragment pluginParameter in pluginPartial.Fragments ) {
              if( pluginParameter.Keyword == Keywords.Title) {
            plugin.Title = pluginParameter.Parameters;

              } else if( pluginParameter.Keyword == Keywords.DefineInterface ) {
            Typo3ExtensionGenerator.Model.Configuration.Interface.Interface @interface =
              InterfaceResolver.Resolve( pluginParameter );

            @interface.ParentModelTarget = "flexform";
            @interface.ParentModel = plugin.Model;
            plugin.Interfaces.Add( @interface );

              } else if( pluginParameter.Keyword == Keywords.PluginDirectives.Action ) {
            Action action = ActionResolver.ResolveAction( pluginParameter );
            plugin.Actions.Add( action );

              } else if( pluginParameter.Keyword == Keywords.PluginDirectives.Listener ) {
            Listener listener = ListenerResolver.ResolveListener( pluginParameter );
            plugin.Actions.Add( listener.TargetAction );
            plugin.Listeners.Add( listener );

              } else if( pluginParameter.Keyword == Keywords.Implementation ) {
            plugin.Implementation = pluginParameter.Parameters;
              }
            }

            // If no name was defined, use the common placeholder names
            if( string.IsNullOrEmpty( plugin.Name ) ) {
              plugin.Name = string.Format( "Pi{0}", ( plugins.Count + 1 ) );
            }

            plugins.Add( plugin );
              }

              return plugins;
        }
        /// <summary>
        /// Resolves the configurations of data models of an extension from a ParsedPartial.
        /// </summary>
        /// <param name="parsedFragment">The partially parsed extension.</param>
        /// <returns>The configurations of the extension</returns>
        public static List<Typo3ExtensionGenerator.Model.Configuration.Configuration> Resolve( Fragment parsedFragment )
        {
            IEnumerable<Fragment> configurationPartials = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclareConfiguration );
              if( !configurationPartials.Any() ) return null;

              List<Typo3ExtensionGenerator.Model.Configuration.Configuration> configurations = new List<Typo3ExtensionGenerator.Model.Configuration.Configuration>();
              foreach( Fragment configurationPartial in configurationPartials ) {
            Typo3ExtensionGenerator.Model.Configuration.Configuration configuration = new Typo3ExtensionGenerator.Model.Configuration.Configuration { Target = configurationPartial.Parameters };
            configurations.Add( configuration );
            if( configurationPartial.Fragments.Any() ) {
              foreach( Fragment configurationDirective in configurationPartial.Fragments ) {

            // Find configuration directives
            if( Keywords.ConfigurationDirectives.Label == configurationDirective.Keyword ) {
              configuration.Label = configurationDirective.Parameters;

            } else if( Keywords.ConfigurationDirectives.LabelAlternative == configurationDirective.Keyword ) {
              configuration.LabelAlternative = configurationDirective.Parameters;

            } else if( Keywords.ConfigurationDirectives.LabelHook == configurationDirective.Keyword ) {
              configuration.LabelHook = true;

            } else if( Keywords.ConfigurationDirectives.SearchFields == configurationDirective.Keyword ) {
              configuration.SearchFields = configurationDirective.Parameters;

            } else if( Keywords.ConfigurationDirectives.Thumbnail == configurationDirective.Keyword ) {
              configuration.Thumbnail = configurationDirective.Parameters;

            } else if( Keywords.ConfigurationDirectives.InterfaceInfo == configurationDirective.Keyword ) {
              configuration.InterfaceInfo = configurationDirective.Parameters;

            } else if( Keywords.ConfigurationDirectives.TypeDeclaration == configurationDirective.Keyword ) {
              configuration.Types.Add( TypeResolver.Resolve( configurationDirective ) );

            } else if( Keywords.ConfigurationDirectives.PaletteDeclaration == configurationDirective.Keyword ) {
              configuration.Palettes.Add( PaletteResolver.Resolve( configurationDirective ) );

            } else if( Keywords.DefineInterface == configurationDirective.Keyword ) {
              Typo3ExtensionGenerator.Model.Configuration.Interface.Interface @interface = InterfaceResolver.Resolve( configurationDirective );
              @interface.ParentModelTarget = configuration.Target;
              configuration.Interfaces.Add( @interface );

            } else if( Keywords.Title == configurationDirective.Keyword ) {
              configuration.Title = configurationDirective.Parameters;

            } else if( Keywords.ConfigurationDirectives.Visibility.Hidden == configurationDirective.Keyword ) {
              configuration.Hidden = true;

            }
              }
            }
              }

              return configurations;
        }
        /// <summary>
        /// Parses a ParsedPartial that should contain an extension definition.
        /// </summary>
        /// <param name="fragment"></param>
        /// <returns></returns>
        /// <exception cref="ParserException">Missing extension declaration.</exception>
        private static Extension Parse( Fragment fragment )
        {
            // The fragment MUST be an extension definition
              if( fragment.Header.Length < Keywords.DeclareExtension.Length || Keywords.DeclareExtension != fragment.Header.Substring( 0, Keywords.DeclareExtension.Length ) ) {
            throw new ParserException( "Missing extension declaration.", fragment.SourceDocument );
              }

              Extension result = ExtensionResolver.Resolve( fragment );
              result.SourceFragment = fragment;

              return result;
        }
        /// <summary>
        /// Resolves an extension model from a parsed fragment.
        /// </summary>
        /// <param name="parsedFragment"></param>
        /// <returns></returns>
        public static Typo3ExtensionGenerator.Model.Extension Resolve( Fragment parsedFragment )
        {
            string extensionKey = parsedFragment.Header.Substring(
            Keywords.DeclareExtension.Length, parsedFragment.Header.Length - Keywords.DeclareExtension.Length ).Trim();

              Typo3ExtensionGenerator.Model.Extension extension = new Typo3ExtensionGenerator.Model.Extension {
                                                                                                        Key     = extensionKey,
                                                                                                        Author  = Person.Someone,
                                                                                                        State   = "alpha",
                                                                                                        Version = "0.0.1"
                                                                                                      };

              foreach( Fragment extensionFragment in parsedFragment.Fragments ) {
            if( extensionFragment.Keyword == Keywords.ExtensionDirectives.DefineAuthor ) {
              extension.Author.Name = extensionFragment.Parameters;

            } else if( extensionFragment.Keyword == Keywords.ExtensionDirectives.DefineAuthorCompany ) {
              extension.Author.Company = extensionFragment.Parameters;

            } else if( extensionFragment.Keyword == Keywords.ExtensionDirectives.DefineAuthorEmail ) {
              extension.Author.Email = extensionFragment.Parameters;

            } else if( extensionFragment.Keyword == Keywords.Category ) {
              extension.Category = extensionFragment.Parameters;

            } else if( extensionFragment.Keyword == Keywords.Description ) {
              extension.Description = extensionFragment.Parameters;

            } else if( extensionFragment.Keyword == Keywords.Title ) {
              extension.Title = extensionFragment.Parameters;

            } else if( extensionFragment.Keyword == Keywords.ExtensionDirectives.State ) {
              extension.State = extensionFragment.Parameters;

            } else if( extensionFragment.Keyword == Keywords.ExtensionDirectives.Version ) {
              extension.Version = extensionFragment.Parameters;

            } else if( extensionFragment.Keyword == Keywords.ConfigurationDirectives.LabelHook ) {
              extension.LabelHookImplementation = extensionFragment.Parameters;
            }
              }
              extension.Configurations = ConfigurationResolver.Resolve( parsedFragment );
              extension.Models         = ModelResolver.Resolve( parsedFragment );
              extension.Modules        = ModuleResolver.Resolve( parsedFragment );
              extension.Plugins        = PluginResolver.Resolve( parsedFragment );
              extension.Repositories   = RepositoryResolver.Resolve( parsedFragment );
              extension.Requirements   = RequirementResolver.Resolve( parsedFragment );
              extension.Services       = ServiceResolver.Resolve( parsedFragment );
              extension.Tasks          = TaskResolver.Resolve( parsedFragment );

              return extension;
        }
        /// <summary>
        /// Resolves a type definition of data model configuration of an extension from a ParsedPartial.
        /// </summary>
        /// <param name="parsedFragment">The partially parsed extension.</param>
        /// <returns>The defined type.</returns>
        /// <exception cref="ParserException">Type does not define an interface.</exception>
        public static Typo3ExtensionGenerator.Model.Configuration.Type Resolve( Fragment parsedFragment )
        {
            // Check if the type defines an interface
              Fragment interfacePartial = parsedFragment.Fragments.SingleOrDefault( p => p.Keyword == Keywords.ConfigurationDirectives.InterfaceType );
              if( null == interfacePartial ) {
            string typeName = parsedFragment.Parameters;
            if( string.IsNullOrEmpty( typeName ) ) {
              typeName = "<unnamed>";
            }
            throw new ParserException( string.Format( "Type '{0}' does not define an interface.", typeName ), parsedFragment.SourceDocument );
              }

              Typo3ExtensionGenerator.Model.Configuration.Type parsedType = new Typo3ExtensionGenerator.Model.Configuration.Type {Interface = interfacePartial.Parameters, SourceFragment = interfacePartial};

              return parsedType;
        }
        public static Action ResolveAction( Fragment parsedFragment )
        {
            Action resultingAction = new Action {Name = parsedFragment.Parameters};
              foreach( Fragment actionDirective in parsedFragment.Fragments ) {
            if( actionDirective.Keyword == Keywords.Title ) {
              resultingAction.Title = actionDirective.Parameters;

            } else if( actionDirective.Keyword == Keywords.Requirement ) {
              resultingAction.Requirements.AddRange( actionDirective.Parameters.Split( new[] {','} ) );

            } else if( actionDirective.Keyword == Keywords.PluginDirectives.ActionDirectives.Uncachable ) {
              resultingAction.Uncachable = true;

            }
              }

              return resultingAction;
        }
        /// <summary>
        /// Resolves all tasks defined in a given parsed fragment.
        /// </summary>
        /// <param name="parsedFragment"></param>
        /// <returns></returns>
        /// <exception cref="ParserException">Task has no name!</exception>
        public static List<Task> Resolve( Fragment parsedFragment )
        {
            IEnumerable<Fragment> taskFragments = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclareTask );
              if( !taskFragments.Any() ) return null;

              List<Task> tasks = new List<Task>();
              foreach( Fragment taskFragment in taskFragments ) {
            // Construct the plugin with the given name
            Task task = new Task {Name = taskFragment.Parameters, SourceFragment = taskFragment};

            // Resolve task
            foreach( Fragment taskParameter in taskFragment.Fragments ) {
              if( taskParameter.Keyword == Keywords.Description ) {
            task.Description = taskParameter.Parameters;

              } else if( taskParameter.Keyword == Keywords.Title ) {
            task.Title = taskParameter.Parameters;

              } else if( taskParameter.Keyword == Keywords.Implementation ) {
            task.Implementation = taskParameter.Parameters;

              } else if( taskParameter.Keyword == Keywords.ServiceDirectives.AdditionalFields ) {
            task.AdditionalFieldsClass = taskParameter.Parameters;
            task.TaskFields = new TaskFields { Implementation = taskParameter.Parameters };
              }
            }

            // If no name was defined, throw
            if( string.IsNullOrEmpty( task.Name ) ) {
              throw new ParserException( "Service has no name!", parsedFragment.SourceDocument );
            }

            if( null != task.TaskFields ) {
              task.TaskFields.Name = task.Name;
            }

            tasks.Add( task );
              }

              return tasks;
        }
        /// <summary>
        /// Find an ExtBase SignalSlot listener in a parsed fragment and return it.
        /// </summary>
        /// <param name="parsedFragment"></param>
        /// <returns></returns>
        /// <exception cref="ParserException">Listener does not define a signal host or slot.</exception>
        public static Listener ResolveListener( Fragment parsedFragment )
        {
            Listener resultingListener = new Listener();
              resultingListener.TargetAction = ActionResolver.ResolveAction( parsedFragment );

              foreach( Fragment actionDirective in parsedFragment.Fragments ) {
            if( actionDirective.Keyword == Keywords.PluginDirectives.ActionDirectives.Host ) {
              resultingListener.Host = actionDirective.Parameters;

            } else if( actionDirective.Keyword == Keywords.PluginDirectives.ActionDirectives.Slot ) {
              resultingListener.Signal = actionDirective.Parameters;
            }
              }

              if( string.IsNullOrEmpty( resultingListener.Host ) ) {
            throw new ParserException( string.Format( "Listener '{0}' does not define a signal host.", parsedFragment.Parameters ), parsedFragment.SourceDocument );
              }
              if( string.IsNullOrEmpty( resultingListener.Signal ) ) {
            throw new ParserException( string.Format( "Listener '{0}' does not define a signal slot.", parsedFragment.Parameters ), parsedFragment.SourceDocument );
              }
              return resultingListener;
        }
        /// <summary>
        /// Resolves all services defined in a given parsed fragment.
        /// </summary>
        /// <param name="parsedFragment"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException">Defining ExtBase SignalSlot listeners in service classes is unsupported at this time.</exception>
        /// <exception cref="ParserException">Service has no name!</exception>
        public static List<Service> Resolve( Fragment parsedFragment )
        {
            IEnumerable<Fragment> serviceFragments = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclareService );
              if( !serviceFragments.Any() ) return null;

              List<Service> services = new List<Service>();
              foreach( Fragment serviceFragment in serviceFragments ) {
            // Construct the plugin with the given name
            Service service = new Service {Name = serviceFragment.Parameters, SourceFragment = serviceFragment};

            // Resolve service
            foreach( Fragment serviceParameter in serviceFragment.Fragments ) {
              if( serviceParameter.Keyword == Keywords.PluginDirectives.Action ) {
            Typo3ExtensionGenerator.Model.Action action = ActionResolver.ResolveAction( serviceParameter );
            service.Actions.Add( action );

              } else if( serviceParameter.Keyword == Keywords.PluginDirectives.Listener ) {
            Listener listener = ListenerResolver.ResolveListener( serviceParameter );
            service.Actions.Add( listener.TargetAction );
            throw new NotImplementedException( "Defining ExtBase SignalSlot listeners in service classes is unsupported at this time." );
            //service.Listeners.Add( listener );

              } else if( serviceParameter.Keyword == Keywords.Implementation ) {
            service.Implementation = serviceParameter.Parameters;
              }
            }

            // If no name was defined, throw
            if( string.IsNullOrEmpty( service.Name ) ) {
              throw new ParserException( "Service has no name!", parsedFragment.SourceDocument );
            }

            services.Add( service );
              }

              return services;
        }
        /// <summary>
        /// Resolves the modules of an extension from a ParsedPartial.
        /// </summary>
        /// <param name="parsedFragment">The partially parsed extension.</param>
        /// <returns>The plauings of the extension</returns>
        public static List<Typo3ExtensionGenerator.Model.Module> Resolve( Fragment parsedFragment )
        {
            IEnumerable<Fragment> modulePartials = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclareModule );
              if( !modulePartials.Any() ) return null;

              List<Typo3ExtensionGenerator.Model.Module> modules = new List<Typo3ExtensionGenerator.Model.Module>();
              foreach( Fragment modulePartial in modulePartials ) {
            Typo3ExtensionGenerator.Model.Module module = new Typo3ExtensionGenerator.Model.Module {Name = modulePartial.Parameters, SourceFragment = parsedFragment};

            foreach( Fragment subPartial in modulePartial.Fragments ) {
              if( subPartial.Keyword == Keywords.Category ) {
            module.MainModuleName = subPartial.Parameters;

              } else if( subPartial.Keyword == Keywords.Title ) {
            module.Title = subPartial.Parameters;

              } else if( subPartial.Keyword == Keywords.Implementation ) {
            module.Implementation = subPartial.Parameters;

              } else if( subPartial.Keyword == Keywords.PluginDirectives.Action ) {
            Action action = ActionResolver.ResolveAction( subPartial );
            module.Actions.Add( action );

              }
            }

            // If no name was defined, use the common placeholder names
            if( string.IsNullOrEmpty( module.Name ) ) {
              module.Name = string.Format( "M{0}", ( modules.Count + 1 ) );
            }

            modules.Add( module );
              }

              return modules;
        }
        /// <summary>
        /// Parses a virtual document into a parsed fragment.
        /// </summary>
        /// <param name="document">The virtual document that should be parsed.</param>
        /// <returns></returns>
        public static Fragment ParseFragment( VirtualDocument document )
        {
            DocumentWalker walker = new DocumentWalker( document );

              // The currently collected scope body
              string body = String.Empty;

              // Sub-scopes which we'll find during parsing will be stored in this partial.
              Fragment result = new Fragment {
                                       Body           = string.Empty,
                                       Header         = string.Empty,
                                       SourceDocument = document
                                     };

              // How deeply nested we are into scopes.
              int scopeLevel  = 0;
              // Where the scope we're currently recording started.
              VirtualDocument.Character scopeStart = walker.CurrentCharacter;
              // Are we currently inside a string?
              bool inString = false;
              // Is the current character escaped?
              bool isEscaped = false;
              // Are we currently inside a comment?
              bool inComment = false;
              // The line where a comment was started
              int commentStart = 0;

              // Iterate over the whole input string
              // The whole point of this operation is to collect the full header of the partial,
              // as well as the full body of the partial.
              // If, while parsing the body of the partial, we find nested scopes, we'll store those to parse them later.
              while( walker.CanWalk ) {
            if( !inString ) {
              // Check for scope terminator
              if( walker.CurrentlyReads( Syntax.ScopeTerminate ) ) {
            // Did we find a scope terminator? Like: ;
            if( 1 == scopeLevel ) {
              // As long as we're on the first scope level, we can collect the body of scopes to parse them later.
              // If we're deeper nested, there's no point, we'll parse those when we recurse.

              // Construct a new document for the currently recorded scope.
              VirtualDocument documentFragment = VirtualDocument.FromDocument( document, scopeStart, walker.CurrentCharacter );

              // ...and store it.
              result.Fragments.Add( new Fragment {Body = body.Trim(), SourceDocument = documentFragment} );
              result.Body += walker.CurrentCharacter;

              // Clear buffer
              body = string.Empty;

              // We skip ahead until we see a character again. We need those as markers.
              try {
                walker.WalkToNext();
              } catch( ArgumentOutOfRangeException ) {
                // Things can always go wrong when running!
                break;
              }
              // Set the current location as the new recording start point
              scopeStart = walker.CurrentCharacter;

              continue;
            }
            if( 0 == scopeLevel ) {
              // If we're on the root level, just increase the scope pointer and skip.
              walker.Walk();
              continue;
            }
              }

              // Check for scopes
              if( walker.CurrentlyReads( Syntax.ScopeStart ) ) {
            // Did we find the start of a new scope?
            ++scopeLevel;

            if( 1 == scopeLevel ) {
              // If we're on the root level (we are, because we just increased the scopeLevel), we need to skip ahead.
              walker.Walk();
              scopeStart = walker.CurrentCharacter;
              continue;
            }
            if( 2 == scopeLevel ) {
              //scopeStart = walker.CurrentCharacter;
            }

              } else if( walker.CurrentlyReads( Syntax.ScopeEnd ) ) {
            --scopeLevel;
            // Did we find the end of a scope?
            if( 1 == scopeLevel ) {
              // Great! Another temporary scope we can store for later
              body += walker.CurrentCharacter;
              result.Fragments.Add(
                new Fragment {
                               Body = body.Trim(),
                               SourceDocument =
                                 VirtualDocument.FromDocument( document, scopeStart, walker.CurrentCharacter )
                             } );
              result.Body += walker.CurrentCharacter;
              // Clear buffer
              body = string.Empty;

              // We skip ahead until we see a character again. We need those as markers.
              try {
                walker.WalkToNext();
              } catch( ArgumentOutOfRangeException ) {
                // Things can always go wrong when running!
                break;
              }
              // Set the current location as the new recording start point
              scopeStart = walker.CurrentCharacter;

              continue;
            }
            if( 0 == scopeLevel ) {
              // If we're on the root level, just increase the scope pointer and skip.
              try {
                walker.Walk();
              } catch( ArgumentOutOfRangeException ){}

              continue;
            }
              }

              // Check for string delimiter
              if( walker.CurrentlyReads( Syntax.StringDelimiter ) ) {
            // Did we hit a string delimiter? Like: "
            inString = true;
              }

              // Check for comment
              try {
            //if( characterPointer + Syntax.CommentMultilineStart.Length <= element.Length && Syntax.CommentMultilineStart == element.Substring( characterPointer, Syntax.CommentMultilineStart.Length ) ) {
            if( walker.CurrentlyReads( Syntax.CommentMultilineStart ) ) {

              inComment    = true;
              commentStart = walker.CurrentLine.PhysicalLineIndex;
              // Skip ahead until comment is terminated
              while( walker.CanWalk && inComment ) {
                walker.Walk();
                if( walker.CurrentlyReads( Syntax.CommentMultilineEnd ) ) {
                  walker.Walk( Syntax.CommentMultilineEnd.Length );

                  inComment    = false;
                  commentStart = 0;
                }

              }
            } else if( walker.CurrentlyReads( Syntax.CommentSinglelineStart ) ) {
              // Skip ahead until comment is terminated
              // Single line comments are terminated by newline.
              while( walker.CanWalkForward ) {
                walker.Walk();
              }
              // We walked to the end of the line, no we skip to the next one
              walker.Walk();
              commentStart = 0;

            }
              } catch( ArgumentOutOfRangeException ex ) {
            throw new ParserException( string.Format( "Hit end of input while looking for end of comment which started on line {0}.", commentStart ), walker.Document );
              }

            } else {

              // This is when we're parsing within a string.

              if( walker.CurrentlyReads( Syntax.StringEscape ) ) {
            // Did we find an escape sequence? Like: \"
            isEscaped = true;
            walker.Walk();
              }
              if( !isEscaped && walker.CurrentlyReads( Syntax.StringDelimiter ) ) {
            // Did the string end?
            inString = false;
              }
            }

            // Decide if we're currently parsing a header or a body and store accordingly.
            if( 0 == scopeLevel && walker.CanWalk ) {
              // Store in persitent result
              result.Header += walker.CurrentCharacter;
            } else {
              // Store in persistent result
              result.Body += walker.CurrentCharacter;
              // Also store in temporary buffer
              body += walker.CurrentCharacter;
            }

            isEscaped = false;
            Debug.Assert( walker.CanWalk, "Tried to walk when it's not possible" );
            walker.Walk();
              }

              result.Header = result.Header.Trim();
              result.Body   = result.Body.Trim();

              if( inString ) {
            throw new ParserException( string.Format( "Unmatched \" in {0}", result.Body ), walker.Document );
              }

              // Recurse to resolve all previously parsed fragments
              foreach( Fragment childFragment in result.Fragments ) {
            Fragment fragment = ParseFragment( childFragment.SourceDocument );

            childFragment.Header    = fragment.Header;
            childFragment.Body      = fragment.Body;
            childFragment.Fragments = fragment.Fragments;

            // Pull keyword from header
            int delimiterPosition = childFragment.Header.IndexOf( ' ' );
            if( 0 > delimiterPosition ) delimiterPosition = childFragment.Header.Length;
            childFragment.Keyword = childFragment.Header.Substring( 0, delimiterPosition ).Trim();

            // The remaining part of the header would now be the parameters
            childFragment.Parameters = childFragment.Header.Substring( childFragment.Keyword.Length ).Trim();

            // Is the parameter set in ""?
            if( !string.IsNullOrEmpty( childFragment.Parameters ) && "\"" == childFragment.Parameters.Substring( 0, 1 ) ) {
              if( "\"" != childFragment.Parameters.Substring( childFragment.Parameters.Length -1, 1 ) ) {
            throw new ParserException( string.Format( "Unmatched \" in {0}", childFragment.Header ), walker.Document );
              }
              childFragment.Parameters = childFragment.Parameters.Substring( 1, childFragment.Parameters.Length - 2 );
            }
              }

              return result;
        }
        /// <summary>
        /// Resolves the models of an extension from a ParsedPartial.
        /// </summary>
        /// <param name="parsedFragment">The partially parsed extension.</param>
        /// <returns>The models of the extension</returns>
        /// <exception cref="GeneratorException">The given requirement root does not exist.</exception>
        public static List<Requirement> Resolve( Fragment parsedFragment )
        {
            IEnumerable<Fragment> requirementFragments = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.Requirement );
              if( !requirementFragments.Any() ) return null;

              List<Requirement> requirements = new List<Requirement>();
              foreach( Fragment requirementFragment in requirementFragments ) {
            Requirement requirement = new Requirement {
                                                    SourceFolder   = requirementFragment.Parameters,
                                                    SourceFragment = requirementFragment
                                                  };
            requirements.Add( requirement );

            if( requirementFragment.Fragments.Any() ) {
              foreach( Fragment fileFilter in requirementFragment.Fragments ) {
            requirement.SourceFilter.Add( ParseHelper.UnwrapString( fileFilter.Keyword ) );
              }
            }
              }

              foreach( Requirement requirement in requirements ) {
            // If the requirement root does not exist, throw
            if( !Directory.Exists( requirement.SourceFolder ) ) {
              throw new GeneratorException( string.Format( "The given requirement root '{0}' does not exist.", requirement.SourceFolder ), requirement.SourceFragment.SourceDocument );
            }

            // Find files in the requirement root
            DirectoryInfo sourceDirectory = new DirectoryInfo( requirement.SourceFolder );
            string currentPath = string.Empty;

            // Iterate over all defined filters in the requirement
            foreach( string sourceFilter in requirement.SourceFilter ) {
              DirectoryInfo searchRoot = sourceDirectory;
              currentPath = string.Empty;

              // Extract folder from filter and adjust filter expression.
              string filter = sourceFilter;
              if( sourceFilter.Contains( "/" ) ) {
            currentPath = sourceFilter.Substring( 0, sourceFilter.LastIndexOf( '/' ) + 1 );
            string activePath = Path.Combine( requirement.SourceFolder, currentPath );

            searchRoot = new DirectoryInfo( activePath );
            filter = sourceFilter.Substring( sourceFilter.LastIndexOf( '/' ) + 1 );
              }

              // Add all matched
              try {
            FileInfo[] files = searchRoot.GetFiles( filter );
            // Convert filenames to RequiredFile instances
            requirement.Files.AddRange(
              files.Select(
                s => new Requirement.RequiredFile {FullSourceName = s.FullName, RelativeTargetName = currentPath + s.Name} ) );

              } catch( DirectoryNotFoundException e ) {
            throw new ParserException( e.Message, parsedFragment.SourceDocument );
              }
            }

              }

              return requirements;
        }
        public static void Resolve( Fragment parsedFragment, Typo3ExtensionGenerator.Model.Configuration.Interface.Interface @interface, string displayType )
        {
            if( Keywords.ConfigurationDirectives.InterfaceDirectives.Representations.FileReference == displayType ) {
            SpecializedDisplayType specializedDisplayType = new SpecializedDisplayType {
                                                                                     Name = Keywords.ConfigurationDirectives.InterfaceDirectives.Representations.RecordGroup,
                                                                                     SourceFragment = parsedFragment
                                                                                   };

            specializedDisplayType.Set( "internal_type", "file_reference" );
            specializedDisplayType.Set( "allowed", "*" );
            specializedDisplayType.Set( "disallowed", "php" );
            specializedDisplayType.Set( "size", 5 );
            specializedDisplayType.Set( "maxitems", 99 );

            // If this field requires anything, it should have at least 1 item.
            if( @interface.Settings.Any( s => s.Key == Keywords.Requirement ) ) {
              specializedDisplayType.Set( "minitems", 1 );
            } else {
              specializedDisplayType.Set( "minitems", 0 );
            }

            @interface.DisplayType = specializedDisplayType;

              } else if( Keywords.ConfigurationDirectives.InterfaceDirectives.Representations.RecordGroup == displayType ) {
            RecordGroupDisplayType recordGroupDisplayType = new RecordGroupDisplayType {
                                                                                     Name = Keywords.ConfigurationDirectives.InterfaceDirectives.Representations.RecordGroup,
                                                                                     SourceFragment = parsedFragment
                                                                                   };

            // Show records next to select box
            recordGroupDisplayType.ShowThumbnails = true;
            // Increase list length
            recordGroupDisplayType.Lines = 10;
            // Increase list width
            recordGroupDisplayType.SelectedListStyle = "width:400px";
            // Don't allow duplicates
            recordGroupDisplayType.AllowDuplicates = false;
            // Set item limit
            recordGroupDisplayType.MaxItems = 99;

            // If this field requires anything, it should have at least 1 item.
            if( @interface.Settings.Any( s => s.Key == Keywords.Requirement ) ) {
              recordGroupDisplayType.MinItems = 1;
            } else {
              recordGroupDisplayType.MinItems = 0;
            }

            // The model type for the suggest wizard is resolved during generation later.
            recordGroupDisplayType.Set( "wizards.RTE.type", "suggest" );

            @interface.DisplayType = recordGroupDisplayType;

              } else if( Keywords.ConfigurationDirectives.InterfaceDirectives.Representations.RichTextArea == displayType ) {
            SpecializedDisplayType specializedDisplayType = new SpecializedDisplayType() {
                                                                                       Name = Keywords.ConfigurationDirectives.InterfaceDirectives.Representations.TextArea,
                                                                                       SourceFragment = parsedFragment
                                                                                     };

            specializedDisplayType.Set( "wizards.RTE.icon", "wizard_rte2.gif" );
            specializedDisplayType.Set( "wizards.RTE.notNewRecords", 1 );
            specializedDisplayType.Set( "wizards.RTE.RTEonly", 1 );
            specializedDisplayType.Set( "wizards.RTE.script", "wizard_rte.php" );
            specializedDisplayType.Set( "wizards.RTE.title", "LLL:EXT:cms/locallang_ttc.xml:bodytext.W.RTE" );
            specializedDisplayType.Set( "wizards.RTE.type", "script" );

            @interface.DisplayType = specializedDisplayType;

            // Add a new property to the interface itself, to enable rich text editing.
            @interface.Set( "defaultExtras", "richtext[]" );

              } else {
            // Could not determine proper display type, use user supplied intput
            @interface.DisplayType = new DisplayType {Name = @interface.DisplayTypeTarget};
              }
        }