class TemplateModel implements IModel {

    final IEngineConfiguration configuration;
    final TemplateData templateData;
    final IEngineTemplateEvent[] queue; // This is final because this IModel is IMMUTABLE


    // Package-protected constructor, because we don't want anyone creating these objects from outside the engine.
    // If a processor (be it standard or custom-made) wants to create a piece of model, that should be a Model
    // object, not this.
    TemplateModel(
            final IEngineConfiguration configuration, final TemplateData templateData,
            final IEngineTemplateEvent[] queue) {
        
        super();
        
        Validate.notNull(configuration, "Engine Configuration cannot be null");
        Validate.notNull(templateData, "Template Resolution cannot be null");
        Validate.notNull(queue, "Event queue cannot be null");
        Validate.isTrue(queue.length >= 2, "At least TemplateStart/TemplateEnd events must be added to a TemplateModel");
        Validate.isTrue(queue[0] == TemplateStart.TEMPLATE_START_INSTANCE, "First event in queue is not TemplateStart");
        Validate.isTrue(queue[queue.length - 1] == TemplateEnd.TEMPLATE_END_INSTANCE, "Last event in queue is not TemplateEnd");

        this.configuration = configuration;
        this.templateData = templateData;
        this.queue = queue;

    }


    public final TemplateData getTemplateData() {
        return this.templateData;
    }


    public final IEngineConfiguration getConfiguration() {
        return this.configuration;
    }


    public final TemplateMode getTemplateMode() {
        return this.templateData.getTemplateMode();
    }



    public final int size() {
        return this.queue.length;
    }


    public final ITemplateEvent get(final int pos) {
        return this.queue[pos];
    }


    public final void add(final ITemplateEvent event) {
        immutableModelException();
    }


    public final void insert(final int pos, final ITemplateEvent event) {
        immutableModelException();
    }


    public final void replace(final int pos, final ITemplateEvent event) {
        immutableModelException();
    }


    public final void addModel(final IModel model) {
        immutableModelException();
    }


    public final void insertModel(final int pos, final IModel model) {
        immutableModelException();
    }


    public final void remove(final int pos) {
        immutableModelException();
    }


    public final void reset() {
        immutableModelException();
    }




    void process(final ITemplateHandler handler) {
        for (int i = 0; i < this.queue.length; i++) {
            this.queue[i].beHandled(handler);
        }
    }


    int process(final ITemplateHandler handler, final int offset, final TemplateFlowController controller) {

        if (controller == null) {
            process(handler);
            return this.queue.length;
        }

        if (this.queue.length == 0 || offset >= this.queue.length) {
            return 0;
        }

        int processed = 0;

        for (int i = offset; i < this.queue.length && !controller.stopProcessing; i++) {
            this.queue[i].beHandled(handler);
            processed++;
        }

        return processed;

    }




    public final IModel cloneModel() {
        return new Model(this);
    }




    public final void write(final Writer writer) throws IOException {
        for (int i = 0; i < this.queue.length; i++) {
            this.queue[i].write(writer);
        }
    }




    public void accept(final IModelVisitor visitor) {
        for (int i = 0; i < this.queue.length; i++) {
            // We will execute the visitor on the Immutable events, that we need to create during the visit
            this.queue[i].accept(visitor);
        }
    }



    @Override
    public final String toString() {
        try {
            final Writer writer = new FastStringWriter();
            write(writer);
            return writer.toString();
        } catch (final IOException e) {
            throw new TemplateProcessingException(
                    "Error while creating String representation of model");
        }
    }




    private static void immutableModelException() {<FILL_FUNCTION_BODY>}


}

        throw new UnsupportedOperationException(
                "Modifications are not allowed on immutable model objects. This model object is an immutable " +
                "implementation of the " + IModel.class.getName() + " interface, and no modifications are allowed in " +
                "order to keep cache consistency and improve performance. To modify model events, convert first your " +
                "immutable model object to a mutable one by means of the " + IModel.class.getName() + "#cloneModel() method");
    
<no_super_class>