/*
 * FindBugs - Find Bugs in Java programs
 * Copyright (C) 2006, University of Maryland
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA
 */

package edu.umd.cs.findbugs.sourceViewer;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Toolkit;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
import javax.swing.text.TabSet;
import javax.swing.text.TabStop;

import edu.umd.cs.findbugs.ba.SourceFile;
import edu.umd.cs.findbugs.gui2.Debug;
import edu.umd.cs.findbugs.gui2.Driver;
import edu.umd.cs.findbugs.gui2.GUISaveState;

public class JavaSourceDocument {

    static final SimpleAttributeSet commentAttributes = new SimpleAttributeSet();

    static final SimpleAttributeSet javadocAttributes = new SimpleAttributeSet();

    static final SimpleAttributeSet quotesAttributes = new SimpleAttributeSet();

    static final SimpleAttributeSet keywordsAttributes = new SimpleAttributeSet();

    static final SimpleAttributeSet whiteAttributes = new SimpleAttributeSet();

    static Font sourceFont = new Font("Monospaced", Font.PLAIN, (int) Driver.getFontSize());

    final static Color HIGHLIGHT_COLOR = new Color(1f, 1f, .3f);

    TabSet TAB_SET;
    static {
        commentAttributes.addAttribute(StyleConstants.Foreground, new Color(0.0f, 0.5f, 0.0f));
        javadocAttributes.addAttribute(StyleConstants.Foreground, new Color(0.25f, 0.37f, 0.75f));
        quotesAttributes.addAttribute(StyleConstants.Foreground, new Color(0.0f, 0.0f, 1.0f));
        keywordsAttributes.addAttribute(StyleConstants.Foreground, new Color(0.5f, 0.0f, 0.5f));
        keywordsAttributes.addAttribute(StyleConstants.Bold, true);

    }

    final HighlightInformation highlights = new HighlightInformation();

    final NumberedEditorKit dek = new NumberedEditorKit(highlights);

    final StyleContext styleContext = new StyleContext();

    final Element root;

    final DefaultStyledDocument doc;

    final SourceFile sourceFile;

    public HighlightInformation getHighlightInformation() {
        return highlights;
    }

    public StyledDocument getDocument() {
        return doc;
    }

    public NumberedEditorKit getEditorKit() {
        return dek;
    }

    private final String title;

    public String getTitle() {
        return title;
    }

    public SourceFile getSourceFile() {
        return sourceFile;
    }

    public JavaSourceDocument(String title, Reader in, SourceFile theSource) throws IOException {
        doc = new DefaultStyledDocument();
        this.title = title;
        this.sourceFile = theSource;
        Debug.println("Created JavaSourceDocument for " + title);
        try {
            dek.read(in, doc, 0);
        } catch (BadLocationException e) {
            throw new RuntimeException(e);
        }
        in.close();
        doc.putProperty(Document.TitleProperty, title);
        root = doc.getDefaultRootElement();
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        FontMetrics fontMetrics = toolkit.getFontMetrics(sourceFont);
        TabStop[] tabs = new TabStop[50];
        float width = fontMetrics.stringWidth(" ");

        int tabSize = GUISaveState.getInstance().getTabSize();
        for (int i = 0; i < tabs.length; i++)
            tabs[i] = new TabStop(width * (tabSize + tabSize * i));
        TAB_SET = new TabSet(tabs);
        StyleConstants.setTabSet(commentAttributes, TAB_SET);
        StyleConstants.setTabSet(javadocAttributes, TAB_SET);

        StyleConstants.setTabSet(quotesAttributes, TAB_SET);

        StyleConstants.setTabSet(keywordsAttributes, TAB_SET);

        StyleConstants.setTabSet(commentAttributes, TAB_SET);

        StyleConstants.setTabSet(whiteAttributes, TAB_SET);
        StyleConstants.setFontFamily(whiteAttributes, sourceFont.getFamily());
        StyleConstants.setFontSize(whiteAttributes, sourceFont.getSize());
        StyleConstants.setLeftIndent(whiteAttributes, NumberedParagraphView.NUMBERS_WIDTH);

        doc.setParagraphAttributes(0, doc.getLength(), whiteAttributes, true);
        JavaScanner parser = new JavaScanner(new DocumentCharacterIterator(doc));
        while (parser.next() != JavaScanner.EOF) {
            int kind = parser.getKind();
            switch (kind) {
            case JavaScanner.COMMENT:
                doc.setCharacterAttributes(parser.getStartPosition(), parser.getLength(), commentAttributes, true);

                break;
            case JavaScanner.KEYWORD:
                doc.setCharacterAttributes(parser.getStartPosition(), parser.getLength(), keywordsAttributes, true);

                break;
            case JavaScanner.JAVADOC:
                doc.setCharacterAttributes(parser.getStartPosition(), parser.getLength(), javadocAttributes, true);

                break;
            case JavaScanner.QUOTE:
                doc.setCharacterAttributes(parser.getStartPosition(), parser.getLength(), quotesAttributes, true);

                break;
            }

        }

    }

    private static final long serialVersionUID = 0L;

    public static final JavaSourceDocument UNKNOWNSOURCE;
    static {
        try {
            UNKNOWNSOURCE = new JavaSourceDocument("Unknown source", new StringReader("Unable to find source"), null);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
