/*
 * Created on Feb 27, 2005
 */
package org.flexdock.plaf.theme;

import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.ButtonModel;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.border.Border;
import javax.swing.plaf.basic.BasicButtonListener;
import javax.swing.plaf.basic.BasicButtonUI;

import org.flexdock.plaf.IFlexViewComponentUI;
import org.flexdock.plaf.PropertySet;
import org.flexdock.plaf.icons.IconResource;
import org.flexdock.view.Button;
import org.flexdock.view.Titlebar;

/**
 * @author Christopher Butler
 */
public class ButtonUI extends BasicButtonUI implements IFlexViewComponentUI {
	public static final String BORDER = "border";
	public static final String BORDER_HOVER = "border.hover";
	public static final String BORDER_ACTIVE = "border.active";
	public static final String BORDER_ACTIVE_HOVER = "border.active.hover";
	public static final String BORDER_PRESSED = "border.pressed";
	
	protected PropertySet creationParameters;
	protected Border borderDefault;
	protected Border borderDefaultHover;
	protected Border borderActive;
	protected Border borderActiveHover;
	protected Border borderPressed;
	
	public void paint(Graphics g, JComponent c) {
		AbstractButton b = (AbstractButton) c;
		ButtonModel model = b.getModel();
		updateTooltip(b);
		
		boolean active = isParentActive(b);
		boolean pressed = isPressed(b);
		boolean hover = pressed || model.isRollover();

		paintBackground(g, b, active, hover, pressed);
		paintIcon(g, b);
		paintBorder(g, b);
	}
	
	protected void paintBackground(Graphics g, AbstractButton b, boolean active, boolean hover, boolean pressed) {
		// do nothing
	}

	protected void paintBorder(Graphics g, AbstractButton b) {
		Border border = getBorder(b);
		if(border!=null)
			border.paintBorder(b, g, 0, 0, b.getWidth(), b.getHeight());
	}
	
	protected Border getBorder(AbstractButton button) {
		if(isPressed(button))
			return getPressedBorder(button);
		
		boolean active = isParentActive(button);
		if(button.getModel().isRollover())
			return getHoverBorder(button, active);
		
		return getDefaultBorder(button, active);
	}

	protected Border getPressedBorder(AbstractButton button) {
		Border border = borderPressed;
		if(border==null)
			border = getHoverBorder(button, true);
		return border;
	}
	
	protected Border getHoverBorder(AbstractButton button, boolean active) {
		Border border = active? borderActiveHover: borderDefaultHover;
		if(border==null)
			border = getDefaultBorder(button, active);
		return border;
	}
	
	protected Border getDefaultBorder(AbstractButton button, boolean active) {
		return active? borderActive: borderDefault;
	}

	


	protected void paintIcon(Graphics g, AbstractButton b) {
		Icon icon = getIcon(b);
		if(icon==null)
			return;
		
		int h = icon.getIconHeight();
		int w = icon.getIconWidth();
		int x = b.getWidth()/2 - w/2;
		int y = b.getHeight()/2 - h/2;
		
		icon.paintIcon(b, g, x, y);
	}
	
	protected Icon getIcon(AbstractButton button) {
	    boolean active = isParentActive(button);

	    if(!button.isEnabled() || !button.getModel().isEnabled())
	        return getDisabledIcon(button, active);
	    
		if(isPressed(button))
			return getPressedIcon(button);
		
		if(button.getModel().isRollover())
			return getHoverIcon(button, active);
		
		return getDefaultIcon(button, active);
	}
	
	protected Icon getDisabledIcon(AbstractButton button, boolean active) {
		Icon icon = button.getDisabledIcon();
		if(icon==null)
			icon = getActionIcon(button, false, active, false);
		if(icon==null)
			icon = getDefaultIcon(button, active);
		return icon;
	}
	
	protected Icon getPressedIcon(AbstractButton button) {
		Icon icon = button.getPressedIcon();
		if(icon==null)
			icon = getActionIcon(button, true, true, true);
		if(icon==null)
			icon = getHoverIcon(button, true);
		return icon;
	}
	
	protected Icon getHoverIcon(AbstractButton button, boolean active) {
		Icon icon = button.getRolloverIcon();
		if(icon==null)
			icon = getActionIcon(button, false, active, true);
		if(icon==null)
			icon = getDefaultIcon(button, active);
		return icon;
	}
	
	protected Icon getDefaultIcon(AbstractButton button, boolean active) {
		Icon icon = button.getIcon();
		if(icon==null)
			icon = getActionIcon(button, false, active, false);
		return icon;
	}
	
