package cnp.ew.richtext;

import java.awt.*;
import java.util.*;
import java.io.*;
import cnp.ew.util.*;

public class CpCharFormat implements CpCopyable
{
    final static int NAME = 0x1;
    final static int BOLD = 0x2;
    final static int ITALIC = 0x4;
    final static int SIZE = 0x8;
    final static int COLOR = 0x10;
    final static int UNDERLINE = 0x20;

    static Hashtable cache = new Hashtable();
    static Font baseFont = new Font("TimesRoman", Font.PLAIN, 12);

    private int flags;

    private String fontName;
    boolean isBold;
    boolean isUnderline;
    boolean isItalic;
    private int pointSize;
    private Color color;

    public CpCharFormat(RandomAccessFile file) throws IOException
    {
        flags = file.readInt();
        fontName = file.readUTF();
        if (fontName.equals(" ")) {
            fontName = null;
        }
        isBold = file.readBoolean();
        isItalic = file.readBoolean();
        pointSize = file.readInt();
        int red = file.readInt();
        if (red != -1) {
            int green = file.readInt();
            int blue = file.readInt();
            color = new Color(red,green,blue);
        }
    }

    static public void setBaseFont(Font f)
    {
        baseFont = f;
    }

    public void writeTo(RandomAccessFile file) throws IOException
    {
        file.writeInt(flags);
        if (fontName == null) {
            file.writeUTF(" ");
        } else {
            file.writeUTF(fontName);
        }
        file.writeBoolean(isBold);
        file.writeBoolean(isItalic);
        file.writeInt(pointSize);
        if (color == null) {
            file.writeInt(-1);
        } else {
            file.writeInt(color.getRed());
            file.writeInt(color.getGreen());
            file.writeInt(color.getBlue());
        }
    }

    public Object getCopy()
    {
        return new CpCharFormat(this);
    }

    public static CpCharFormat getBold()
    {
    	CpCharFormat style = new CpCharFormat();
    	style.setBold(true);
    	return style;
    }

    public static CpCharFormat getUnderline()
    {
    	CpCharFormat style = new CpCharFormat();
    	style.setUnderline(true);
    	return style;
    }

    public static CpCharFormat getItalic()
    {
    	CpCharFormat style = new CpCharFormat();
    	style.setItalic(true);
    	return style;
    }

    public CpCharFormat()
    {
    	this(0, null, false, false, false, 0, null);
    }

    public CpCharFormat(int newFlags, String newFontName, boolean newIsBold, boolean newIsUnderline, boolean newIsItalic, int newPointSize, Color newColor)
    {
     	flags = newFlags;
     	fontName = newFontName;
     	isBold = newIsBold;
     	isUnderline = newIsUnderline;
     	isItalic = newIsItalic;
     	pointSize = newPointSize;
     	color = newColor;
    }

    public CpCharFormat(CpCharFormat charFormat)
    {
    	this(charFormat.flags, charFormat.fontName, charFormat.isBold, charFormat.isUnderline, charFormat.isItalic, charFormat.pointSize, charFormat.color);
    }

    public int paint(Graphics g, int curOffset, int charsToDraw, CpLine line, CpTextModel text, int x, int y)
    {
        setupGraphics(g);
        int width = g.getFontMetrics().charsWidth(text.getChars(), curOffset, charsToDraw);
        int theY = y + line.getHeight() - line.getDescent();
        if (isUnderline()) {
            g.drawLine(x, theY + 1, x + width - 1, theY + 1);
        }
        g.drawChars(text.getChars(), curOffset, charsToDraw, x, y + line.getHeight() - line.getDescent());
        return width;
    }

    public boolean hasFontName()
    {
    	return (flags & NAME) != 0;
    }

    public String getFontName()
    {
    	if (hasFontName()) {
    	    return fontName;
    	} else {
    	   return baseFont.getName();
    	}
    }

    public void setFontName(String fontName)
    {
    	this.fontName = fontName;
    	flags |= NAME;
    }

    public boolean hasBold()
    {
    	return (flags & BOLD) != 0;
    }

    public void setBold(boolean isBold)
    {
    	this.isBold = isBold;
    	flags |= BOLD;
    }

    public boolean hasUnderline()
    {
    	return (flags & UNDERLINE) != 0;
    }

    public void setUnderline(boolean isUnderline)
    {
    	this.isUnderline = isUnderline;
    	flags |= UNDERLINE;
    }

    public boolean isUnderline()
    {
        return isUnderline;
    }

    public boolean hasItalic()
    {
    	return (flags & ITALIC) != 0;
    }

    public boolean isBold()
    {
        return isBold;
    }

