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

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

import javax.swing.event.*;

/**
 * Spin edit control.
 */
public class WSpinEdit_base extends WControl
{	
	private EventListenerList m_pListners       = null;
	private int               m_SpinnersAlign   = LeftRight.Right;
	private boolean           m_SpinnersVisible = true;
	private int               m_ButtonWidth     = 14;
	private Point             m_MousePos        = new Point(-1,-1);
	private int               m_MouseModifiers  = 0;
	private String            m_HittedObject    = "";
	private Dimension         m_Size            = new Dimension(0,0);
	private boolean           m_ReadOnly        = false;
	
	/**
	 * Default constructor.
	 *
	 */
	public WSpinEdit_base()
	{
		super();
		
		m_pListners = new EventListenerList();
						
		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)
	{
		if(m_Size != this.getSize()){
			m_Size = this.getSize();
			
			SizeChanged();			
		}
		
		Draw((Graphics2D)g);
	}
					
	private void Draw(Graphics2D g)
	{
		Rectangle clientRect = new Rectangle(0,0,this.getSize().width,this.getSize().height);
		boolean hot = isEnabled() && (Utils.ContainsFocus(this) || clientRect.contains(m_MousePos));
		
		// Fill backround
		g.setColor(getViewStyle().GetEditColor(getReadOnly(),isEnabled(),Utils.ContainsFocus(this)));		
		g.fill(clientRect);
		
		//--- Draw buttons -------------------------------------------------------
		if(this.getSpinnersVisible()){
			boolean upHot   = isEnabled() && this.getUpButtonRect().contains(m_MousePos);
			boolean downHot = isEnabled() && this.getDownButtonRect().contains(m_MousePos);
					
			// Draw up button
			g.setColor(getViewStyle().GetButtonColor(upHot,m_MouseModifiers == MouseEvent.BUTTON1_DOWN_MASK));
			g.fill(this.getUpButtonRect());
			if(isEnabled()){
				g.setColor(Color.BLACK);
			}
			else{
				g.setColor(Color.GRAY);
			}
			Paint.DrawTriangle(g,getTriangleRect(getUpButtonRect()),Direction.Up);
			
			// Draw down button
			g.setColor(getViewStyle().GetButtonColor(downHot,m_MouseModifiers == MouseEvent.BUTTON1_DOWN_MASK));
			g.fill(this.getDownButtonRect());
			if(isEnabled()){
				g.setColor(Color.BLACK);
			}
			else{
				g.setColor(Color.GRAY);
			}
			Paint.DrawTriangle(g,getTriangleRect(getDownButtonRect()),Direction.Down);
		}
		//-------------------------------------------------------------------------
		
		// Draw borders
		g.setColor(getViewStyle().GetBorderColor(hot));
		g.drawRect(0,0,this.getWidth() - 1,this.getHeight() - 1);
		g.drawLine(this.getButtonsRect().x,0,this.getButtonsRect().x,this.getHeight());
		g.drawLine((int)this.getButtonsRect().getMaxX(),0,(int)this.getButtonsRect().getMaxX(),this.getHeight());
		g.drawLine(this.getButtonsRect().x,this.getHeight() / 2,(int)this.getButtonsRect().getMaxX(),this.getHeight() / 2);
	}
	
	
	/**
	 * Is called when size has changed.
	 *
	 */
	protected void SizeChanged()
	{		
	}
	
	/**
	 * Is called when mouse has pressed down.
	 * @param e
	 */
	protected void OnMousePressed(MouseEvent e)
	{
		m_MouseModifiers = e.getModifiersEx();
		
		this.repaint();
	}
	
	/**
	 * Is called when mouse has released.
	 * @param e
	 */
	protected void OnMouseReleased(MouseEvent e)
	{
		// Reset, we don't need them anymore
		m_MouseModifiers = 0;
		
		if(!isEnabled()){
			return;
		}
		
		if(this.getUpButtonRect().contains(m_MousePos)){
			OnUpButtonClicked();
			OnValueChanged();
		}
		else if(this.getDownButtonRect().contains(m_MousePos)){
			OnDownButtonClicked();
			OnValueChanged();
		}
		
		this.repaint();
	}
	
	/**
	 * Is called when mouse cursor has entered to this control.
	 * @param e
	 */
	protected void OnMouseEntered(MouseEvent e)
	{
		this.repaint();
	}
	