	protected Icon getActionIcon(AbstractButton button, boolean pressed, boolean active, boolean hover) {
		Action action = button.getAction();
		IconResource resource = action==null? null: (IconResource)action.getValue(ICON_RESOURCE);
		if(resource==null)
			return null;

		boolean disabled = !button.isEnabled() || !button.getModel().isEnabled();
		boolean selected = button.isSelected();
		
		
		if(pressed && !disabled) {
			Icon icon = selected? resource.getIconSelectedPressed(): null;
			if(icon==null)
				icon = resource.getIconPressed();
			return icon;
		}
		
		if(active) {
		    if(disabled) {
		        Icon icon = selected? resource.getIconSelectedActiveDisabled(): null;
				if(icon==null)
					icon = resource.getIconActiveDisabled();
				return icon==null? resource.getIconActive(): icon;
		    }
		    
			if(hover) {
				Icon icon = selected? resource.getIconSelectedActiveHover(): null;
				if(icon==null)
					icon = resource.getIconActiveHover();
				return icon;
			}
			
			Icon icon = selected? resource.getIconSelectedActive(): null;
			if(icon==null)
				icon = resource.getIconActive();
			return icon;
		}
		
		if(disabled) {
			Icon icon = selected? resource.getIconSelectedDisabled(): null;
			if(icon==null)
				icon = resource.getIconDisabled();
			return icon==null? resource.getIcon(): icon;
		}
		
		if(hover) {
			Icon icon = selected? resource.getIconSelectedHover(): null;
			if(icon==null)
				icon = resource.getIconHover();
			return icon;
		}
		
		Icon icon = selected? resource.getIconSelected(): null;
		if(icon==null)
			icon = resource.getIcon();
		return icon;
	}

	protected boolean isPressed(AbstractButton button) {
		ButtonModel model = button.getModel();
		return model.isArmed() && model.isPressed();
	}
	
	protected boolean isParentActive(AbstractButton button) {
		Container parent = button.getParent();
		return parent instanceof Titlebar? ((Titlebar)parent).isActive(): false;
	}
	
	
	public void installUI(JComponent c) {
		super.installUI(c);
		AbstractButton button = (AbstractButton)c;
		button.setRolloverEnabled(true);
		button.setRequestFocusEnabled(false);
		button.setOpaque(false);
		button.setBorder(null);
		
		// add the toggle listener
		button.addItemListener(new ToggleListener());
		updateTooltip(button);
	}

	public void uninstallUI(JComponent c) {
		AbstractButton button = (AbstractButton)c;
		super.uninstallUI(c);
	}
	
    protected void installKeyboardActions(AbstractButton b){
    	// do nothing
    }
    
    protected BasicButtonListener createButtonListener(AbstractButton b) {
        return new ButtonListener(b);
    }
    
    protected static class ButtonListener extends BasicButtonListener {
    	protected ButtonListener(AbstractButton b) {
    		super(b);
    	}
		public void focusGained(FocusEvent e) {
		}
		public void focusLost(FocusEvent e) {
		}
    }

	public void setBorderActive(Border borderActive) {
		this.borderActive = borderActive;
	}

	public void setBorderActiveHover(Border borderActiveHover) {
		this.borderActiveHover = borderActiveHover;
	}

	public void setBorderDefault(Border borderDefault) {
		this.borderDefault = borderDefault;
	}

	public void setBorderDefaultHover(Border borderDefaultHover) {
		this.borderDefaultHover = borderDefaultHover;
	}

	public void setBorderPressed(Border borderPressed) {
		this.borderPressed = borderPressed;
	}

	public PropertySet getCreationParameters() {
		return creationParameters;
	}
	public void setCreationParameters(PropertySet creationParameters) {
		this.creationParameters = creationParameters;
		initializeCreationParameters();
	}
	
	public void initializeCreationParameters() {
		setBorderDefault(creationParameters.getBorder(BORDER));
		setBorderDefaultHover(creationParameters.getBorder(BORDER_HOVER));
		setBorderActive(creationParameters.getBorder(BORDER_ACTIVE));
		setBorderActiveHover(creationParameters.getBorder(BORDER_ACTIVE_HOVER));
		setBorderPressed(creationParameters.getBorder(BORDER_PRESSED));
	}

	private class ToggleListener implements ItemListener {
		public void itemStateChanged(ItemEvent e) {
			if(e.getStateChange()!=ItemEvent.SELECTED && e.getStateChange()!=ItemEvent.DESELECTED)
				return;
			
			Button button = (Button)e.getSource();
			updateTooltip(button);
		}
	}
	
	private void updateTooltip(AbstractButton button) {
		Action action = button.getAction();
		if(action==null)
			return;
		
		String toolTip = (String)action.getValue(Action.SHORT_DESCRIPTION);
		if(toolTip!=null)
			return;
		
		IconResource resource = action==null? null: (IconResource)action.getValue(ICON_RESOURCE);
		if(resource==null)
			return;
		
		toolTip = button.isSelected()? resource.getTooltipSelected(): resource.getTooltip();
		if(toolTip==null)
			toolTip = resource.getTooltip();

		if(toolTip!=null)
			button.setToolTipText(toolTip);		
	}
}