package com.uvigo.mhp.util;

import java.util.HashMap;

public class CodeViewer
{
    public CodeViewer()
    {
        inMultiLineComment = false;
        backgroundColor = "#ffffff";
        commentStart = "</font><font size=2 color=\"#0000aa\"><i>";
        commentEnd = "</font></i><font size=2 color=black>";
        stringStart = "</font><font size=2 color=\"#00bb00\">";
        stringEnd = "</font><font size=2 color=black>";
        reservedWordStart = "<b>";
        reservedWordEnd = "</b>";
    }

    public void setCommentStart(String commentStart)
    {
        this.commentStart = commentStart;
    }

    public void setCommentEnd(String commentEnd)
    {
        this.commentEnd = commentEnd;
    }

    public void setStringStart(String stringStart)
    {
        this.stringStart = stringStart;
    }

    public void setStringEnd(String stringEnd)
    {
        this.stringEnd = stringEnd;
    }

    public void setReservedWordStart(String reservedWordStart)
    {
        this.reservedWordStart = reservedWordStart;
    }

    public void setReservedWordEnd(String reservedWordEnd)
    {
        this.reservedWordEnd = reservedWordEnd;
    }

    public String getCommentStart()
    {
        return commentStart;
    }

    public String getCommentEnd()
    {
        return commentEnd;
    }

    public String getStringStart()
    {
        return stringStart;
    }

    public String getStringEnd()
    {
        return stringEnd;
    }

    public String getReservedWordStart()
    {
        return reservedWordStart;
    }

    public String getReservedWordEnd()
    {
        return reservedWordEnd;
    }

    public String syntaxHighlight(String line)
    {
        return htmlFilter(line);
    }

    private String htmlFilter(String line)
    {
        if(line == null || line.equals(""))
        {
            return "";
        } else
        {
            line = replace(line, "&", "&#38;");
            line = replace(line, "\\\\", "&#92;&#92;");
            line = replace(line, "\\\"", "&#92;&#34");
            line = replace(line, "<", "&#60;");
            line = replace(line, ">", "&#62;");
            return multiLineCommentFilter(line);
        }
    }

    private String multiLineCommentFilter(String line)
    {
        if(line == null || line.equals(""))
            return "";
        StringBuffer buf = new StringBuffer();
        int index;
        if(inMultiLineComment && (index = line.indexOf("*/")) > -1 && !isInsideString(line, index))
        {
            inMultiLineComment = false;
            buf.append(line.substring(0, index));
            buf.append("*/").append(commentEnd);
            if(line.length() > index + 2)
                buf.append(inlineCommentFilter(line.substring(index + 2)));
            return buf.toString();
        }
        if(inMultiLineComment)
            return line;
        if((index = line.indexOf("/*")) > -1 && !isInsideString(line, index))
        {
            inMultiLineComment = true;
            buf.append(inlineCommentFilter(line.substring(0, index)));
            buf.append(commentStart).append("/*");
            buf.append(multiLineCommentFilter(line.substring(index + 2)));
            return buf.toString();
        } else
        {
            return inlineCommentFilter(line);
        }
    }

    private String inlineCommentFilter(String line)
    {
        if(line == null || line.equals(""))
            return "";
        StringBuffer buf = new StringBuffer();
        int index;
        if((index = line.indexOf("//")) > -1 && !isInsideString(line, index))
        {
            buf.append(stringFilter(line.substring(0, index)));
            buf.append(commentStart);
            buf.append(line.substring(index));
            buf.append(commentEnd);
        } else
        {
            buf.append(stringFilter(line));
        }
        return buf.toString();
    }

    private String stringFilter(String line)
    {
        if(line == null || line.equals(""))
            return "";
        StringBuffer buf = new StringBuffer();
        if(line.indexOf("\"") <= -1)
            return keywordFilter(line);
        int start = 0;
        int startStringIndex = -1;
        int endStringIndex = -1;
        int i;
        while((i = line.indexOf("\"")) > -1) 
            if(startStringIndex == -1)
            {
                startStringIndex = 0;
                buf.append(stringFilter(line.substring(start, i)));
                buf.append(stringStart).append("\"");
                line = line.substring(i + 1);
            } else
            {
                startStringIndex = -1;
                endStringIndex = i;
                buf.append(line.substring(0, endStringIndex + 1));
                buf.append(stringEnd);
                line = line.substring(endStringIndex + 1);
            }
        buf.append(keywordFilter(line));
        return buf.toString();
    }

