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

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

import javax.swing.event.*;
import LumiSoft.UI.Controls.Paint;

/**
 * Tabbar control.
 */
public class WTabBar extends WControl
{
	private EventListenerList m_pListners        = null;
	private WTabBarItems      m_pTabs            = null;
	private WTabBarItem       m_pSelectedTab     = null;
	private int               m_FVisibleTabIndex = 0;
	private ImageList         m_ImageList        = null;
	private Object            m_ActiveObj        = null;
	private Point             m_MousePos         = new Point(0,0);
//	private int               m_MouseModifiers   = 0;

	/**
	 * Default constructor.
	 *
	 */
	public WTabBar()
	{		
		m_pTabs = new WTabBarItems(this);
		m_pListners = new EventListenerList();

		this.setMinimumSize(new Dimension(50,22));
		
		this.addMouseListener(new MouseAdapter(){
			public void mousePressed(MouseEvent e){
				OnMousePressed(e);
			}
			
			public void mouseReleased(MouseEvent e){
				OnMouseReleased(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)
	{		
		CalcDrawInfo((Graphics2D)g);
		
		DrawTabs((Graphics2D)g);
		DrawButtons((Graphics2D)g);
	}

	
	private void DrawTabs(Graphics2D g)
	{	
		Rectangle clientRect = new Rectangle(0,0,this.getSize().width,this.getSize().height);
		
		g.setColor(ViewStyle.GetColorFromRgb(247,243,233));
		g.fill(clientRect);
	
		g.setColor(Color.BLACK);
		g.drawRect(0,0,this.getWidth() - 1,this.getHeight() - 2);
		
		Shape clip = g.getClip(); 
		g.setClip(new Rectangle(0,0,(int)this.getWidth() - (int)this.getBtnsRect().getWidth(),this.getHeight()));

		for(WTabBarItem tab : getTabs().getVisibleItems()){
			boolean hot = tab.getBounds().contains(m_MousePos) && !this.getBtnsRect().contains(m_MousePos);		
			if(tab.getBounds().x > - 1 && clip.getBounds().intersects(tab.getBounds())){
				DrawTab(g,tab,hot,tab.equals(m_pSelectedTab));
			}
		}

		// Restore old clip area
		g.setClip(clip);
	}

	private void DrawTab(Graphics2D g,WTabBarItem tab,boolean hot,boolean selected)
	{
		//--- Fill selected tab backround
		if(selected){
			g.setColor(ViewStyle.GetColorFromRgb(212,208,200));
			g.fill(new Rectangle(tab.getBounds().x - 1,tab.getBounds().y + 3,tab.getBounds().width,tab.getBounds().height - 3));
		}
		
		//--- Draw caption
		if(hot){
			if(tab.getEnabled()){
				g.setColor(Color.BLUE);
			}
			else{
				g.setColor(Color.RED);
			}
		}
		else{
			if(selected){
				g.setColor(Color.BLACK);				
			}
			else{
				g.setColor(Color.GRAY);				
			}			
		}
		
		Paint.DrawText(g,this.getFont(),tab.getText(),tab.getTextRect(),HorizontalAlignment.Left);
		//------------------------------------------------------------------------------------------//
		
		//---- Draw right side tab border
		if(selected){
			g.setColor(Color.BLACK);
			g.drawLine((int)tab.getBounds().getMaxX() - 1,4,(int)tab.getBounds().getMaxX() - 1,this.getHeight() - 3);							
		}
		else{
			g.setColor(Color.GRAY);
			g.drawLine((int)tab.getBounds().getMaxX() - 1,4,(int)tab.getBounds().getMaxX() - 1,this.getHeight() - 6);
		}
				
		//---- Draw item image 			
		if(m_ImageList != null && tab.getImageIndex() > -1 && tab.getImageIndex() < m_ImageList.getCount()){
			if(tab.getEnabled()){				
				g.drawImage(m_ImageList.get(tab.getImageIndex()),tab.getImageRect().x,tab.getImageRect().y,this);
			}
			else{		
				g.drawImage(m_ImageList.get(tab.getImageIndex()),tab.getImageRect().x,tab.getImageRect().y,this);
			}				
		}
	}
	
	private Rectangle GetArrowRect(Rectangle rect)
	{
		int w = rect.width - 11;
		int h = rect.height - 7;
		int x = rect.x + (rect.width - w) / 2;
		int y = rect.y + (rect.height - h) / 2;
		
		return new Rectangle(x,y,w,h);
	}
		
	private void DrawButtons(Graphics2D g)
	{
		g.setColor(ViewStyle.GetColorFromRgb(212,208,200));
		g.fillRect(this.getBtnsRect().x,this.getBtnsRect().y - 1,this.getBtnsRect().width,this.getBtnsRect().height + 1);
		
		//--- Draw buttons ------------------------------------------
		Rectangle rect = null;
		
		g.setColor(Color.BLACK);		
		if(!this.getIsFirstBtnEnabled()){
			g.setColor(Color.GRAY);
		}
		rect = GetArrowRect(this.getFirstBtnRect());
		Paint.DrawTriangle(g,rect,Direction.Left);
		g.drawLine(rect.x - 2,rect.y,rect.x - 2,(int)rect.getMaxY() - 1);
		
		g.setColor(Color.BLACK);		
		if(!this.getIsPrevBtnEnabled()){
			g.setColor(Color.GRAY);
		}
		rect = GetArrowRect(this.getPrevBtnRect());
		Paint.DrawTriangle(g,rect,Direction.Left);
		
		g.setColor(Color.BLACK);		
		if(!this.getIsNextBtnEnabled()){
			g.setColor(Color.GRAY);
		}
		rect = GetArrowRect(this.getNextBtnRect());
		Paint.DrawTriangle(g,rect,Direction.Right);
		
		g.setColor(Color.BLACK);		
		if(!this.getIsLastBtnEnabled()){
			g.setColor(Color.GRAY);
		}
		rect = GetArrowRect(this.getLastBtnRect());
		Paint.DrawTriangle(g,rect,Direction.Right);
		g.drawLine((int)rect.getMaxX() + 1,rect.y,(int)rect.getMaxX() + 1,(int)rect.getMaxY() - 1);
		//------------------------------------------------------------
			
						
		//------------- Draw hot -----------------------------------------------------------------------------------//
		if(this.getFirstBtnRect().contains(m_MousePos)){
			g.setColor(Color.WHITE);
			g.drawLine(this.getFirstBtnRect().x - 1,1,this.getFirstBtnRect().x - 1,this.getHeight() - 4);
			g.drawLine(this.getFirstBtnRect().x - 1,1,(int)this.getFirstBtnRect().getMaxX() - 1,1);			
			g.setColor(Color.GRAY);
			g.drawLine((int)this.getFirstBtnRect().getMaxX() - 1,1,(int)this.getFirstBtnRect().getMaxX() - 1,this.getHeight() - 4);
		}
		
		if(this.getPrevBtnRect().contains(m_MousePos)){
			g.setColor(Color.WHITE);
			g.drawLine(this.getPrevBtnRect().x - 1,1,this.getPrevBtnRect().x - 1,this.getHeight() - 4);
			g.drawLine(this.getPrevBtnRect().x - 1,1,(int)this.getPrevBtnRect().getMaxX() - 1,1);		
			g.setColor(Color.GRAY);
			g.drawLine((int)this.getPrevBtnRect().getMaxX() - 1,1,(int)this.getPrevBtnRect().getMaxX() - 1,this.getHeight() - 4);
		}

		if(this.getNextBtnRect().contains(m_MousePos)){
			g.setColor(Color.WHITE);
			g.drawLine(this.getNextBtnRect().x - 1,1,this.getNextBtnRect().x - 1,this.getHeight() - 4);
			g.drawLine(this.getNextBtnRect().x - 1,1,(int)this.getNextBtnRect().getMaxX() - 1,1);		
			g.setColor(Color.GRAY);
			g.drawLine((int)this.getNextBtnRect().getMaxX() - 1,1,(int)this.getNextBtnRect().getMaxX() - 1,this.getHeight() - 4);	
	
		}

		if(this.getLastBtnRect().contains(m_MousePos)){
			g.setColor(Color.WHITE);
			g.drawLine(this.getLastBtnRect().x - 1,1,this.getLastBtnRect().x - 1,this.getHeight() - 4);
			g.drawLine(this.getLastBtnRect().x - 1,1,(int)this.getLastBtnRect().getMaxX() - 1,1);			
			g.setColor(Color.GRAY);
			g.drawLine((int)this.getLastBtnRect().getMaxX() - 1,1,(int)this.getLastBtnRect().getMaxX() - 1,this.getHeight() - 4);
		}
		//------------------------------------------------------------------------------------------------------------//
	/*			

		//---- Draw white line at the right edge
		g.DrawLine(new Pen(Color.White),this.Right-1,0,this.Right-1,this.Height);*/
	}

	private void CalcDrawInfo(Graphics2D g)
	{			
		int tRight = 5;
			
		//--- loop through all tabs ------//
		for(int i=0;i<m_pTabs.getCount();i++){
			WTabBarItem tab = this.getTabs().get(i);

			if(i >= m_FVisibleTabIndex){
				int width = CalcTabWidth(g,tab) + 10;
				tab.setBounds(new Rectangle(tRight,1,width,this.getHeight() - 1));
				tRight += width;
			}
			else{
				tab.setBounds(new Rectangle(-1,-1,0,0));
			}
		}
	}

	private int CalcTabWidth(Graphics2D g,WTabBarItem tab)
	{
		int size = Paint.CalcTextWidth(g,this.getFont(),tab.getText());
		if(tab.getImageIndex() > -1){
			size += 16 + 4;
		}
		return size;
	}
	
	
	/**
	 * Is called when UI language has changed.
	 */
	protected void OnLanguageChanged()
	{
		this.repaint();
	}
	
	/**
	 * Is called when mouse has pressed down.
	 * @param e
	 */
	private void OnMousePressed(MouseEvent e)
	{
//		m_MouseModifiers = e.getModifiersEx();
	}
	
	/**
	 * Is called when mouse has released.
	 * @param e
	 */
	private void OnMouseReleased(MouseEvent e)
	{
		// Reset, we don't need them anymore
//		m_MouseModifiers = 0;
		
		//--- Check if some scroll button clicked
		if(this.getBtnsRect().contains(m_MousePos)){
			if(this.getIsFirstBtnEnabled() && this.getFirstBtnRect().contains(m_MousePos)){
				m_FVisibleTabIndex = 0;
			}

			if(this.getIsPrevBtnEnabled() && this.getPrevBtnRect().contains(m_MousePos)){
				m_FVisibleTabIndex--;
			}

			if(this.getIsNextBtnEnabled() && this.getNextBtnRect().contains(m_MousePos)){
				m_FVisibleTabIndex++;
			}

			if(this.getIsLastBtnEnabled() && this.getLastBtnRect().contains(m_MousePos)){
				WTabBarItem lastTab = this.getTabs().get(this.getTabs().getCount() - 1);
				while(m_FVisibleTabIndex < this.getTabs().getCount() - 1){
					m_FVisibleTabIndex++;

					if(lastTab.getBounds().getMaxX() < this.getBtnsRect().x){
						break;
					}
				}				
			}
			
			this.repaint();

			return;
		}
		
		//--- Check if some tab hitted
		for(int i=0;i<m_pTabs.getCount();i++){
			WTabBarItem tab = (WTabBarItem)this.getTabs().get(i);
		
			if(tab.getBounds().contains(m_MousePos) && tab.getEnabled() && !tab.equals(this.getSelectedTab())){
				this.setSelectedTab(tab);
				MakeTabVisible(tab);
				break;
			}
		}
	}
	
	/**
	 * Is called when mouse cursor has exited this control.
	 * @param e
	 */
	private void OnMouseExited(MouseEvent e)
	{
		m_MousePos = new Point(-1,-1);
//		m_MouseModifiers = 0;
		m_ActiveObj = null;
		this.repaint();
	}
	
	/**
	 * Is called when mouse has moved.
	 * @param e
	 */
	public void OnMouseMoved(MouseEvent e)
	{
		m_MousePos = e.getPoint();
		
		Object activeItem = "";
		
		// Buttons
		if(this.getBtnsRect().contains(m_MousePos)){
			if(this.getFirstBtnRect().contains(m_MousePos)){
				activeItem = "FirstButton";				
			}
			if(this.getPrevBtnRect().contains(m_MousePos)){
				activeItem = "PrevButton";	
			}
			if(this.getNextBtnRect().contains(m_MousePos)){
				activeItem = "NextButton";	
			}
			if(this.getLastBtnRect().contains(m_MousePos)){
				activeItem = "LastButton";	
			}
		}
		else{
			// Tab
			WTabBarItem t = GetMouseTab();
			if(t != null){
				activeItem = t;
			}
			// TabControl
			else{
				activeItem = "tabcontrol";
			}
		}

		if(activeItem != m_ActiveObj){
			m_ActiveObj = activeItem;
			this.repaint();
		}
	}
	
		
	/**
	 * Gets tab which is mouse cursor.
	 * @return
	 */
	private WTabBarItem GetMouseTab()
	{
		//--- loop through all tabs ------//
		for(WTabBarItem tab : getTabs().getVisibleItems()){
			if(tab.getBounds().contains(m_MousePos)){
				return tab;
			}
		}

		return null;
	}

	/**
	 * Makes specified tab visible (scrolls to visible area).
	 * @param tab
	 */
	public void MakeTabVisible(WTabBarItem tab)
	{
		if(tab.getBounds().x < 0 || tab.getBounds().getMaxX() > this.getBtnsRect().x){
			while(m_FVisibleTabIndex < this.getTabs().getCount() - 1){
				m_FVisibleTabIndex++;
				CalcDrawInfo((Graphics2D)this.getGraphics());
				
				if(tab.getBounds().getMaxX() < this.getBtnsRect().x){
					break;
				}
			}
			this.repaint();
		}
	}
	
	
	/**
	 * Makes first tab visible.
	 *
	 */
	public void SelectFirstTab()
	{
		if(this.getTabs().getCount() > 0){
			MakeTabVisible((this.getTabs().get(0)));
		}
	}
	

	/**
	 * Gets tabs collection. 
	 */
	public WTabBarItems getTabs()
	{
		return m_pTabs;
	}
	
	/**
	 * Gets selected tab.
	 * @return
	 */
	public WTabBarItem getSelectedTab()
	{
		return m_pSelectedTab;
	}
	/**
	 * Sets selected tab.
	 * @param s
	 */
	public void setSelectedTab(WTabBarItem s)
	{
		if(m_pSelectedTab != s){
			// Raise event
			OnSelectedTabChanged(s,m_pSelectedTab);
			
			m_pSelectedTab = s;
			this.repaint();
		}
	}
	
	/**
	 * Gets imagelist.
	 * @return
	 */
	public ImageList getImageList()
	{
		return m_ImageList;
	}
	/**
	 * Sets imagelist.
	 * @param s
	 */
	public void setImageList(ImageList s)
	{
		if(m_ImageList != s){
			m_ImageList = s;
			this.repaint();
		}
	}
	

	private Rectangle getBtnsRect()
	{
		return new Rectangle(this.getWidth() - 68,2,67,this.getHeight() - 4);
	}

	private Rectangle getFirstBtnRect()
	{
		return new Rectangle(this.getWidth() - 67,5,16,16);
	}

	private Rectangle getPrevBtnRect()
	{
		return new Rectangle(this.getWidth() - 51,5,16,16);
	}

	private Rectangle getNextBtnRect()
	{
		return new Rectangle(this.getWidth() - 34,5,16,16);
	}

	private Rectangle getLastBtnRect()
	{
		return new Rectangle(this.getWidth() - 17,5,16,16);
	}

	private boolean getIsFirstBtnEnabled()
	{		
		if(m_pTabs.getCount() > 0){
			WTabBarItem t = this.getTabs().get(0);
			if(t.getBounds().x < 1){
				return true;
			}
		}
			
		return false;
		
	}

	private boolean getIsPrevBtnEnabled()
	{
		if(m_pTabs.getCount() > 0){
			WTabBarItem t = this.getTabs().get(0);
			if(t.getBounds().x > 5 || m_FVisibleTabIndex > 0){ // 5 is left for first tab
				return true;
			}
		}

		return false;		
	}

	private boolean getIsNextBtnEnabled()
	{
		if(m_pTabs.getCount() > 0){
			WTabBarItem t = this.getTabs().get(this.getTabs().getCount() - 1);
			if(t.getBounds().getMaxX() > this.getBtnsRect().x){
				return true;
			}
		}

		return false;	
	}

	private boolean getIsLastBtnEnabled()
	{
		if(m_pTabs.getCount() > 0){
			WTabBarItem t = this.getTabs().get(this.getTabs().getCount() - 1);		
			if(t.getBounds().getMaxX() > this.getBtnsRect().x){
				return true;
			}
		}

		return false;		
	}
	
	
	/**
	 * Adds the specified action listener to receive action events
	 * from this button.
	 * @param l the action listener
	 */ 
	public void addTabChangedListener(WTabListener l) 
	{
		m_pListners.add(WTabListener.class,l);
	}

	/**
	 * Removes the specified action listener so it no longer receives
	 * action events from this button.
	 * @param l the action listener
	 */ 
	public void removeTabChangedListener(WTabListener l) 
	{
		m_pListners.remove(WTabListener.class,l);
	}
	
	protected void OnSelectedTabChanged(WTabBarItem newTab,WTabBarItem oldTab)
	{
		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] == WTabListener.class){
				// pass the event to the listeners event dispatch method
				((WTabListener)listeners[i+1]).TabChanged(this,newTab,oldTab);
			}            
		}
	}

}
