class AbstractAnalyzer extends Analyzer {

    public static final Reader DUMMY_READER = new StringReader("");
    protected AnalyzerFactory factory;
    protected Supplier<JFlexTokenizer> symbolTokenizerFactory;
    protected Project project;
    protected Ctags ctags;
    protected NumLinesLOCAggregator countsAggregator;
    protected boolean scopesEnabled;
    protected boolean foldingEnabled;

    protected AbstractAnalyzer(ReuseStrategy reuseStrategy) {
        super(reuseStrategy);
    }

    /**
     * Subclasses should override to return the case-insensitive name aligning
     * with either a built-in Universal Ctags language name or an OpenGrok
     * custom language name.
     * @return a defined instance or {@code null} if the analyzer has no aligned
     * Universal Ctags language
     */
    public abstract String getCtagsLang();

    public abstract long getVersionNo();

    /**
     * Subclasses should override to produce a value relevant for the evolution
     * of their analysis in each release.
     *
     * @return 0 since {@link AbstractAnalyzer} is not specialized
     */
    protected int getSpecializedVersionNo() {
        return 0;
    }

    public void setCtags(Ctags ctags) {
        this.ctags = ctags;
    }

    public void setCountsAggregator(NumLinesLOCAggregator countsAggregator) {
        this.countsAggregator = countsAggregator;
    }

    public void setProject(Project project) {
        this.project = project;
    }

    public void setScopesEnabled(boolean scopesEnabled) {
        this.scopesEnabled = supportsScopes() && scopesEnabled;
    }

    public void setFoldingEnabled(boolean foldingEnabled) {
        this.foldingEnabled = supportsScopes() && foldingEnabled;
    }

    protected abstract boolean supportsScopes();

    /**
     * Get the factory which created this analyzer.
     *
     * @return the {@code FileAnalyzerFactory} which created this analyzer
     */
    public final AnalyzerFactory getFactory() {
        return factory;
    }

    public AbstractAnalyzer.Genre getGenre() {
        return factory.getGenre();
    }

    public abstract String getFileTypeName();

    public abstract void analyze(Document doc, StreamSource src, Writer xrefOut)
            throws IOException, InterruptedException;

    public abstract Xrefer writeXref(WriteXrefArgs args) throws IOException;

    @Override
    protected abstract TokenStreamComponents createComponents(String fieldName);

    @Override
    protected abstract TokenStream normalize(String fieldName, TokenStream in);

    /**
     * Subclasses must override to incorporate a determined number of lines and
     * lines-of-code (LOC).
     * @param doc Document instance
     * @param counts NumLinesLOC instance
     */
    protected abstract void addNumLinesLOC(Document doc, NumLinesLOC counts);

    /**
     * What kind of file is this?
     */
    public enum Genre {
        /**
         * xrefed - line numbered context.
         */
        PLAIN("p"),
        /**
         * xrefed - summarizer context.
         */
        XREFABLE("x"),
        /**
         * not xrefed - no context - used by diff/list.
         */
        IMAGE("i"),
        /**
         * not xrefed - no context.
         */
        DATA("d"),
        /**
         * not xrefed - summarizer context from original file.
         */
        HTML("h");
        private final String typeName;

        Genre(String typename) {
            this.typeName = typename;
        }

        /**
         * Get the type name value used to tag lucene documents.
         *
         * @return a none-null string.
         */
        public String typeName() {
            return typeName;
        }

        /**
         * Get the Genre for the given type name.
         *
         * @param typeName name to check
         * @return {@code null} if it doesn't match any genre, the genre
         * otherwise.
         * @see #typeName()
         */
        public static Genre get(String typeName) {<FILL_FUNCTION_BODY>}
    }
}

            if (typeName == null) {
                return null;
            }
            for (Genre g : values()) {
                if (g.typeName.equals(typeName)) {
                    return g;
                }
            }
            return null;
        
<no_super_class>