/*
 * Created on Dec 31, 2003
 *
 */
package LumiSoft.UI.Controls;

import java.awt.*;
import java.awt.event.*;

import javax.swing.event.*;

/**
 * CheckBox control.
 */
public class WCheckBox extends WControl
{
	private EventListenerList m_pListners      = null;
	private boolean           m_Checked        = false;
	private boolean           m_ReadOnly       = false;
	private int               m_CheckAreaAlign = HorizontalAlignment.Left;
	private Point             m_MousePos       = new Point(-1,-1);
//	private int               m_MouseModifiers = 0;
	
	/**
	 * Default constructor.
	 *
	 */
	public WCheckBox()
	{
		super();
		
		m_pListners = new EventListenerList();
		
		this.setFocusable(true);
		this.setOpaque(false);
		this.setMinimumSize(new Dimension(12,12));
		
		this.addFocusListener(new FocusAdapter(){
			public void focusGained(FocusEvent e){
				OnFocusGained(e);
			}
			
			public void focusLost(FocusEvent e){
				OnFocusLost(e);
			}
		});
		this.addKeyListener(new KeyAdapter(){
			public void keyReleased(KeyEvent e){
				OnKeyReleased(e);
			}
		});
		this.addMouseListener(new MouseAdapter(){
			public void mousePressed(MouseEvent e){
				OnMousePressed(e);
			}
			
			public void mouseReleased(MouseEvent e){
				OnMouseReleased(e);
			}
			
			public void mouseEntered(MouseEvent e){
				OnMouseEntered(e);
			}
			
			public void mouseExited(MouseEvent e){
				OnMouseExited(e);
			}
		});
		this.addMouseMotionListener(new MouseMotionAdapter(){
			public void mouseMoved(MouseEvent e){
				OnMouseMoved(e);
			}
		});
	}
	
	/**
	 * Is called by system when control need to repaint.
	 */
	public void paintComponent(Graphics g)
	{
		Rectangle clientRect = new Rectangle(0,0,this.getSize().width,this.getSize().height);
		boolean hot = this.hasFocus() || clientRect.contains(m_MousePos);
		DrawCheckBox((Graphics2D)g,hot);
	}
	
	/**
	 * Draws checkbox.
	 * @param g Graphics where to draw.
	 * @param hot Specifies if checkbox is hot.
	 */
	private void DrawCheckBox(Graphics2D g,boolean hot)
	{	
		// Fill check rect backround
		g.setColor(getViewStyle().GetEditColor(this.getReadOnly(),this.isEnabled(),this.hasFocus()));
		g.fill(this.getCheckRect());
		
		if(m_Checked){
			// Draw check (Lines from up to down).
			g.setColor(Color.BLACK);
			g.drawLine(this.getCheckRect().x + 3,this.getCheckRect().y + 5,this.getCheckRect().x + 3,this.getCheckRect().y + 5 + 2);
			g.drawLine(this.getCheckRect().x + 4,this.getCheckRect().y + 6,this.getCheckRect().x + 4,this.getCheckRect().y + 6 + 2);
			g.drawLine(this.getCheckRect().x + 5,this.getCheckRect().y + 7,this.getCheckRect().x + 5,this.getCheckRect().y + 7 + 2);
			g.drawLine(this.getCheckRect().x + 6,this.getCheckRect().y + 6,this.getCheckRect().x + 6,this.getCheckRect().y + 6 + 2);
			g.drawLine(this.getCheckRect().x + 7,this.getCheckRect().y + 5,this.getCheckRect().x + 7,this.getCheckRect().y + 5 + 2);
			g.drawLine(this.getCheckRect().x + 8,this.getCheckRect().y + 4,this.getCheckRect().x + 8,this.getCheckRect().y + 4 + 2);
			g.drawLine(this.getCheckRect().x + 9,this.getCheckRect().y + 3,this.getCheckRect().x + 9,this.getCheckRect().y + 3 + 2);
		}
		
		// Draw rect around check
		g.setColor(getViewStyle().GetBorderColor(isEnabled() && hot));
		g.draw(this.getCheckRect());		
	}
	
	
	/**
	 * Is called when focus has gained.
	 * @param e
	 */	
	private void OnFocusGained(FocusEvent e)
	{
		this.repaint();
	}
	
	/**
	 * Is called when focus has lost.
	 * @param e
	 */
	private void OnFocusLost(FocusEvent e)
	{
		this.repaint();
	}
	