    private String keywordFilter(String line)
    {
        if(line == null || line.equals(""))
            return "";
        StringBuffer buf = new StringBuffer();
        HashMap usedReservedWords = new HashMap();
        int i = 0;
        int startAt = 0;
        StringBuffer temp = new StringBuffer();
        while(i < line.length()) 
        {
            temp.setLength(0);
            char ch = line.charAt(i);
            startAt = i;
            while(i < line.length() && (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z')) 
            {
                temp.append(ch);
                if(++i < line.length())
                    ch = line.charAt(i);
            }
            String tempString = temp.toString();
            if(reservedWords.containsKey(tempString) && !usedReservedWords.containsKey(tempString))
            {
                usedReservedWords.put(tempString, tempString);
                line = replace(line, tempString, reservedWordStart + tempString + reservedWordEnd);
                i += reservedWordStart.length() + reservedWordEnd.length();
            } else
            {
                i++;
            }
        }
        buf.append(line);
        return buf.toString();
    }

    private String replace(String line, String oldString, String newString)
    {
        for(int i = 0; (i = line.indexOf(oldString, i)) >= 0; i += newString.length())
            line = line.substring(0, i) + newString + line.substring(i + oldString.length());

        return line;
    }

    private boolean isInsideString(String line, int position)
    {
        if(line.indexOf("\"") < 0)
            return false;
        String left = line.substring(0, position);
        String right = line.substring(position);
        int leftCount = 0;
        int rightCount = 0;
        int index;
        while((index = left.indexOf("\"")) > -1) 
        {
            leftCount++;
            left = left.substring(index + 1);
        }
        while((index = right.indexOf("\"")) > -1) 
        {
            rightCount++;
            right = right.substring(index + 1);
        }
        return rightCount % 2 != 0 && leftCount % 2 != 0;
    }

    private static void loadHash()
    {
        reservedWords.put("abstract", "abstract");
        reservedWords.put("do", "do");
        reservedWords.put("inner", "inner");
        reservedWords.put("public", "public");
        reservedWords.put("var", "var");
        reservedWords.put("boolean", "boolean");
        reservedWords.put("continue", "continue");
        reservedWords.put("int", "int");
        reservedWords.put("return", "return");
        reservedWords.put("void", "void");
        reservedWords.put("break", "break");
        reservedWords.put("else", "else");
        reservedWords.put("interface", "interface");
        reservedWords.put("short", "short");
        reservedWords.put("volatile", "volatile");
        reservedWords.put("byvalue", "byvalue");
        reservedWords.put("extends", "extends");
        reservedWords.put("long", "long");
        reservedWords.put("static", "static");
        reservedWords.put("while", "while");
        reservedWords.put("case", "case");
        reservedWords.put("final", "final");
        reservedWords.put("naive", "naive");
        reservedWords.put("super", "super");
        reservedWords.put("transient", "transient");
        reservedWords.put("cast", "cast");
        reservedWords.put("float", "float");
        reservedWords.put("new", "new");
        reservedWords.put("rest", "rest");
        reservedWords.put("catch", "catch");
        reservedWords.put("for", "for");
        reservedWords.put("null", "null");
        reservedWords.put("synchronized", "synchronized");
        reservedWords.put("char", "char");
        reservedWords.put("finally", "finally");
        reservedWords.put("operator", "operator");
        reservedWords.put("this", "this");
        reservedWords.put("class", "class");
        reservedWords.put("generic", "generic");
        reservedWords.put("outer", "outer");
        reservedWords.put("switch", "switch");
        reservedWords.put("const", "const");
        reservedWords.put("goto", "goto");
        reservedWords.put("package", "package");
        reservedWords.put("throw", "throw");
        reservedWords.put("double", "double");
        reservedWords.put("if", "if");
        reservedWords.put("private", "private");
        reservedWords.put("true", "true");
        reservedWords.put("default", "default");
        reservedWords.put("import", "import");
        reservedWords.put("protected", "protected");
        reservedWords.put("try", "try");
    }

    private static HashMap reservedWords = new HashMap();
    private boolean inMultiLineComment;
    private String backgroundColor;
    private String commentStart;
    private String commentEnd;
    private String stringStart;
    private String stringEnd;
    private String reservedWordStart;
    private String reservedWordEnd;

    static 
    {
        loadHash();
    }
}
