/*
 * Copyright (c) 2006-2008 MiniMe. Code released under The MIT/X Window System
 * License. Full license text can be found in license.txt
 */
package minime.ui;

import javax.microedition.lcdui.*;

import minime.Font;
import minime.Image;
import minime.Portability;
import minime.FontManager;
import minime.core.Component;
import minime.core.Event;
import minime.core.EventDispatcher;
import minime.core.ResourceManager;

/**
 * The SoftBar class is used to hold softkey buttons at the bottom of the
 * screen.It mostly has three softkey buttons:left softkey button, right softkey
 * button and the middle softkey button,you can use one or two or three of them.
 * Each button may have images for being pressed down and up.Also, buttons can
 * have the same size or have different sizes, if like this, you have to set
 * buttons x positions.
 * 
 * @author yishu
 * 
 */
public class SoftBar extends Component
{
    /** The left softkey button index */
    public final static int LEFT = 0;
    /** The middle softkey button index */
    public final static int MIDDLE = 1;
    /** The right softkey button index */
    public final static int RIGHT = 2;

    private static final int DOWN_DELAY = 100;
    private static final int UP_DELAY = 50;

    private static SoftBar inst ;
    
    private Button[] softKeys;
    private Font font;
    private boolean hasPointedXPos = false;
    private int[] offsetXPos;

    public static SoftBar getInstance()
    {
    	if (inst==null)
    		inst = new SoftBar() ;
    	return inst ;
    }

    public static void setLeftSoftkey(int textId)
    {
    	getInstance().setSoftkeyLabel(LEFT, textId) ;
    }
    public static void setCenterSoftkey(int textId)
    {
    	getInstance().setSoftkeyLabel(MIDDLE, textId) ;
    }
    public static void setRightSoftkey(int textId)
    {
    	getInstance().setSoftkeyLabel(RIGHT, textId) ;
    }
    
    /**
     * Creates a new SoftBar object with the default
     * font:FontManager.BUTTON_FONT, it doesn't have buttons.
     * 
     */
    private SoftBar()
    {
        this(FontManager.getFont(FontManager.BUTTON_FONT));
    }
    /**
     * Creates a new SoftBar object with the given font, but doesn't have
     * buttons.
     * 
     * @param font
     *            the preferred font to use to render the button's label
     */
    private SoftBar(Font font)
    {
        this.font = font;
        softKeys = new Button[3];
        setNeedLayout() ;
    }

    /**
     * Creates a new SoftBar object with the given three buttons.
     * 
     * @param kl
     *            the left softkey button
     * @param km
     *            the middle softkey button
     * @param kr
     *            the right softkey button
     */
    private SoftBar(Button kl, Button km, Button kr)
    {
        softKeys = new Button[3];

        softKeys[LEFT] = kl;
        softKeys[MIDDLE] = km;
        softKeys[RIGHT] = kr;

        this.font = kl.getFont();

        setNeedLayout() ;
    }

