// Copyright 1996, Marimba Inc. All Rights Reserved.


// @(#)Style.java, 1.12, 12/05/96





package marimba.text;





import java.awt.*;


import java.io.*;





/**


 * A representation of a style.  To save on the number of classes, a


 * style is really a reference to a style, i.e., it has a position in


 * the buffer that the style occurs at.


 *


 * @author	Jonathan Payne


 * @version 	1.12, 12/05/96


 */


public class Style implements Cloneable, marimba.gui.WidgetConstants {


    public static final byte CHAR_WRAP = 0;	// the default


    public static final byte TRUNCATE = 1;


    public static final byte WORD_WRAP = 2;





    public static final char wrapNames[] = {'C', 'T', 'W'};





    public static final String wrapStrings[] = {"char", "truncate", "word"};


    public static final String alignStrings[] = {"left", "right",


						 "both", "center"};





    /** Font family. */


    FontFamily family;





    /** Font face. */


    int fontFace;





    /** Font size. */


    int fontSize;





    /** Color. */


    Color color;





    /** Background color. */


    Color background;





    /** Left margin. */


    int leftMargin;





    /** Right margin. */


    int rightMargin;





    /** Wrap style, default = word wrap. */


    int wrapStyle = WORD_WRAP;





    /** Justification style, default = left. */


    int justifyStyle = LEFT;





    public String toString() {


	return getClass().getName() + "[" + toString(null) + "]";


    }





    public int hashCode() {


	return family.hashCode() ^ fontFace ^ fontSize


	    ^ color.hashCode() ^ wrapStyle ^ justifyStyle;


    }





    /**


     * Outputs all the parameters of this style where they are


     * different from the styles in the other style.  If other is


     * null, outputs all the parameters.


     */


    public String toString(Style other) {


	StringBuffer buf = new StringBuffer();





	if (other == null || other.family != family)


	    buf.append(family != null ? family.name : "(null)");


	buf.append(',');





	if (other == null || other.fontFace != fontFace)


	    buf.append(String.valueOf(fontFace));


	buf.append(',');


	    


	if (other == null || other.fontSize != fontSize)


	    buf.append(String.valueOf(fontSize));


	buf.append(',');


	    


	if ((other == null || other.color != color) && color != null)


	    buf.append(color.getRed() + "," + color.getGreen()


		       + "," + color.getBlue() + ",");


	else


	    buf.append(",,,");





	if (other == null || other.wrapStyle != wrapStyle)


	    buf.append(wrapNames[wrapStyle]);


	buf.append(',');





	if (other == null || other.justifyStyle != justifyStyle) {


	    char code;


	    switch (justifyStyle) {


	      default:


	      case LEFT: code = 'L'; break;


	      case CENTER: code = 'C'; break;


	      case RIGHT: code = 'R'; break;


	      case FILL: code = 'F'; break;


	    }


	    buf.append(code);


	}


	return buf.toString();


    }





    private String readUntil(int delim, int c, InputStream in) 


    throws IOException {


	if (c == -1)


	    c = in.read();





	if (c == delim)


	    return null;


	char namebuf[] = new char[8];


	int off = 1;


	namebuf[0] = (char) c;


	while ((c = in.read()) != delim && c != -1) {


	    if (off == namebuf.length) {


		char nn[] = new char[off + 16];


		System.arraycopy(namebuf, 0, nn, 0, off);


		namebuf = nn;


	    }


	    namebuf[off++] = (char) c;


	}


	return new String(namebuf, 0, off);


    }





    /**


     * Inputs all the parameters of this style from a stream.  C is


     * the first character read, and the rest can be found from the


     * stream.


     */


    public Style fromStream(int c, InputStream in) throws IOException {


	String s = readUntil(',', c, in);


	if (s != null)


	    family = FontFamily.lookup(s);


	if ((s = readUntil(',', -1, in)) != null)


	    fontFace = Integer.parseInt(s);


	if ((s = readUntil(',', -1, in)) != null)


	    fontSize = Integer.parseInt(s);


	if ((s = readUntil(',', -1, in)) != null) {


	    int r = Integer.parseInt(s);


	    int g = Integer.parseInt(readUntil(',', -1, in));


	    int b = Integer.parseInt(readUntil(',', -1, in));


	    color = new Color(r, g, b);


	} else {


	    in.read();


	    in.read();


	}


	if ((s = readUntil(',', -1, in)) != null) {


	    switch (s.charAt(0)) {


	      case 'C':


		wrapStyle = CHAR_WRAP;


		break;





	      case 'T':


		wrapStyle = TRUNCATE;


		break;





	      case 'W':


		wrapStyle = WORD_WRAP;


		break;





	      default:


		System.out.println("Unknown wrap style: " + s);


	    }


	}





	if ((s = readUntil('}', -1, in)) != null) {


	    switch (s.charAt(0)) {


	      case 'L':


		justifyStyle = LEFT;


		break;





	      case 'R':


		justifyStyle = RIGHT;


		break;





	      case 'F':


		justifyStyle = FILL;


		break;





	      case 'C':


		justifyStyle = CENTER;


		break;





	      default:


		System.out.println("Unknown justification style: " + s);


	    }


	}


	return this;


    }





    DeviceFont getFont() {


	return family.getFont(fontSize, fontFace);


    }





    public boolean equals(Object other) {


	if (other == this)


	    return true;


	if (!(other instanceof Style))


	    return false;


	Style os = (Style) other;


	return


	    family == os.family && fontFace == os.fontFace


		&& fontSize == os.fontSize && color.equals(os.color)


		&& leftMargin == os.leftMargin


		&& rightMargin == os.rightMargin;


    }





    public int getAlign() {


	return justifyStyle;


    }





    public int getWrap() {


	return wrapStyle;


    }





    public void setAlign(int align) {


	justifyStyle = align;


    }





    public void setWrap(int wrap) {


	wrapStyle = wrap;


    }





    public void setFont(Font f) {


	family = FontFamily.lookup(f.getFamily());


	fontFace = f.getStyle();


	fontSize = f.getSize();


    }





    public void setFontFamily(FontFamily f) {


	family = f;


    }





    public void setColor(Color color) {


	this.color = color;


    }





    public Object clone() {


	try {


	    return super.clone();


	} catch (CloneNotSupportedException e) {


	    return null;


	}


    }


}


