package javax.microedition.lcdui;

import java.util.ArrayList;

/**
 * 
 * @author Andre Nijholt
 */
public class ChoiceGroup extends Item implements Choice {	
	protected int choiceType;
	protected ArrayList choiceItems;
//	private int fitPolicy;
	
	/** Scrolling administration */
	private int scrollFirst = 0;
	private int scrollCurr 	= 0;
	private int scrollLast 	= 0;
	private boolean scrollWrap = true;
	
	public ChoiceGroup(String label, int choiceType) {
		if (choiceType == Choice.IMPLICIT) {
			// Type IMPLICIT not allowed
			throw new IllegalArgumentException();
		}

		this.label = label;
		this.choiceType = choiceType;
		choiceItems = new ArrayList();
		interactive = true;
		
		if (label != null) {
			// Only show label or first item when POPUP list is used
			minWidth = (label.length() * Display.CHAR_WIDTH);
			minHeight = ((choiceType == Choice.POPUP) ? 1 : 2) * Display.CHAR_HEIGHT;
		} else {
			minWidth = Display.CHAR_WIDTH;
			minHeight = Display.CHAR_HEIGHT;
		}
	}
	
	public ChoiceGroup(String label, int choiceType, String[] stringElements, Image[] imageElements) {
		if (choiceType == Choice.IMPLICIT) {
			// Type IMPLICIT not allowed
			throw new IllegalArgumentException();
		}
		this.label = label;
		this.choiceType = choiceType;
		interactive = true;

		if (label != null) {
			minWidth = (label.length() * Display.CHAR_WIDTH);
			minHeight = 2 * Display.CHAR_HEIGHT;
		} else {
			minWidth = Display.CHAR_WIDTH;
			minHeight = Display.CHAR_HEIGHT;
		}

		choiceItems = new ArrayList(stringElements.length);
		for (int i = 0; i < stringElements.length; i++) {
			choiceItems.add(new ChoiceItem(
					((stringElements != null) && (stringElements.length < i))
						? stringElements[i] : null, 
					((imageElements != null) && (imageElements.length < i))
						? imageElements[i] : null));
			
			// Update minimum width
			int itemWidth = (((stringElements != null) && (stringElements.length < i))
					? stringElements[i].length() * Display.CHAR_WIDTH : 0) 
				+ (((imageElements != null) && (imageElements.length < i))
					? imageElements[i].getWidth() : 0);
			if (itemWidth > minWidth) {
				minWidth = itemWidth;
			}
			scrollLast++;
		}
	}

	public int append(String stringPart, Image imagePart) {
		// Add item and update minimum size
		choiceItems.add(new ChoiceItem(stringPart, imagePart));
		int itemWidth = ((stringPart != null) ? stringPart.length() * Display.CHAR_WIDTH : 0)
			+ ((imagePart != null) ? imagePart.getWidth() : 0);
		if (itemWidth > minWidth) {
			minWidth = itemWidth;
		}
		
		scrollLast++;
		return choiceItems.size();
	}
	
	public void delete(int elementNum) {
		scrollLast--;
		choiceItems.remove(elementNum);
	}
	
	public void deleteAll() {
		scrollLast = 0;
		choiceItems.clear();
	}

// TODO: FitPolicy currently not supported: no wrapping allowed
//	  public int getFitPolicy() {
//		  return fitPolicy;
//	  }
//
//    public void setFitPolicy(int fitPolicy) {
//    	this.fitPolicy = fitPolicy;
//    }
	
//	 TODO: Multiple fonts currently not supported	
//	public Font getFont(int elementNum) {
//		return ((ListItem) listItems.get(elementNum)).font;
//	}
//	
//    public void setFont(int elementNum, Font font) {
//    	((ListItem) listItems.get(elementNum)).font = font;
//    } 
	
	public Image getImage(int elementNum) {
		return ((ChoiceItem) choiceItems.get(elementNum)).img;
	}

	public int getSelectedFlags(boolean[] selectedArray_return) {
		selectedArray_return = new boolean[choiceItems.size()];
		for (int i = 0; i < selectedArray_return.length; i++) {
			selectedArray_return[i] = ((ChoiceItem) choiceItems.get(i)).selected;
		}
		
		return selectedArray_return.length;
	}

	public int getSelectedIndex() {
		for (int i = 0; i < choiceItems.size(); i++) {
			if (((ChoiceItem) choiceItems.get(i)).selected) {
				return i;
			}
		}

		return -1;
	}

	public String getString(int elementNum) {
		return ((ChoiceItem) choiceItems.get(elementNum)).str;
	} 
	
	public void insert(int elementNum, String stringPart, Image imagePart) {
		choiceItems.add(elementNum, new ChoiceItem(stringPart, imagePart));
	}
	
	public boolean isSelected(int elementNum) {
		return ((ChoiceItem) choiceItems.get(elementNum)).selected;
	}

