/*
 * Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 *  o Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer. 
 *     
 *  o Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution. 
 *     
 *  o Neither the name of Substance Kirill Grouchnikov nor the names of 
 *    its contributors may be used to endorse or promote products derived 
 *    from this software without specific prior written permission. 
 *     
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */
package org.pushingpixels.substance.api.renderers;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
import java.util.Map;

import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.JList;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.ListUI;

import org.pushingpixels.substance.api.ColorSchemeAssociationKind;
import org.pushingpixels.substance.api.ComponentState;
import org.pushingpixels.substance.api.SubstanceColorScheme;
import org.pushingpixels.substance.api.SubstanceLookAndFeel;
import org.pushingpixels.substance.internal.animation.StateTransitionTracker;
import org.pushingpixels.substance.internal.animation.StateTransitionTracker.StateContributionInfo;
import org.pushingpixels.substance.internal.ui.SubstanceListUI;
import org.pushingpixels.substance.internal.utils.SubstanceColorSchemeUtilities;
import org.pushingpixels.substance.internal.utils.SubstanceSizeUtils;
import org.pushingpixels.substance.internal.utils.SubstanceStripingUtils;
import org.pushingpixels.substance.internal.utils.UpdateOptimizationInfo;

/**
 * Default renderer for list cells.
 * 
 * @author Kirill Grouchnikov
 */
@SubstanceRenderer
public class SubstanceDefaultListCellRenderer extends DefaultListCellRenderer {
	/**
	 * Constructs a default renderer object for an item in a list.
	 */
	public SubstanceDefaultListCellRenderer() {
		super();
		this.putClientProperty(SubstanceLookAndFeel.COLORIZATION_FACTOR, 1.0);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing
	 * .JList, java.lang.Object, int, boolean, boolean)
	 */
	@Override
	public Component getListCellRendererComponent(JList list, Object value,
			int index, boolean isSelected, boolean cellHasFocus) {
		this.setComponentOrientation(list.getComponentOrientation());

		ListUI listUI = list.getUI();
		if (listUI instanceof SubstanceListUI) {
			SubstanceListUI ui = (SubstanceListUI) listUI;

			StateTransitionTracker.ModelStateInfo modelStateInfo = ui
					.getModelStateInfo(index, this);
			ComponentState currState = ui.getCellState(index, this);

			// special case for drop location
			JList.DropLocation dropLocation = list.getDropLocation();
			boolean isDropLocation = (dropLocation != null
					&& !dropLocation.isInsert() && dropLocation.getIndex() == index);

			if (!isDropLocation && (modelStateInfo != null)) {
				Map<ComponentState, StateContributionInfo> activeStates = modelStateInfo
						.getStateContributionMap();
				SubstanceColorScheme colorScheme = getColorSchemeForState(list,
						ui, currState);
				if (currState.isDisabled() || (activeStates == null)
						|| (activeStates.size() == 1)) {
					super.setForeground(new ColorUIResource(colorScheme
							.getForegroundColor()));
				} else {
					float aggrRed = 0;
					float aggrGreen = 0;
					float aggrBlue = 0;

					for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : modelStateInfo
							.getStateContributionMap().entrySet()) {
						ComponentState activeState = activeEntry.getKey();
						SubstanceColorScheme scheme = getColorSchemeForState(
								list, ui, activeState);
						Color schemeFg = scheme.getForegroundColor();
						float contribution = activeEntry.getValue()
								.getContribution();
						aggrRed += schemeFg.getRed() * contribution;
						aggrGreen += schemeFg.getGreen() * contribution;
						aggrBlue += schemeFg.getBlue() * contribution;
					}
					super.setForeground(new ColorUIResource(new Color(
							(int) aggrRed, (int) aggrGreen, (int) aggrBlue)));
				}
			} else {
				SubstanceColorScheme scheme = getColorSchemeForState(list, ui,
						currState);
				if (isDropLocation) {
					scheme = SubstanceColorSchemeUtilities.getColorScheme(list,
							ColorSchemeAssociationKind.TEXT_HIGHLIGHT,
							currState);
				}
				super.setForeground(new ColorUIResource(scheme
						.getForegroundColor()));
			}
		} else {
			if (isSelected) {
				this.setForeground(list.getSelectionForeground());
			} else {
				this.setForeground(list.getForeground());
			}
		}

		if (SubstanceLookAndFeel.isCurrentLookAndFeel()
				&& (list.getLayoutOrientation() == JList.VERTICAL))
			SubstanceStripingUtils.applyStripedBackground(list, index, this);

		if (value instanceof Icon) {
			this.setIcon((Icon) value);
			this.setText("");
		} else {
			this.setIcon(null);
			this.setText((value == null) ? "" : value.toString());
		}

		this.setEnabled(list.isEnabled());
		this.setFont(list.getFont());

		Insets ins = SubstanceSizeUtils
				.getListCellRendererInsets(SubstanceSizeUtils
						.getComponentFontSize(list));
		this
				.setBorder(new EmptyBorder(ins.top, ins.left, ins.bottom,
						ins.right));

		this.setOpaque(false);
		return this;
	}

	private SubstanceColorScheme getColorSchemeForState(JList list,
			SubstanceListUI ui, ComponentState state) {
		UpdateOptimizationInfo updateOptimizationInfo = ui
				.getUpdateOptimizationInfo();
		if (state == ComponentState.ENABLED) {
			if (updateOptimizationInfo == null) {
				return SubstanceColorSchemeUtilities
						.getColorScheme(list, state);
			} else {
				return updateOptimizationInfo.getDefaultScheme();
			}
		} else {
			if (updateOptimizationInfo == null) {
				return SubstanceColorSchemeUtilities.getColorScheme(list,
						ColorSchemeAssociationKind.HIGHLIGHT, state);
			} else {
				return updateOptimizationInfo.getHighlightColorScheme(state);
			}
		}
	}

	/**
	 * UI resource for renderer (does nothing yet).
	 * 
	 * @author Kirill Grouchnikov
	 */
	public static class SubstanceUIResource extends
			SubstanceDefaultListCellRenderer implements
			javax.swing.plaf.UIResource {
		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing
		 * .JList, java.lang.Object, int, boolean, boolean)
		 */
		@Override
		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean cellHasFocus) {
			return super.getListCellRendererComponent(list, value, index,
					isSelected, cellHasFocus);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JComponent#paint(java.awt.Graphics)
	 */
	@Override
	public final void paint(Graphics g) {
		super.paint(g);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
	 */
	@Override
	protected final void paintComponent(Graphics g) {
		super.paintComponent(g);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.Container#paintComponents(java.awt.Graphics)
	 */
	@Override
	public final void paintComponents(Graphics g) {
		super.paintComponents(g);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JComponent#paintBorder(java.awt.Graphics)
	 */
	@Override
	protected final void paintBorder(Graphics g) {
		super.paintBorder(g);
	}
}
