class DefaultTemplateContainer implements TemplateContainer {

    private void parseTemplate(final InputStream templateStream) {
        try {
            final ColumnFactory cf = new ColumnFactory();
            final BufferedReader templateReader = new BufferedReader(
                    new InputStreamReader(templateStream, IoUtils.UTF8_CHARSET));
            String line;

            boolean inTemplate = false;
            boolean inHeader = false;
            boolean inContents = false;
            boolean inMultiLineComment = false;

            RuleTemplate template = null;
            StringBuilder header = new StringBuilder();
            StringBuilder contents = new StringBuilder();

            while ((line = templateReader.readLine()) != null) {

                if (inMultiLineComment) {
                    int commentEnd = line.indexOf( "*/" );
                    if (commentEnd >= 0) {
                        line = line.substring( commentEnd+2 );
                        inMultiLineComment = false;
                    } else {
                        line = "";
                    }
                } else {
                    int commentStart = line.indexOf( "/*" );
                    if (commentStart >= 0) {
                        int commentEnd = line.indexOf( "*/" );
                        if (commentEnd > commentStart) {
                            line = line.substring( 0, commentStart ) + line.substring( commentEnd+2 );
                        } else {
                            line = line.substring( 0, commentStart );
                            inMultiLineComment = true;
                        }
                    }
                }

                String trimmed = line.trim();
                if (trimmed.length() > 0) {
                    if (trimmed.startsWith("template header")) {
                        inHeader = true;

                    } else if (trimmed.startsWith("template ")) {
                        inTemplate = true;
                        inHeader = false;
                        String quotedName = trimmed.substring(8).trim();
                        quotedName = quotedName.substring(1, quotedName.length() - 1);
                        template = new RuleTemplate(quotedName, this, replaceOptionals );
                        addTemplate(template);

                    } else if (trimmed.startsWith("package ")) {
                        if ( !inHeader ) {
                            throw new DecisionTableParseException(
                                    "Missing header");
                        }
                        inHeader = false;
                        header.append(line).append("\n");

                    } else if (trimmed.startsWith("import ")) {
                        inHeader = false;
                        header.append(line).append("\n");

                    } else if (inHeader) {
                        addColumn(cf.getColumn(trimmed));

                    } else if (!inTemplate) {
                        header.append(line).append("\n");

                    } else if (!inContents && trimmed.startsWith("rule ")) {
                        inContents = true;
                        contents.append(line).append("\n");

                    } else if (trimmed.equals("end template")) {
                        template.setContents(contents.toString());
                        contents.setLength(0);
                        inTemplate = false;
                        inContents = false;

                    } else if (inContents) {
                        contents.append(removeSingleLineComment(line)).append( "\n");

                    } else {
                        template.addColumn(trimmed);
                    }
                }

            }
            if (inTemplate) {
                throw new DecisionTableParseException("Missing end template");
            }
            this.header = header.toString();

        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (templateStream != null) { closeStream(templateStream); }
        }
    }

    public  DefaultTemplateContainer(final String template);
    public  DefaultTemplateContainer(final InputStream templateStream);
    public  DefaultTemplateContainer(final String template, boolean replaceOptionals);
    public  DefaultTemplateContainer(final InputStream templateStream, boolean replaceOptionals);

}