    public boolean isItalic()
    {
        return isItalic;
    }

    public void setItalic(boolean isItalic)
    {
    	this.isItalic = isItalic;
    	flags |= ITALIC;
    }


    final public boolean hasPointSize()
    {
    	return (flags & SIZE) != 0;
    }

    public void setPointSize(int pointSize)
    {
    	this.pointSize = pointSize;
    	flags |= SIZE;
    }

    public int getPointSize()
    {
    	if (hasPointSize()) {
    	    return pointSize;
    	} else {
    	    return baseFont.getSize();
    	}
    }

    public boolean hasColor()
    {
    	return (flags & COLOR) != 0;
    }

    public void setColor(Color color)
    {
    	this.color = color;
    	flags |= COLOR;
    }

    public Color getColor()
    {
    	if (hasColor()) {
    	    return color;
    	} else {
    	    return null;
    	}
    }

    public Font applyStyle(Font font)
    {
    	String fname = hasFontName() ? fontName : font.getName();
    	boolean bold = hasBold() ? isBold : font.isBold();
    	boolean italic = hasItalic() ? isItalic : font.isItalic();
    	int style = (bold ? Font.BOLD : 0) | (italic ? Font.ITALIC : 0);
    	int size = hasPointSize() ? pointSize : font.getSize();

    	return new Font(fname, style, size);
    }

    public CpCharFormat merge(CpCharFormat charFormat)
    {
    	CpCharFormat copy = (CpCharFormat)getCopy();
    	int f = (flags ^ charFormat.flags) & charFormat.flags;

    	if (charFormat.hasFontName()) {
    	    copy.setFontName(charFormat.fontName);
    	}

    	if (charFormat.hasBold()) {
    	    copy.setBold(charFormat.isBold);
    	}

    	if (charFormat.hasUnderline()) {
    	    copy.setUnderline(charFormat.isUnderline);
    	}

    	if (charFormat.hasItalic()) {
    	    copy.setItalic(charFormat.isItalic);
    	}

    	if (charFormat.hasPointSize()) {
    	    copy.setPointSize(charFormat.pointSize);
    	}

    	if (charFormat.hasColor()) {
    	    copy.setColor(charFormat.color);
    	}

    	return copy;
    }

    public int hashCode()
    {
    	int code = flags;

    	if (hasBold()) {
    	    code += isBold ? 1 : 0;
    	}

        if (hasUnderline()) {
            code += isUnderline ? 16 : 0;
        }

    	if (hasItalic()) {
    	    code += isItalic ? 2 : 0;
    	}

    	if (hasPointSize()) {
    	    code += pointSize * 4;
    	}

    	if (hasColor()) {
    	    code += color.hashCode();
    	}

    	if (hasFontName()) {
    	    code += fontName.hashCode();
    	}

    	return code;
    }

    public boolean equals(Object newCharFormat)
    {
    	if (!(newCharFormat instanceof CpCharFormat)) {
    	    return false;
    	}

    	CpCharFormat charFormat = (CpCharFormat) newCharFormat;

    	if (flags != charFormat.flags) {
    	    return false;
    	}

    	if (hasBold() && (isBold != charFormat.isBold)) {
    	    return false;
    	}

    	if (hasUnderline() && (isUnderline != charFormat.isUnderline)) {
    	    return false;
    	}

    	if (hasItalic() && (isItalic != charFormat.isItalic)) {
    	    return false;
    	}

    	if (hasPointSize() && (pointSize != charFormat.pointSize)) {
    	    return false;
    	}

    	if (hasColor() && (! color.equals(charFormat.color))) {
    	    return false;
    	}

    	if (hasFontName() && (! fontName.equals(charFormat.fontName))) {
    	    return false;
    	}

    	return true;
    }

    public int[] getWidths()
    {
        return getFontMetrics().getWidths();
    }

    public int getHeight()
    {
        return getFontMetrics().getHeight();
    }

    public int getDescent()
    {
        return getFontMetrics().getDescent();
    }

    public FontMetrics getFontMetrics()
    {
	    FontMetrics fm = (FontMetrics)cache.get(this);
    	if (fm == null)	{
    	    fm = Toolkit.getDefaultToolkit().getFontMetrics(applyStyle(baseFont));
    	    cache.put(this, fm);
    	}

	    return fm;
	}

    public void setupGraphics(Graphics g)
    {
        g.setColor(Color.black);

    	FontMetrics fm = getFontMetrics();
    	g.setFont(fm.getFont());

    	if (hasColor()) {
    	    g.setColor(color);
        }
    }

    public void aboutToDelete()
    {
    }
}