/*
 * Created on Jan 12, 2004
 *
 */
package LumiSoft.UI.Controls;

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

import javax.swing.*;
import java.util.ArrayList;
import LumiSoft.UI.Controls.Paint;

/**
 * Context menu popup windows.
 */
public class WContextMenuPopup extends JWindow implements HierarchyBoundsListener
{
	private ViewStyle m_ViewStyle          = null;
			
	private WContextMenu         m_pOwner         = null;
	private Component            m_pParent        = null;
	private ArrayList<WMenuItem> m_pItems         = null;
	private WMenuItem            m_pHotItem       = null;
	private WContextMenu         m_pActiveSubMenu = null;
	private Point                m_MousePos       = new Point(-1,-1);
	
	/**
	 * Default constructor.
	 */
	public WContextMenuPopup(WContextMenu owner,Component parent,ArrayList<WMenuItem> menuItems,ImageList imageList)
	{	
		super(SwingUtilities.getWindowAncestor(parent));
		
		m_pOwner = owner;		
		
		m_pParent = parent;
		m_pParent.addHierarchyBoundsListener(this);
		
		m_pItems = menuItems;
		
		m_ViewStyle = new ViewStyle();
						
		this.setFocusable(false);
		this.addMouseListener(new MouseAdapter(){			
			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 paint(Graphics g)
	{	
		Image imageBuffer = this.createImage(this.getWidth(),this.getHeight());
		Graphics2D gBuffer = (Graphics2D)imageBuffer.getGraphics();
		
		// Fill backoround
		gBuffer.setColor(Color.WHITE);
		gBuffer.fill(new Rectangle(0,0,this.getWidth(),this.getHeight()));
		
		// Draw icon frame
		gBuffer.setColor(ViewStyle.GetColorFromRgb(220,212,198));
		gBuffer.fill(new Rectangle(0,2,24,this.getHeight() - 4));
						
		int y = 2;
		for(WMenuItem item : m_pItems){
			if(item.getSeparator()){
				item.setBounds(new Rectangle(1,y,this.getWidth() - 1,4));
				y += 4;
			}
			else{
				item.setBounds(new Rectangle(1,y,this.getWidth() - 1,22));
				y += 22;
			}
			
			boolean hot = item.getBounds().contains(m_MousePos) || (item == m_pHotItem && m_pActiveSubMenu != null);
			DrawItem(gBuffer,item,hot);			
			
		}
		
		// Draw border around context menu
		gBuffer.setColor(m_ViewStyle.getBorderColor());
		gBuffer.draw(new Rectangle(0,0,this.getWidth() - 1,this.getHeight() - 1));
		
		gBuffer.dispose();
		// Draw graphics buffer
		g.drawImage(imageBuffer,0,0,this);
	}
	
	/**
	 * Draws menu item to specified Graphics object.
	 * @param g Graphics to draw.
	 * @param item Item to draw.
	 * @param hot Specifies if mouse in that item.
	 */
	private void DrawItem(Graphics2D g,WMenuItem item,boolean hot)
	{
		// Fill backround
		if(hot && item.getEnabled()){
			g.setColor(m_ViewStyle.getButtonHotColor());
		}
		else{
			g.setColor(Color.WHITE);
		}
		g.fillRect(item.getBounds().x + 1,item.getBounds().y,item.getBounds().width - 3,item.getBounds().height);
		
		if(item.getSeparator()){
			// Draw icon frame
			g.setColor(ViewStyle.GetColorFromRgb(220,212,198));
			g.fill(new Rectangle(item.getBounds().x,item.getBounds().y,23,item.getBounds().height));
			
			// Draw separator
			g.setColor(m_ViewStyle.getBorderColor());
			g.drawLine(28,item.getBounds().y + 1,(int)item.getBounds().getMaxX(),item.getBounds().y + 1);
		}
		else{
			// Draw text
			if(item.getEnabled()){
				g.setColor(Color.BLACK);
			}
			else{
				g.setColor(Color.GRAY);
			}
			Paint.DrawText(g,this.getFont(),item.getText(),item.getTextRect(),HorizontalAlignment.Left);
			
			// Draw icon frame
			if(!hot){
				g.setColor(ViewStyle.GetColorFromRgb(220,212,198));
				g.fill(new Rectangle(item.getBounds().x,item.getBounds().y,23,item.getBounds().height));
			}
			
			// Draw image
			if(m_pOwner.getImageList() != null && item.getImageIndex() > -1 && item.getImageIndex() < m_pOwner.getImageList().getCount()){
				Image image = m_pOwner.getImageList().get(item.getImageIndex());
			
				g.drawImage(image,item.getBounds().x + 3,item.getBounds().y + 3,16,16,this);	
			}
			
			// Draw submenu arrow
			if(item.getSubMenu() != null){
				if(item.getEnabled()){
					g.setColor(Color.BLACK);
				}
				else{
					g.setColor(Color.GRAY);
				}
				int y = (int)item.getBounds().y + (item.getBounds().height - 7) / 2;
				Paint.DrawTriangle(g,new Rectangle((int)item.getBounds().getMaxX() - 9,y,4,7),Direction.Right);
			}
			
			// Draw border around hot item
			if(hot){
				g.setColor(Color.BLACK);
				g.draw(new Rectangle(item.getBounds().x + 1,item.getBounds().y,item.getBounds().width - 4,item.getBounds().height - 1));		
			}
		}
	}
	
	
	/**
	 * Is called when mouse has released.
	 * @param e
	 */
	private void OnMouseReleased(MouseEvent e)
	{
		if(m_pHotItem != null && !m_pHotItem.getSeparator() && m_pHotItem.getEnabled() && m_pHotItem.getSubMenu() == null){
			this.setVisible(false);
			
			OnMenuItemSelected(m_pHotItem);
			
			// Close all visible menus
			WContextMenu menu = m_pOwner.m_pParentMenu;
			while(menu != null){				
				menu.Hide();
				menu = menu.m_pParentMenu;
			}			
			
			m_pParent.removeHierarchyBoundsListener(this);
			this.Hide();
		}
	}
		
	/**
	 * Is called when mouse cursor has exited this control.
	 * @param e
	 */
	private void OnMouseExited(MouseEvent e)
	{
		m_MousePos = new Point(-1,-1);
		
		// If no submenu open, deselect hot item
		if(m_pActiveSubMenu == null){
			if(m_pHotItem != null && this.getGraphics() != null){
				DrawItem((Graphics2D)this.getGraphics(),m_pHotItem,false);
				
				m_pHotItem = null;
			}
		}
	}
	
	/**
	 * Is called when mouse has moved.
	 * @param e
	 */
	private void OnMouseMoved(MouseEvent e)
	{
		m_MousePos = e.getPoint();
			
		WMenuItem inMouseItem = getInMouseItem();
		if(inMouseItem != m_pHotItem){
			//--- Redraw ------------------------------------------------//
			if(m_pHotItem != null){
				DrawItem((Graphics2D)this.getGraphics(),m_pHotItem,false);
			}
			if(inMouseItem != null && !inMouseItem.getSeparator()){
				DrawItem((Graphics2D)this.getGraphics(),inMouseItem,true);				
			}
			//-----------------------------------------------------------//
			
			m_pHotItem = inMouseItem;
			
			// Close open submenu
			if(m_pActiveSubMenu != null){
				m_pActiveSubMenu.Hide();
				m_pActiveSubMenu = null;
			}
			
			if(m_pHotItem != null && m_pHotItem.getEnabled() && m_pHotItem.getSubMenu() != null){
				m_pActiveSubMenu = m_pHotItem.getSubMenu();	
				m_pActiveSubMenu.m_pParentMenu = m_pOwner;
				m_pActiveSubMenu.setWText(m_pOwner.getWText());
				m_pActiveSubMenu.Show(this.getLocationOnScreen().x + this.getWidth(),this.getLocationOnScreen().y + m_pHotItem.getBounds().y);
			}
		}
	}
	
	
	public void ancestorMoved(HierarchyEvent e)
	{	
		m_pParent.removeHierarchyBoundsListener(this);
		Hide();
	}
	
	public void ancestorResized(HierarchyEvent e)
	{
		m_pParent.removeHierarchyBoundsListener(this);
		Hide();
	}
	

	/**
	 * Shows menu at specified location.
	 * @param screenX
	 * @param screenY
	 */
	public void Show(int screenX,int screenY)
	{		
		this.setSize(0,0);
		this.setLocation(screenX,screenY);		
		this.setVisible(true);
		
		Graphics g = this.getGraphics();
		CalculateSize((Graphics2D)g);		
	}
	
	/**
	 * Hides menu.
	 *
	 */
	public void Hide()
	{
		// Close open submenu
		if(m_pActiveSubMenu != null){
			m_pActiveSubMenu.Hide();
			m_pActiveSubMenu = null;
		}		
		
		this.setVisible(false);
		this.dispose();
	
		m_pOwner.fireMenuClosed();		
	}
		
	/**
	 * Calculate and set menu size.
	 * @param g
	 */
	private void CalculateSize(Graphics2D g)
	{
		int height   = 0;
		int maxWidth = 0;		
		for(WMenuItem item : m_pItems){			
			if(!item.getSeparator()){
				int width = Paint.CalcTextWidth(g,this.getFont(),item.getText());
				if(width > maxWidth){
					maxWidth = width;				
				}
				
				height += 22;
			}
			else{
				height += 4;
			}
		}
		
		maxWidth += 27 + 8 + 10;
		height   += 4;

		this.setSize(new Dimension(maxWidth,height + this.getInsets().bottom));
	}
	
	/**
	 * Gets menu item what is currently in mouse cursor.
	 * @return
	 */
	private WMenuItem getInMouseItem()
	{
		for(WMenuItem item : m_pItems){			
			if(item.getBounds() != null && item.getBounds().contains(m_MousePos)){
				return item;
			}
		}
		
		return null;
	}
	
		
	
	protected void OnMenuItemSelected(WMenuItem item)
	{
		m_pOwner.fireMenuItemSelected(item);
	}

}
