/*
 * 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 java.util.Vector;

import javax.microedition.lcdui.*;

import minime.Drawable;
import minime.Font;
import minime.FontManager;
import minime.core.ResourceManager;

/**
 * The Label class is used to hold label,it can have frame.If not set text
 * position, string will be rendered at the middle of the Label.
 * 
 * @author aaa
 * 
 */
public class Label extends Drawable 
{
	private final static char SPACE=' ';
    private String label;
    private Font font;
    private int textColor;
    private int frameThickness = 0;
    private int frameColor = 0;
    private boolean framed;
    
    private int labelX, labelY;

    boolean forcedWidth = false ;
    boolean forcedHeight = false ;
    private boolean needWrap = false;
    
    private Vector textRows;
    
    protected Label()
    {
    }
    /**
     * Creates an instance of label by given source Label instance,it will copy
     * the attributes from source Label instance.
     * 
     * @param l
     *            the source Label istance.
     */
    public Label(Label l)
    {
        this(l.label, l.font, l.textColor, l.frameThickness, l.frameColor);
        setRscId(l.getRscId()) ;
    }

    /**
     * Creates an instance of label by given text, font, text color, frame
     * thickness and frame color.
     * 
     * @param label
     *            the Label text
     * @param font
     *            the font for render label
     * @param textColor
     *            the color for label
     */
    public Label(String label, Font font, int textColor)
    {
        this(label, font, textColor, 0, 0);
    }

    /**
     * Creates an instance of label by given text, and text color.
     * 
     * @param label
     *            the Label text
     * @param textColor
     *            the color for label
     */
    public Label(String label, int textColor)
    {
        this(label, FontManager.getFont(FontManager.LABEL_FONT), textColor);
    }

    /**
     * Creates an instance of label by given text, font, text color, frame
     * thickness and frame color.If font is null, font will be the default
     * font:FontManager.LABEL_FONT
     * 
     * @param label
     *            the Label text
     * @param font
     *            the font for render label
     * @param textColor
     *            the color for label
     * @param framethickness
     *            the frame thickness
     * @param frameColor
     *            the frame color
     */
    public Label(String label, Font font, int textColor, int framethickness, int frameColor)
    {
        this.label = label;
        if (font != null)
            this.font = font;
        else
            this.font = FontManager.getFont(FontManager.LABEL_FONT);
        this.textColor = textColor;
        this.frameThickness = framethickness;
        // if frameSickness==0 means no frame
        if (framethickness > 0)
            framed = true;
        this.frameColor = frameColor;
        setNeedLayout() ;
    }

    /**
     * Creates an Label instance with given text resource id, font, text color,
     * frame thickness and frame color. the text will be gotten from resource
     * file with text resource index id by ResourceManager.If want to set text
     * to null, set txRscId to ResourceManager.NONE_RESOURCE.
     * 
     * @param txRscId
     *            the text resource index id for getting text from resource
     *            file, if want to set text to null, txRscId should be
     *            ResourceManager.NONE_RESOURCE.
     * @param font
     *            the font for label text
     * @param textColor
     *            the text color
     * @param framethickness
     *            the frame thickness
     * @param frameColor
     *            the frame color
     */
    public Label(int txRscId, Font font, int textColor, int framethickness, int frameColor)
    {
        this(ResourceManager.getString(txRscId), font, textColor, framethickness, frameColor);
        setRscId(txRscId);
    }

    /**
     * Creates an Label instance with given text resource id, font, text
     * color.the text will be gotten from resource file with text resource index
     * id by ResourceManager.If want to set text to null, set txRscId to
     * ResourceManager.NONE_RESOURCE.
     * 
     * @param txRscId
     *            the text resource index id for getting text from resource
     *            file, if want to set text to null, txRscId should be
     *            ResourceManager.NONE_RESOURCE.
     * @param font
     *            the font for label text
     * @param textColor
     *            the text color
     */
    public Label(int txRscId, Font font, int textColor)
    {
        this(txRscId, font, textColor, 0, 0);
    }

    /**
     * Creates an Label instance with given text resource id, text color. The
     * font will be set to the default font.the text will be gotten from
     * resource file with text resource index id by ResourceManager.If want to
     * set text to null, set txRscId to ResourceManager.NONE_RESOURCE.
     * 
     * @param txRscId
     *            the text resource index id for getting text from resource
     *            file, if want to set text to null, txRscId should be
     *            ResourceManager.NONE_RESOURCE.
     * @param textColor
     *            the text color
     */
    public Label(int txRscId, int textColor)
    {
        this(txRscId, FontManager.getFont(FontManager.LABEL_FONT), textColor);
    }

    private static boolean isSeperate(char c)
    {
    	if(c==SPACE || c==';' || c==',')
    		return true;
    	else
    		return false;
    }