	/**
	 * Is called when key has released.
	 * @param e
	 */
	private void OnKeyReleased(KeyEvent e)
	{
		if(e.getKeyCode() == KeyEvent.VK_SPACE && this.isEnabled() && !m_ReadOnly){
			ToggleChecked();
			RaiseCheckedChanged();
		}
	}
	
	/**
	 * Is called when mouse has pressed down.
	 * @param e
	 */
	private void OnMousePressed(MouseEvent e)
	{
//		m_MouseModifiers = e.getModifiersEx();
		
		this.repaint();
	}
	
	/**
	 * Is called when mouse has released.
	 * @param e
	 */
	private void OnMouseReleased(MouseEvent e)
	{
		// Reset, we don't need them anymore
//		m_MouseModifiers = 0;
		
		if(this.isEnabled() && !m_ReadOnly){
			ToggleChecked();
			RaiseCheckedChanged();
		}		
	}
	
	/**
	 * Is called when mouse cursor has entered to this control.
	 * @param e
	 */
	private void OnMouseEntered(MouseEvent e)
	{			
		this.repaint();
	}
	
	/**
	 * Is called when mouse cursor has exited this control.
	 * @param e
	 */
	private void OnMouseExited(MouseEvent e)
	{
		m_MousePos = new Point(-1,-1);
		
		this.repaint();
	}
	
	/**
	 * Is called when mouse has moved.
	 * @param e
	 */
	public void OnMouseMoved(MouseEvent e)
	{
		m_MousePos = e.getPoint();
	}
	
	
	/**
	 * Toggles checked state.
	 *
	 */
	public void ToggleChecked()
	{
		if(m_Checked){
			m_Checked = false;			
		}
		else{
			m_Checked = true;
		}
		
		this.repaint();
	}
	
	
	/**
	 * Gets if checkbox is checked.
	 * @return
	 */
	public boolean getChecked()
	{
		return m_Checked;
	}
	/**
	 * Sets checkbox is checked.
	 * @param value
	 */
	public void setChecked(boolean value)
	{
		if(m_Checked != value){
			m_Checked = value;
			
			this.repaint();
		}
	}
	
	/**
	 * Gets if checkbox is readonly.
	 * @return
	 */
	public boolean getReadOnly()
	{
		return m_ReadOnly;
	}
	/**
	 * Sets if checkbox is readonly.
	 * @param value
	 */
	public void setReadOnly(boolean value)
	{
		if(m_ReadOnly != value){
			m_ReadOnly = value;			
		}
	}
	
	/**
	 * Gets check area alignment.
	 * @return
	 */
	public int getCheckAreaAlign()
	{
		return m_CheckAreaAlign;
	}
	/**
	 * Sets check area alignment.
	 * @param value
	 */
	public void setCheckAreaAlign(int value)
	{
		if(m_CheckAreaAlign != value){
			m_CheckAreaAlign = value;
			
			this.repaint();
		}
	}
	
	
	/**
	 * Gets checkbox rectangle.
	 * @return
	 */
	private Rectangle getCheckRect()
	{
		switch(m_CheckAreaAlign)
		{
			case HorizontalAlignment.Center:
				return new Rectangle((this.getWidth() - 12) / 2,(this.getHeight() - 13) / 2,12,12);
			case HorizontalAlignment.Left:
				return new Rectangle(0,(this.getHeight() - 13) / 2,12,12);
			case HorizontalAlignment.Right:
				return new Rectangle(this.getWidth() - 13,(this.getHeight() - 13) / 2,12,12);				
			
		}
		
		return null;
	}
	
	
	/**
	 * Adds the specified action listener to receive action events
	 * from this button.
	 * @param l the action listener
	 */ 
	public void addCheckedChangedListener(ActionListener l) 
	{
		m_pListners.add(ActionListener.class,l);
	}

	/**
	 * Removes the specified action listener so it no longer receives
	 * action events from this button.
	 * @param l the action listener
	 */ 
	public void removeCheckedChangedListener(ActionListener l) 
	{
		m_pListners.remove(ActionListener.class,l);
	}
	
	/**
	 * Raises checked changed event.
	 *
	 */
	protected void RaiseCheckedChanged()
	{
		Object[] listeners = m_pListners.getListenerList();
		// loop through each listener and pass on the event if needed		
		for(int i=0;i < listeners.length;i++){
			if(listeners[i] == ActionListener.class){
				// pass the event to the listeners event dispatch method
				((ActionListener)listeners[i+1]).actionPerformed(new ActionEvent(this,1,""));
			}            
		}
	}

}