    /**
     * Calculates the buttons size the sets their positions.
     */
    public void layoutImp()
    {
    	// set position of each key.  Will be relative to Softbar position
        if (!hasPointedXPos)
        {
        	// standard key width if 1/3 of the view width
        	int keyWidth = getWidth() / 3 ;
        	// cal. buttons positions and sizes if not pointed position,set
            // button 0 as high because high will be re-calculated button layout
            if (softKeys[LEFT] != null)
            {	
            	softKeys[LEFT].setWidth(keyWidth) ;
            	softKeys[LEFT].layout() ;
                softKeys[LEFT].setPosition(0, 0);
            }
            if (softKeys[MIDDLE] != null)
            {
            	softKeys[MIDDLE].setWidth(keyWidth) ;
            	softKeys[MIDDLE].layout() ;
                softKeys[MIDDLE].setPosition(getWidth()/3, 0);
            }
            if (softKeys[RIGHT] != null)
            {
            	softKeys[RIGHT].setWidth(keyWidth) ;
            	softKeys[RIGHT].layout() ;
                softKeys[RIGHT].setPosition((getWidth() / 3 )*2,0);
            }
        }
        else
        {
            if (softKeys[LEFT] != null)
            {
            	softKeys[LEFT].layout() ;
                softKeys[LEFT].setPosition(offsetXPos[0], 0);
            }
            if (softKeys[MIDDLE] != null)
            {
            	softKeys[MIDDLE].layout() ;
                softKeys[MIDDLE].setPosition(offsetXPos[1], 0);
            }
            if (softKeys[RIGHT] != null)
            {
            	softKeys[RIGHT].layout() ;
                softKeys[RIGHT].setPosition(offsetXPos[2], 0);
            }
        }

        // if soktkeys exit, set softkey high as softbar high, or set softbar
        // hight as font high plus 2
        int maxH = 0 ;
        if (softKeys[LEFT] != null)
            maxH = Math.max(maxH, softKeys[LEFT].getHeight());
        if (softKeys[MIDDLE] != null)
            maxH = Math.max(maxH, softKeys[MIDDLE].getHeight());
        if (softKeys[RIGHT] != null)
            maxH = Math.max(maxH, softKeys[RIGHT].getHeight());
        maxH = Math.max(maxH, font.getHeight() + 2);
        setHeight(maxH) ;
    }

    /**
     * set softkey text
     * 
     * @param pos
     *            the position of soktkey
     * @param label
     *            the label for soktkey
     */
    public void setSoftkeyLabel(int pos, String label)
    {
        setSoftKey(pos, label, 0, 0);
    }

    /**
     * set softkey text, If want to set text to null, set txRscId to
     * ResourceManager.NONE_RESOURCE.
     * 
     * @param pos
     *            the position of soktkey
     * @param txRscId
     *            the text index id for text for soktkey,If want to set text to
     *            null, set txRscId to ResourceManager.NONE_RESOURCE.
     */
    public void setSoftkeyLabel(int pos, int txRscId)
    {
        setSoftkeyLabel(pos, ResourceManager.getString(txRscId));
        softKeys[pos].setRscId(txRscId) ;
    }

    /**
     * set sofkt key with given position, label and frame thickness and frame
     * color
     * 
     * @param pos
     *            the button position, just LEFT, MIDDLE, or RIGHT
     * @param label
     *            the label for button
     * @param framethickness
     *            the thickness for button frame
     * @param frameColor
     *            the color for button frame
     */
    public void setSoftKey(int pos, String label, int framethickness, int frameColor)
    {
        setSoftKey(pos, label, null, null, framethickness, frameColor);
    }

    /**
     * set sofkt key with given position, button text and frame thickness and
     * frame color.Button text is drawed from resource file based on txRscId by
     * ResourceManager.If want to set button text to null, set txRscId to
     * ResourceManager.NONE_RESOURCE.
     * 
     * @param pos
     *            the button position, just LEFT, MIDDLE, or RIGHT
     * @param txRscId
     *            the button text index id, If want to set text to null, set
     *            txRscId to ResourceManager.NONE_RESOURCE.
     * @param framethickness
     *            the thickness for button frame
     * @param frameColor
     *            the color for button frame
     */
    public void setSoftKey(int pos, int txRscId, int framethickness, int frameColor)
    {
        setSoftKey(pos, ResourceManager.getString(txRscId), framethickness, frameColor);
        softKeys[pos].setRscId(txRscId) ;
    }

    /**
     * set sofkt key with given position, label and background bitmaps for
     * button up and down
     * 
     * @param pos
     *            the button position, just LEFT, MIDDLE, or RIGHT
     * @param label
     *            the label for button
     * @param bgBitmapUp
     *            the background bitmap for button up
     * @param bgBitmapDown
     *            the background bitmap for button down
     */
    public void setSoftKey(int pos, String label, Image bgBitmapUp, Image bgBitmapDown)
    {
        setSoftKey(pos, label, bgBitmapUp, bgBitmapDown, 0, 0);
    }

