class AbstractGatheringModelProcessable implements IGatheringModelProcessable {


    private final ProcessorTemplateHandler processorTemplateHandler;
    private final IEngineContext context;
    private final Model syntheticModel;
    private final TemplateModelController modelController;
    private final TemplateFlowController flowController;

    private final SkipBody buildTimeSkipBody;
    private final boolean buildTimeSkipCloseTag;

    private final ProcessorExecutionVars processorExecutionVars;

    private boolean gatheringFinished = false;

    private int modelLevel;


    AbstractGatheringModelProcessable(
            final IEngineConfiguration configuration, final ProcessorTemplateHandler processorTemplateHandler, final IEngineContext context,
            final TemplateModelController modelController, final TemplateFlowController flowController,
            final SkipBody buildTimeSkipBody, final boolean buildTimeSkipCloseTag,
            final ProcessorExecutionVars processorExecutionVars) {

        super();

        this.processorTemplateHandler = processorTemplateHandler;
        this.context = context;
        this.modelController = modelController;
        this.flowController = flowController;
        this.buildTimeSkipBody = buildTimeSkipBody;
        this.buildTimeSkipCloseTag = buildTimeSkipCloseTag;

        if (this.context == null) {
            throw new TemplateProcessingException(
                    "Neither iteration nor model gathering are supported because local variable support is DISABLED. " +
                    "This is due to the use of an implementation of the " + ITemplateContext.class.getName() + " interface " +
                    "that does not provide local-variable support. In order to have local-variable support, the context " +
                    "implementation should also implement the " + IEngineContext.class.getName() +
                    " interface");
        }

        this.syntheticModel = new Model(configuration, context.getTemplateMode());
        this.processorExecutionVars = processorExecutionVars.cloneVars();
        this.gatheringFinished = false;
        this.modelLevel = 0;
    }


    public final void resetGatheredSkipFlagsAfterNoIterations() {
        if (this.buildTimeSkipBody == SkipBody.PROCESS_ONE_ELEMENT) {
            this.modelController.skip(SkipBody.SKIP_ELEMENTS, this.buildTimeSkipCloseTag);
        } else {
            this.modelController.skip(this.buildTimeSkipBody, this.buildTimeSkipCloseTag);
        }
    }

    public final void resetGatheredSkipFlags() {
        this.modelController.skip(this.buildTimeSkipBody, this.buildTimeSkipCloseTag);
    }


    protected final void prepareProcessing() {
        this.processorTemplateHandler.setCurrentGatheringModel(this);
        resetGatheredSkipFlags();
    }


    protected final ProcessorTemplateHandler getProcessorTemplateHandler() {
        return this.processorTemplateHandler;
    }

    protected final TemplateFlowController getFlowController() {
        return this.flowController;
    }


    public final boolean isGatheringFinished() {
        return this.gatheringFinished;
    }



    protected final IEngineContext getContext() {
        return this.context;
    }



    public ProcessorExecutionVars initializeProcessorExecutionVars() {
        // This was cloned during construction
        return this.processorExecutionVars;
    }




    public final Model getInnerModel() {
        return this.syntheticModel;
    }





    public final void gatherText(final IText text) {<FILL_FUNCTION_BODY>}


    public final void gatherComment(final IComment comment) {
        if (this.gatheringFinished) {
            throw new TemplateProcessingException("Gathering is finished already! We cannot gather more events");
        }
        this.syntheticModel.add(comment);
    }


    public final void gatherCDATASection(final ICDATASection cdataSection) {
        if (this.gatheringFinished) {
            throw new TemplateProcessingException("Gathering is finished already! We cannot gather more events");
        }
        this.syntheticModel.add(cdataSection);
    }


    public final void gatherStandaloneElement(final IStandaloneElementTag standaloneElementTag) {
        if (this.gatheringFinished) {
            throw new TemplateProcessingException("Gathering is finished already! We cannot gather more events");
        }
        this.syntheticModel.add(standaloneElementTag);
        if (this.modelLevel == 0) {
            this.gatheringFinished = true;
        }
    }


    public final void gatherOpenElement(final IOpenElementTag openElementTag) {
        if (this.gatheringFinished) {
            throw new TemplateProcessingException("Gathering is finished already! We cannot gather more events");
        }
        this.syntheticModel.add(openElementTag);
        this.modelLevel++;
    }


    public final void gatherCloseElement(final ICloseElementTag closeElementTag) {
        if (closeElementTag.isUnmatched()) {
            gatherUnmatchedCloseElement(closeElementTag);
            return;
        }
        if (this.gatheringFinished) {
            throw new TemplateProcessingException("Gathering is finished already! We cannot gather more events");
        }
        this.modelLevel--;
        this.syntheticModel.add(closeElementTag);
        if (this.modelLevel == 0) {
            // OK, we are finished gathering, this close tag ends the process
            this.gatheringFinished = true;
        }
    }


    public final void gatherUnmatchedCloseElement(final ICloseElementTag closeElementTag) {
        if (this.gatheringFinished) {
            throw new TemplateProcessingException("Gathering is finished already! We cannot gather more events");
        }
        this.syntheticModel.add(closeElementTag);
    }


    public final void gatherDocType(final IDocType docType) {
        if (this.gatheringFinished) {
            throw new TemplateProcessingException("Gathering is finished already! We cannot gather more events");
        }
        this.syntheticModel.add(docType);
    }


    public final void gatherXMLDeclaration(final IXMLDeclaration xmlDeclaration) {
        if (this.gatheringFinished) {
            throw new TemplateProcessingException("Gathering is finished already! We cannot gather more events");
        }
        this.syntheticModel.add(xmlDeclaration);
    }


    public final void gatherProcessingInstruction(final IProcessingInstruction processingInstruction) {
        if (this.gatheringFinished) {
            throw new TemplateProcessingException("Gathering is finished already! We cannot gather more events");
        }
        this.syntheticModel.add(processingInstruction);
    }

    
}

        if (this.gatheringFinished) {
            throw new TemplateProcessingException("Gathering is finished already! We cannot gather more events");
        }
        this.syntheticModel.add(text);
    
<no_super_class>