package com.jscape.inet.terminal;

import java.awt.*;
import java.util.HashMap;

/**
 * This immutable classs represents code>Cell</code> class attributes.
 * Currently they are: bold, underscored, blinked, reversed and has two colors
 * - foreground and background. <code>hashCode()</code> function is
 * overriden for this class, so each <code>CellAttributes</code> object has
 * unique hash and may be stored in <code>HashMap</code> object.
 * There are no public constructors for <code>CellAttributes</code>  class
 * and user can get an instance only by using static factory functions.
 * All these techniques help to reduce overall memory usage.
 * Together with <code>Cell</code> class this class
 * implements "Flyweight" pattern [Gamma94]
 */
public class CellAttributes {

    private static final HashMap INSTANCES = new HashMap();

    private final boolean bold;
    private final boolean underscored;
    private final boolean blinked;
    private final boolean reversed;
    private final Color fgColor;
    private final Color bkColor;

    //----------------------------------------------------------------------------
    private static int hash(boolean bold, boolean underscored, boolean blinked,
                            boolean reversed, Color fg, Color bk) {
        int h = 17;
        h = h * 37 + (bold ? 0 : 1);
        h = h * 37 + (underscored ? 0 : 1);
        h = h * 37 + (blinked ? 0 : 1);
        h = h * 37 + (reversed ? 0 : 1);
        h = h * 37 + fg.hashCode();
        h = h * 37 + bk.hashCode();

        return h;
    }

    //----------------------------------------------------------------------------

    /**
     * Returns instance of <code>CellAttributes</code> class giving all
     * needed parameters. Function calculates hash for this parameters combination
     * and seeks for object with same parameters in hash map.
     * If there is no object with such parameters a new instance will be created
     * and stored in hash map.
     *
     * @param bold        true if screen character must be bold.
     * @param underscored true if screen character must be underscored.
     * @param blinked     true if screen character must be blinked.
     * @param reversed    true if screen character must be reversed.
     * @param fgColor     foreground color.
     * @param bkColor     background color.
     *
     * @return <code>CellAttributes</code> with specified parameters.
     */
    public static CellAttributes getInstance(boolean bold,
                                             boolean underscored,
                                             boolean blinked,
                                             boolean reversed, Color fgColor,
                                             Color bkColor) {

        Integer hc =
                new Integer(hash(bold, underscored, blinked, reversed, fgColor, bkColor));

        if (INSTANCES.containsKey(hc)) {
            return (CellAttributes) INSTANCES.get(hc);
        } else {
            CellAttributes attributes = new CellAttributes(bold, underscored, blinked, reversed, fgColor, bkColor);
            INSTANCES.put(hc, attributes);

            return attributes;
        }
    }

    //----------------------------------------------------------------------------

    /**
     * Returns <code>CellAttributes</code> object with default parameters:
     * all character parametrs are false, foreground color is white,
     * background is black.
     *
     * @return <code>CellAttributes</code> with default parameters.
     */
    public static CellAttributes getInstance() {
        return getInstance(false, false, false, false, new Color(255, 255, 255),
                           new Color(0, 0, 0));
    }

    //----------------------------------------------------------------------------

    /**
     * Private constructor makes sure that no free attributes can be created.
     */
    private CellAttributes(boolean bold, boolean underscored,
                           boolean blinked, boolean reversed,
                           Color fgColor, Color bkColor) {
        if (fgColor == null || bkColor == null) {
            throw new NullPointerException("CellAttributes.constructor(): null passed");
        }

        this.bold = bold;
        this.underscored = underscored;
        this.blinked = blinked;
        this.reversed = reversed;
        this.fgColor = fgColor;
        this.bkColor = bkColor;
    }

    //----------------------------------------------------------------------------

    /**
     * Returns if 'bold' is set in current object.
     *
     * @return true if 'bold' is set.
     */
    public boolean isBold() {
        return this.bold;
    }

    //----------------------------------------------------------------------------

    /**
     * Returns if 'underscored' is set for current object.
     *
     * @return true if 'underscored' is set.
     */
    public boolean isUnderscored() {
        return this.underscored;
    }

    //----------------------------------------------------------------------------

    /**
     * Returns if 'blinked' is set for current object.
     *
     * @return true if 'blinked' is set
     */
    public boolean isBlinked() {
        return this.blinked;
    }

    //----------------------------------------------------------------------------

    /**
     * Returns if 'reversed' is set for current object.
     *
     * @return true if 'reversed' is set.
     */
    public boolean isReversed() {
        return this.reversed;
    }

    //----------------------------------------------------------------------------

    /**
     * Returns foreground color.
     *
     * @return foreground color.
     */
    public Color getFgColor() {
        return this.fgColor;
    }

    //----------------------------------------------------------------------------

    /**
     * Returns background color.
     *
     * @return background color.
     */
    public Color getBkColor() {
        return this.bkColor;
    }

}