    /**
     * set sofkt key with given position, label, background bitmaps for button
     * up and down, frame thickness and frame color
     * 
     * @param pos
     *            the button position, just LEFT, MIDDLE, or RIGHT
     * @param label
     *            the label for button
     * @param bgBitmapUp
     *            the background bitmap for button up
     * @param bgBitmapDown
     *            the background bitmap for button down
     * @param framethickness
     *            the thickness for button frame
     * @param frameColor
     *            the color for button frame
     */
    // \TODO should be removed
    public void setSoftKey(int pos, String label, Image bgBitmapUp, Image bgBitmapDown, int framethickness,
            int frameColor)
    {
        if (softKeys[pos] == null)
            softKeys[pos] = new Button(label, Portability.defaultFontTextColor, bgBitmapUp, bgBitmapDown);
        else
            softKeys[pos].setString(label);
        softKeys[pos].setVisible((null != label));
        // set the frame 
        softKeys[pos].setFrameThicknessAndColor(framethickness, frameColor);
        if (framethickness>0)
        	softKeys[pos].setFrame(true);
        else
        	softKeys[pos].setFrame(false);

        softKeys[pos].setTextColor(Portability.defaultFontTextColor);
        setNeedLayout() ;
    }

    /**
     * set sofkt key with given position, button text , button background image
     * for up and down, and frame thickness and frame color.Button text is
     * drawed from resource file based on txRscId by ResourceManager.If want to
     * set button text to null, set txRscId to ResourceManager.NONE_RESOURCE.
     * 
     * @param pos
     *            the button position, just LEFT, MIDDLE, or RIGHT
     * @param txRscId
     *            the button text index id,If want to set text to null, set
     *            txRscId to ResourceManager.NONE_RESOURCE.
     * @param upImRscId
     *            background bitmap index id for button up
     * @param downImRscId
     *            background bitmap index id for button down
     * @param framethickness
     *            the thickness for button frame
     * @param frameColor
     *            the color for button frame
     */
    public void setSoftKey(int pos, int txRscId, int upImRscId, int downImRscId, int framethickness, int frameColor)
    {
        if (softKeys[pos] == null)
            softKeys[pos] = new Button(txRscId, Portability.defaultFontTextColor, upImRscId, downImRscId);
        else
            softKeys[pos].setString(txRscId);
        softKeys[pos].setVisible((txRscId >= 0));
        // set the frame
        softKeys[pos].setFrameThicknessAndColor(framethickness, frameColor);
        if (framethickness>0)
        	softKeys[pos].setFrame(true);
        else
        	softKeys[pos].setFrame(false);
        	
        softKeys[pos].setRscId(txRscId) ;
        softKeys[pos].setTextColor(Portability.defaultFontTextColor);
        setNeedLayout() ;
    }

    //  return the resource key value 
    
    public int getLeftKey()
    {
    	return getSoftkey(LEFT) ;
    }
    
    public int getRightKey()
    {
    	return getSoftkey(RIGHT) ;
    }
    public int getCenterKey()
    {
    	return getSoftkey(MIDDLE) ;
    }
    
    private int getSoftkey(int pos)
    {
    	if (softKeys[pos] != null)
    		return softKeys[pos].getRscId() ;
    	return ResourceManager.NONE_RESOURCE ;
    }
    
    /**
     * set softkeys x coordinates
     * 
     * @param offsetX
     *            x coordinates for softkeys
     */
    public void setSoftKeysXPos(int[] offsetX)
    {
        hasPointedXPos = true;
        this.offsetXPos = offsetX;
        setNeedLayout() ;
    }

    
    /**
     * remove a softkey
     * 
     * @param pos
     *            at the pos key will be removed
     */
    public void removeSoftKey(int pos)
    {
        if (softKeys[pos] != null)
        {
            softKeys[pos] = null;
        }
    }

    /**
     * Removes all the buttons in the SoftBar.
     */
    public void removeAllSoftKey()
    {
        for (int i = 0; i < 3; i++)
            removeSoftKey(i);
    }