	/**
	 * Is called when mouse cursor has exited this control.
	 * @param e
	 */
	protected void OnMouseExited(MouseEvent e)
	{
		m_MousePos = new Point(-1,-1);
		
		this.repaint();
	}
	
	/**
	 * Is called when mouse has moved.
	 * @param e
	 */
	protected void OnMouseMoved(MouseEvent e)
	{
		m_MousePos = e.getPoint();
		
		String hittedObject = "";
		if(this.getUpButtonRect().contains(m_MousePos)){
			hittedObject = "upButtons";			
		}
		else if(this.getDownButtonRect().contains(m_MousePos)){
			hittedObject = "downButtons";
		}
		
		if(m_HittedObject != hittedObject){
			m_HittedObject = hittedObject;
			
			this.repaint();
		}		
	}
	
	
	private Rectangle getTriangleRect(Rectangle buttonRect)
	{
		return new Rectangle(buttonRect.x + 3,buttonRect.y + 3,buttonRect.width - 5,buttonRect.height - 5);
	}
	
	private Rectangle getButtonsRect()
	{
		if(this.getSpinnersVisible()){
			if(m_SpinnersAlign == LeftRight.Right){
				return new Rectangle(this.getWidth() - m_ButtonWidth,1,m_ButtonWidth - 1,this.getHeight() - 2);
			}
			else{
				return new Rectangle(0,0,m_ButtonWidth - 1,this.getHeight() - 2);
			}
		}
		else{
			return new Rectangle(0,0,0,0);
		}
	}
	
	private Rectangle getUpButtonRect()
	{
		Rectangle rectButton = getButtonsRect();
		Rectangle retVal = new Rectangle(rectButton.x,rectButton.y,rectButton.width,rectButton.height / 2);
		return retVal;
	}

	private Rectangle getDownButtonRect()
	{
		Rectangle rectButton = this.getButtonsRect();
		Rectangle retVal = new Rectangle(rectButton.x,rectButton.height / 2 + 1,rectButton.width,rectButton.height / 2);
		return retVal;
	}
	
	protected Rectangle getEditRect()
	{
		if(m_SpinnersAlign == LeftRight.Right){
			return new Rectangle(2,1,this.getWidth() - this.getButtonsRect().width - 4,this.getHeight() - 2);
		}
		else{
			return new Rectangle((int)this.getButtonsRect().getMaxX() + 2,1,this.getWidth() - this.getButtonsRect().width - 4,this.getHeight() - 2);
		}
	}
	
	
	/**
	 * Gets if numeric box is readonly.
	 * @return
	 */
	public boolean getReadOnly()
	{
		return m_ReadOnly;
	}
	/**
	 * Sets if numeric box is readonly.
	 * @param value
	 */
	public void setReadOnly(boolean value)
	{
		if(m_ReadOnly != value){
			m_ReadOnly = value;
		}
	}
	
	/**
	 * Gets if spinners visible.
	 * @return
	 */
	public boolean getSpinnersVisible()
	{
		return m_SpinnersVisible;
	}
	/**
	 * Sets if spinners visible.
	 * @param value
	 */
	public void setSpinnersVisible(boolean value)
	{	
		if(m_SpinnersVisible != value){
			m_SpinnersVisible = value;
			
			this.repaint();
		}
	}
	
	/**
	 * Gets if spinners alignment.
	 * @return
	 */
	public int getSpinnersAlign()
	{
		return m_SpinnersAlign;
	}
	/**
	 * Sets if spinners alignment.
	 * @param value
	 */
	public void setSpinnersAlign(int value)
	{	
		if(m_SpinnersAlign != value){
			m_SpinnersAlign = value;
			
			this.repaint();
		}
	}
	
	
	/**
	 * Adds the specified action listener to receive action events
	 * from this button.
	 * @param l the action listener
	 */ 
	public void addValueChangedListener(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 removeValueChangedListener(ActionListener l) 
	{
		m_pListners.remove(ActionListener.class,l);
	}
	
	/**
	 * Raises ValueChanged event.
	 *
	 */
	protected void OnValueChanged()
	{
		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,""));
			}            
		}
	}
	
	protected void OnUpButtonClicked()
	{
		
	}
	protected void OnDownButtonClicked()
	{
		
	}

}
