/*
 * 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.Graphics;

import minime.Composite;
import minime.Drawable;
import minime.Image;
import minime.core.ResourceManager;

/**
 * The MenuItemComposite class is used to construct a complicated menu item.In
 * MenuItemComposite, it may have background image,selected image and many
 * drawables.For example, at the same time, it has labels and images.
 * 
 * @author yishu
 * 
 */
public class MenuItemComposite extends MenuItem
{
    public static final int DRAWABLE_TYPE_LABEL = 1;
    public static final int DRAWABLE_TYPE_ICON = 2;
    public static final int DRAWABLE_TYPE_IMAGE = 3;

    private Composite composite;

    private int numberOfComponents = 0;
    private Vector offsets;

    public static MenuItem[] createMenuItemComposite(Drawable[][] drawables, int[][]offsets)
    {
    	return createMenuItemCompositeWithBackgroundImageAndFrame(drawables, offsets, 0,0,null,null) ;
    }

    public static MenuItem[] createMenuItemCompositeWithFrame(Drawable[][] drawables, int[][]offsets, int frameThickness, int frameColor)
    {
    	return createMenuItemCompositeWithBackgroundImageAndFrame(drawables, offsets, frameThickness,frameColor,null,null) ;
    }

    public static MenuItem[] createMenuItemCompositeWithBackgroundImage(Drawable[][] drawables, int[][]offsets, int bgImRscId,  int selImRscId)
    {
    	Image bgImage = new Image(ResourceManager.getImage(bgImRscId)) ;
    	Image selImage = new Image(ResourceManager.getImage(selImRscId)) ;
    	return createMenuItemCompositeWithBackgroundImageAndFrame(drawables, offsets, 0,0, bgImage, selImage) ;
    }

    public static MenuItem[] createMenuItemCompositeWithBackgroundImage(Drawable[][] drawables, int[][]offsets, Image bgImage,  Image selImage)
    {
    	return createMenuItemCompositeWithBackgroundImageAndFrame(drawables,offsets,0,0,bgImage,selImage) ;
    }
    
    public static MenuItem[] createMenuItemCompositeWithBackgroundImageAndFrame(Drawable[][] drawables, int[][]offsets, int frameThickness, int frameColor, Image bgImage,  Image selImage)
    {
    	if (drawables.length != offsets.length)
    		throw new IllegalArgumentException() ;
    	
    	MenuItem[] items = new MenuItem[drawables.length] ;
    	for(int i=0;i<drawables.length;i++)
    		items[i] = new MenuItemComposite(drawables[i],offsets[i],frameThickness, frameColor, bgImage,selImage) ;
    	return items ;
    }
    /**
     * Creates a new MenuItemConposite object with the given background image,
     * selected image, with the given drawables and their offsets, offsets must
     * be the same length as the drawables array.
     * 
     * @param bgImage
     *            the background image for MenuItemComposite
     * @param selectedImage
     *            the image for MenuItemComposite when it is selected
     * @param drawables
     *            an array of drawables
     * @param offsets
     *            an int array of drawables offsets
     * @throws NullPointerException
     *             if drawables is null
     * @throws NullPointerException
     *             if offsets is null
     * @throws IllegalArgumentException
     *             if the offsets array is non-null and has a different length
     *             from the drawables array
     */
    public MenuItemComposite(Drawable[] drawables, int[] offsets, int frameThickness, int frameColor, Image bgImage, Image selectedImage)
            throws NullPointerException, IllegalArgumentException
    {
        if (drawables == null || offsets == null)
            throw new NullPointerException();
        if (offsets.length != drawables.length)
            throw new IllegalArgumentException();

        composite = new Composite();
        numberOfComponents = drawables.length;
        if (numberOfComponents < offsets.length)
            numberOfComponents = offsets.length;

        this.offsets = new Vector() ;
        setOffsetArray(offsets) ;
        for (int i = 0; i < numberOfComponents; i++)
        {
            composite.addDrawable(drawables[i]);
        }
        // initialized sub component image
        setBgImage(bgImage) ;
        setSelectedImage(selectedImage) ;
        setFrameThicknessAndColor(frameThickness, frameColor) ;
    }