    /**
     * Sets the SoftBar buttons whether visisble.
     * 
     * @param visibled
     *            the SoftBar buttons whether visisble or not.
     */
    public void setSoftBarVisible(boolean visibled)
    {
        for (int i = 0; i < 3; i++)
            if (softKeys[i] != null && softKeys[i].getString() != null)
                softKeys[i].setVisible(visibled);
    }

    /**
     * Fires a SB_EVENT, ParamA is the one of
     * KEY_SOFT_LEFT,KEY_FIRE,KEY_SOFT_RIGHT,paramB is the button lable resource
     * id.
     */
    public boolean onEvent(Event evt)
    {
    	// change the softkey state to pressed
        if (evt.type == Event.KEY_DOWN_EVENT)
        { 
            if (evt.paramA == Portability.KEY_SOFT_LEFT && softKeys[LEFT] != null && softKeys[LEFT].isVisible())
            {
                EventDispatcher.getInstance().fire(
                		Event.createEvent(Event.SB_EVENT, Portability.KEY_SOFT_LEFT, softKeys[LEFT].getRscId()));
                softKeys[LEFT].setKeyPressed(true);
                softKeys[LEFT].setTextColor(Portability.defaultFontTextColor);
                minime.core.Runtime.getInstance().repaint();
                return true;
            }
            else if (evt.paramA == Portability.KEY_FIRE && softKeys[MIDDLE] != null && softKeys[MIDDLE].isVisible())
            {
                EventDispatcher.getInstance().fire(
                		Event.createEvent(Event.SB_EVENT, Portability.KEY_FIRE, softKeys[MIDDLE].getRscId()));
                softKeys[MIDDLE].setKeyPressed(true);
                softKeys[MIDDLE].setTextColor(Portability.defaultFontTextColor);
                minime.core.Runtime.getInstance().repaint();
                return true;
            }
            else if (evt.paramA == Portability.KEY_SOFT_RIGHT && softKeys[RIGHT] != null && softKeys[RIGHT].isVisible())
            {
                EventDispatcher.getInstance().fire(
                		Event.createEvent(Event.SB_EVENT, Portability.KEY_SOFT_RIGHT, softKeys[RIGHT].getRscId()));
                softKeys[RIGHT].setKeyPressed(true);
                softKeys[RIGHT].setTextColor(Portability.defaultFontTextColor);
                minime.core.Runtime.getInstance().repaint();
                return true;
            }
            // if not a SB_EVENT, just fire the KEY_EVENT
            else
            {
                EventDispatcher.getInstance().fire(
                        Event.createEvent(Event.KEY_EVENT, evt.paramA, evt.paramB));
                return true;
            }
        }
        // change the softkey state to released and fire the right SB_EVENT or KEY_EVENT 
        else if (evt.type == Event.KEY_UP_EVENT)
        { 
            if (evt.paramA == Portability.KEY_SOFT_LEFT && softKeys[LEFT] != null && softKeys[LEFT].isVisible())
            {
                softKeys[LEFT].setKeyPressed(false);
                minime.core.Runtime.getInstance().repaint();
                return true;
            }
            else if (evt.paramA == Portability.KEY_FIRE && softKeys[MIDDLE] != null && softKeys[MIDDLE].isVisible())
            {
                softKeys[MIDDLE].setKeyPressed(false);
                minime.core.Runtime.getInstance().repaint();
                return true;
            }
            else if (evt.paramA == Portability.KEY_SOFT_RIGHT && softKeys[RIGHT] != null && softKeys[RIGHT].isVisible())
            {
                softKeys[RIGHT].setKeyPressed(false);
                minime.core.Runtime.getInstance().repaint();
                return true;
            }
        }

        return false;
    }

    public int getPriority()
    {
        return HIGH_PRIORITY;
    }

    public void renderImpl(Graphics gc)
    {
        // Display soft key
        for (int i = 0; i < 3; i++)
        {
            if (softKeys[i] != null)
            {
            	// coordinates translate already been done by view.composite
                softKeys[i].render(gc);
            }
        }
    }
}