	public void set(int elementNum, String stringPart, Image imagePart) {
		choiceItems.set(elementNum, new ChoiceItem(stringPart, imagePart));
	}

    public void setScrollWrap(boolean scrollWrap) {
    	this.scrollWrap = scrollWrap;
    }
    
    public void setSelectedFlags(boolean[] selectedArray) {
		for (int i = 0; i < choiceItems.size(); i++) {
			((ChoiceItem) choiceItems.get(i)).selected = selectedArray[i];
		}
    } 

    public void setSelectedIndex(int elementNum, boolean selected) {
    	if ((choiceType == Choice.MULTIPLE) || !selected) {
			// Just set/clear selection
			((ChoiceItem) choiceItems.get(elementNum)).selected = selected;    		
    	} else {
			// Set single selection for these types
			for (int i = 0; i < choiceItems.size(); i++) {
				ChoiceItem li = ((ChoiceItem) choiceItems.get(i));
				li.selected = (i == elementNum);
			}
		} 
	}
    
    public int size() {
    	return choiceItems.size();
    }
    
	protected void keyPressed(int keyCode) {
		if (keyCode == Screen.KEY_RIGHT) {
			if (scrollWrap) {
				scrollCurr = (scrollCurr + 1) % choiceItems.size();
			} else if (scrollCurr < (choiceItems.size() - 1)) {
				scrollCurr++;
			}
			repaint();
		} else if (keyCode == Screen.KEY_LEFT) {
			if (scrollWrap) {
				scrollCurr = (scrollCurr == 0) 
					? (choiceItems.size() - 1) : (scrollCurr - 1);
			} else if (scrollCurr > 0) {
				scrollCurr--;
			}
			repaint();
		} else if (keyCode == Screen.KEY_BACK) {
			// BACK key has no function
		} else if (keyCode == Screen.KEY_ENTER) {
			ChoiceItem li = ((ChoiceItem) choiceItems.get(scrollCurr));
			setSelectedIndex(scrollCurr, !li.selected);

			notifyStateChanged();
		}
	}
    
	protected void paint(Graphics g, int x, int y, int w, int h, boolean selected) {
    	if (label != null) {
    		g.drawString(label, x, y, 
    				(selected && (choiceType == Choice.POPUP)));
    		y += Display.CHAR_HEIGHT;
    		h -= Display.CHAR_HEIGHT;
    	}

		if (h <= 0) {
			// No items allowed to draw (especially for POPUP)
			return;
		}

    	// Update scrolling administration
		int scrollLines = h / Display.CHAR_HEIGHT;
    	if (scrollCurr == 0) {
    		// Init top item
    		scrollFirst = 0;
    		scrollLast = scrollLines;
    	} else if ((choiceItems.size() >= scrollLines)
    			&& (scrollCurr >= (choiceItems.size() - 1))) {
    		// Init bottom item
    		scrollFirst = choiceItems.size() - scrollLines;
    		scrollLast = choiceItems.size() - 1;
    	} else if (scrollCurr >= scrollLast) {
    		scrollFirst++;
    		scrollLast++;
    	} else if (scrollCurr < scrollFirst) {
    		scrollFirst--;
    		scrollLast--;
    	}
    	
// TODO: Drawing a rectangle around menu would be nice, but is very slow    	
//    	if (choiceType == Choice.POPUP) {
//    		g.drawRect(x, y, w, h);
//    	}
    	
    	// Display list items with current highlighted
    	int xOffset = (choiceType == Choice.POPUP) ? x : (x + 2 * Display.CHAR_WIDTH);
		for (int i = scrollFirst; (i < choiceItems.size()) && (i <= scrollLast); i++) {
			ChoiceItem li = ((ChoiceItem) choiceItems.get(i));
			g.drawString(li.str, xOffset, y, 
					(selected && (i == scrollCurr)));
			
			if ((choiceType == Choice.EXCLUSIVE) || (choiceType == Choice.MULTIPLE)) {
				// Draw selection state
				if (li.selected) {
					g.fillArc(x, y, 8, 8, 0, 360);
				} else {
					g.drawArc(x, y, 8, 8, 0, 360);
				}
//			} else if (choiceType == Choice.POPUP) {
//	TODO Filling remaing text withing rectangle is even slower...
//				for (int j = li.str.length(); j < (w * Display.CHAR_WIDTH); j++) {
//					g.drawChar(' ', xOffset + li.str.length() * Display.CHAR_WIDTH, 
//							y / Display.CHAR_HEIGHT, (i == scrollCurr));
//				}
			}
			
			y += Display.CHAR_HEIGHT;
			h -= Display.CHAR_HEIGHT;
			if (h <= 0) {
				// No more items allowed
				break;
			}
		}
	}
    
    private class ChoiceItem {
    	String str;
    	Image img;
    	boolean selected;
//    	Font font;

    	ChoiceItem(String stringPart, Image imagePart) {
    		this.str = stringPart;
    		this.img = imagePart;
    		this.selected = false;
//    		this.font = null;
    	}    	
    }
}