    public void renderImpl(Graphics gc)
    {
        if (label != null)
        {
        	drawLabel(gc);
        }
    	if (framed && frameThickness > 0)
        { // draw editfieldTitleLabel rectangle
        	drawFrame(gc);
        }
    }

    private void drawFrame(Graphics gc)
    {
        gc.setColor(frameColor);
        int tmpX = 0;
        int tmpY = 0;
        int tmpW = getWidth();
        int tmpH = getHeight();
        for (int i = 0; i < frameThickness; i++)
        {
            gc.drawRect(tmpX, tmpY, tmpW, tmpH);
            tmpX++;
            tmpY++;
            tmpW-=2;
            tmpH-=2;
        }
    }

    private void drawLabel(Graphics gc)
    {
        gc.setColor(textColor);    
        int tmpY =labelY;
        if( needWrap )
        {
        	for(int i=0; i<textRows.size(); i++)
        	{
        		String text = (String)( textRows.elementAt(i));
        		drawStringInCenter(gc, tmpY, text);
        		tmpY += font.getHeight();
        	}
        }
        else
        {
        	font.drawString(gc, labelX, labelY, label);        	
        }
    }

    private void drawStringInCenter(Graphics gc, int y, String text)
    {
    	text = text.trim();
    	int textWidth = font.getStringWidth(text);
    	int centerX = (this.getWidth()-textWidth)/2;
       	font.drawString(gc, centerX , y, text);
    }
    
    public void layoutImp()
    {
        // if no font or no label, nothing to do ..
    	if (font==null || label==null)
    	{
    		if(!forcedWidth)
    			super.setWidth(0);
    		if(!forcedHeight)
    			super.setHeight(0);
    		return ;
    	}
    	int textWidth  = font.getStringWidth(label) ;
    	if(label.indexOf('\n') != -1)
    	{
    		needWrap = true;
    	}
    	if (!forcedWidth)
    	{    		
	    	int w = textWidth + (frameThickness * 2) + 2  ;  // leave 1 dot space between frame and left & right of the string
	    	super.setWidth(w);   
            labelX = frameThickness + 1;
    	}
    	else
    	{
    		int w = getWidth() ;
    		labelX = Math.max(frameThickness+1, (w - textWidth)/2) ;
    		if(textWidth > getWidth())
    		{
    			needWrap = true;
    		}
    	}
    	
    	if (!forcedHeight)
    	{
    		int h=0;
    		if(needWrap)
    		{
    			textRows = getSplitTextArray(font, label, 
    					getWidth()- (frameThickness * 2) - 2 - 2*font.getCharWidth('A'));
    			int nbrRows = textRows.size();
	    		h = (nbrRows * font.getHeight()) + (frameThickness * 2) + 2 ;  // leave 1 dot space between frame and up & down of the string
    		}
	    	else
	    	{
	    		h = font.getHeight()+ (frameThickness * 2) + 2;
	    	}	
	        super.setHeight(h) ;
	        labelY = frameThickness+1 ;    // set the label right below the frame
    	}
    	else
    	{
    		int textH = 0;
    		int nbrRows = 1; // if no wrap , nbrRows is 1.
    		if(needWrap)
    		{
    			textRows = getSplitTextArray(font, label, 
    					getWidth()- (frameThickness * 2) - 2 - 2*font.getCharWidth('A'));
    			nbrRows = textRows.size();
    		}
    		textH = nbrRows * font.getHeight();
    		labelY = Math.max(frameThickness+1, (getHeight()-textH)/2) ;	
    	}
    }
    
    private static Vector getSplitTextArray(Font font, String text, int width)
    {        
    	Vector rows = new Vector();
        char[] ch = text.toCharArray();
		int w = 0;
		int begin = 0;
		int lastWordEnd = 0;							
		boolean lineStart = true;
		for (int i = 0; i < ch.length; i++) {
			if (i < ch.length - 1 && (!isSeperate(ch[i]))
					&& isSeperate(ch[i + 1])) {
				lastWordEnd = i + 1;
			}

			if (ch[i] == '\n') { // newline
				lastWordEnd = i + 1;
				rows.addElement( String.valueOf(ch, begin, lastWordEnd - begin - 1) );
				begin = lastWordEnd;
				w = 0;
				lineStart = true;
			} else {
				if (lineStart) {
					if (ch[i] != SPACE) {
						w = w + font.getCharWidth(ch[i]);
						lineStart = false;
					}
				} else {
					w = w + font.getCharWidth(ch[i]);
				}
				if (w >= width )// need minus two char's
													// width
				{
					if (lastWordEnd <= begin) // meet a very long word
					{
						lastWordEnd = i + 1;
					}
					// we need assert lastWordEnd>begin here.
					rows.addElement(String.valueOf(ch, begin, lastWordEnd - begin));
					begin = lastWordEnd;
					lineStart = true;
					w = 0;
				}
			}
		}
		if (begin < ch.length){
			rows.addElement(String.valueOf(ch, begin, ch.length - begin));
		}
		return rows;
        
    }