    public MenuItemComposite(MenuItem item)
	{
		//super(new Label(), bgImage, selectedImage);
		
		composite = new Composite();
		numberOfComponents = 1;
		int[] off = {0} ;
        this.offsets = new Vector() ;
		setOffsetArray(off) ;
	    composite.addDrawable(item);
		
		setBgImage(null) ;
		setSelectedImage(null) ;
	}
    
    public void setOffsetArray(int[] offsets)
    {
    	this.offsets.removeAllElements() ;
    	for(int i=0;i<offsets.length;i++)
    		this.offsets.addElement(new Integer(offsets[i])) ;
    }

    /**
     * Sets a component and offset at the specified index. The previous drawable and offset at that position are
     * discarded.
     * 
     * The index must be a value greater than or equal to 0 and less than the
     * current size of the vector.
     * 
     * @param drawable
     *            what the component is to be set to.
     * @param offset
     *            new offset.
     * @param index
     *            the specified index.
     *            @throws NullPointerException if drawable is null
     * @throws IndexOutOfBoundsException
     *             if the index was invalid.
     */
    public void setElementAt(Drawable drawable, int offset, int index) throws NullPointerException, IndexOutOfBoundsException
    {
        if(drawable == null)
            throw new NullPointerException();
        
        if (index < 0 || index >= numberOfComponents)
            throw new IndexOutOfBoundsException();

        composite.setDrawableAt(drawable, index);
        offsets.setElementAt(new Integer(offset), index) ;
        setNeedLayout() ;
    }

    public void insertElementAt(Drawable drawable, int offset, int index) throws NullPointerException, IndexOutOfBoundsException
    {
        if(drawable == null)
            throw new NullPointerException();
        
        if (index < 0 || index >= numberOfComponents)
            throw new IndexOutOfBoundsException();

        composite.insertDrawable(drawable, index) ;
        offsets.insertElementAt(new Integer(index), offset) ;
        setNeedLayout() ;
    }

    /**
     * Gets the drawable at the specified index in this MenuItemComposite.
     * 
     * The index must be in[0.. getElementCount()-1].
     * 
     * @param index
     *            the specified index.
     * @throws IllegalArgumentException
     *             if the index was invalid.
     */
    public Drawable getElementAt(int index) throws IllegalArgumentException
    {
        if (index < 0 || index >= numberOfComponents)
            throw new IllegalArgumentException();

        return composite.drawableAt(index);
    }

    public int getElementOffsetAt(int index) throws IllegalArgumentException
    {
        if (index < 0 || index >= numberOfComponents)
            throw new IllegalArgumentException();

        return ((Integer)offsets.elementAt(index)).intValue() ;
    }

    /**
     * Gets how many elements in this composite.
     * 
     * @return the count of elements in this composite.
     */
    public int getElementCount()
    {
        return numberOfComponents;
    }

    public void layoutImp()
    {
    	// layout background 
        super.layoutImp() ;
        
        // layout and position each sub component
        int maxH = super.getHeight();
        int maxW = super.getWidth();
        int offsetX = getFrameThickness() + 1 ;
        if (numberOfComponents != 0)
        {
        	// search maxH over all component and layout horizontally 
            for (int i = 0; i < numberOfComponents; i++)
            {
            	Drawable d = composite.drawableAt(i) ;                 
                d.layout() ;		// layout the sub component first to init its size
                maxH = Math.max(maxH, d.getHeight());
            }
            
            setHeight(maxH) ;
            for (int i = 0; i < numberOfComponents; i++)
            {
                Drawable d = composite.drawableAt(i);
                // center the sub component (commulate offsetX ...)
                offsetX += ((Integer)offsets.elementAt(i)).intValue() ;
                int dy = (maxH - d.getHeight()) / 2 ;
                d.setPosition(offsetX, dy);
            }
            
            // MenuItemComposit width is ofset of the last component + width of the component
            int w = ((Integer)offsets.elementAt(numberOfComponents - 1)).intValue() + composite.drawableAt(numberOfComponents - 1).getWidth();
            setWidth(Math.max(maxW, w)) ;
        }
    }

    public void renderImpl(Graphics gc)
    {
        super.renderImpl(gc);
        composite.render(gc);
    }
}