    /**
	 * set text for editfieldTitleLabel, and size calculated by layout
	 * 
	 * @param text
	 *            string for editfieldTitleLabel
	 */
    public void setString(String text)
    {
        this.label = text;
        setNeedLayout();
    }

    /**
	 * set text for editfieldTitleLabel, and size calculated by layout, the text
	 * will be drawed from text resource file based on text resource id.If want
	 * to set text to null, set txRscId to ResourceManager.NONE_RESOURCE.
	 * 
	 * @param txRscId
	 *            the text resource index id for getting text from resource
	 *            file, if want to set text to null, txRscId should be
	 *            ResourceManager.NONE_RESOURCE.
	 */
    public void setString(int txRscId)
    {
        setString(ResourceManager.getString(txRscId));
        setRscId(txRscId) ;
    }

    /**
     * Add a string to label.
     * 
     * @param content
     *            the new added string
     */
    public void append(String content)
    {
        if (content != null)
        {
            if (label != null)
                label += content;
            else
                label = content;

            setString(label);
        }
    }

    /**
     * Add a string to label.This added string is gotten from resource file
     * based on given text resource id,If want to append nothing, set txRscId to
     * ResourceManager.NONE_RESOURCE.
     * 
     * @param txRscId
     *            the text resource id.If want to append nothing, set txRscId to
     *            ResourceManager.NONE_RESOURCE.
     */
    public void append(int txRscId)
    {
        append(ResourceManager.getString(txRscId));
    }

    /**
     * set text for editfieldTitleLabel, and set string width as Label width
     * 
     * @param text
     *            string for editfieldTitleLabel
     */
    public void setStrWithStrWidth(String text)
    {
        this.label = text;
        setWidth(font.getStringWidth(label));
        setNeedLayout() ;
    }

    /**
     * set text for editfieldTitleLabel, and set string width as Label width,
     * the text will be drawed from text resource file based on text resource
     * id.If want to set text to null, set txRscId to
     * ResourceManager.NONE_RESOURCE.
     * 
     * @param txRscId
     *            the text resource index id for getting text from resource
     *            file, if want to set text to null, txRscId should be
     *            ResourceManager.NONE_RESOURCE.
     */
    public void setStrWithStrWidth(int txRscId)
    {
        setStrWithStrWidth(ResourceManager.getString(txRscId));
        setRscId(txRscId) ;
    }

    /**
     * Gets the label text
     * 
     * @return the label text
     */
    public String getString()
    {
        return label;
    }

    /**
     * Returns the font.
     * 
     * @return font instance.
     */
    public Font getFont()
    {
        return font;
    }

    /**
     * Sets the color for rendering label text.
     * 
     * @param textColor
     *            the color for label text
     */
    public void setTextColor(int textColor)
    {
        this.textColor = textColor;
    }

    /**
     * Sets the Label is framed or not.
     * 
     * @param framed
     *            the Label whether has frame
     */
    public void setFrame(boolean framed)
    {
        this.framed = framed;
    }

    /**
     * Sets the Label frame thickness and color.
     * 
     * @param frameThickness
     *            the frame thickness
     * @param frameColor
     *            the color for frame
     */
    public void setFrameThicknessAndColor(int frameThickness, int frameColor)
    {
        this.frameThickness = frameThickness;
        this.frameColor = frameColor;
//        if (frameThickness > 0)
//            framed = true;
        setNeedLayout();
    }

//    /**
//     * Sets the Label selected, if it is selected and has frame, will display
//     * the frame around the label.
//     */
//    public void setSelected(boolean s)
//    {
//        super.setSelected(s);
//        if (s && frameThickness > 0)
//        {
//            framed = true;
//        }
//        else
//            framed = false;
//    }

    public void setWidth(int w)
    {
    	forcedWidth = true ;
    	super.setWidth(w) ;
    }

    public void setHeight(int h)
    {
    	forcedHeight = true ;
    	super.setHeight(h) ;
    }
	public int getTextColor() {
		return textColor;
	}
	public void setFont(Font font) {
		this.font = font;
	}
	
	protected int getFrameThickness(){
		return this.frameThickness;
	}
	public int getLabelX() {
		return labelX;
	}
	public void setLabelX(int labelX) {
		this.labelX = labelX;
	}
	public int getLabelY() {
		return labelY;
	}
	public void setLabelY(int labelY) {
		this.labelY = labelY;
	}
}
