/**
 * Copyright (c) 2011, Martin Foster <martin@ethereal-realms.org>
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice, 
 *       this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of the Ethereal-Realms.org 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 HOLDER 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.lyra.Widgets;

import java.awt.Component;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.AbstractCellEditor;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;

import org.lyra.Lyra;
import org.lyra.Interface.Constants;

/**
 * Generates a user interface necessary to modify the rating section of the
 * song listing.   Will display a series of stars that when clicked will 
 * set the rating to a specific value. 
 * <p>
 * @author Martin Foster
 * @version 1.0.1,  %Revision, 95%, %LastChangedDate, 12/03/11 9:59PM%
 */
public class RatingCellEditor extends AbstractCellEditor implements TableCellEditor{

	// Serial Requirements
	private static final long serialVersionUID = 1L;

	/*
	 * INTERFACE ELEMENTS
	 */

	// Icon Groups
	private ImageIcon iconFull  = new ImageIcon(Lyra.getIconByMap("Rating-Full"));
	private ImageIcon iconEmpty = new ImageIcon(Lyra.getIconByMap("Rating-Empty"));
	private ImageIcon iconZero = new ImageIcon(Lyra.getIconByMap("Rating-None"));
	
	// Storage Panel
	private JPanel panelRating;
	
	// Individual Elements
	private JLabel labelZero;
	private JLabel labelFirst;
	private JLabel labelSecond;
	private JLabel labelThird;
	private JLabel labelFourth;
	private JLabel labelFifth;
	
	
	/*
	 * CLASS ELEMENTS
	 */
	
	// String containing actual value
	private String myValue;
	
	// Interface Listener
	private Interact Interface = new Interact();
	
	private RatingCellEditor OneSelf = this;
	
	

	/* (non-Javadoc)
	 * @see javax.swing.CellEditor#getCellEditorValue()
	 */
	public Object getCellEditorValue() {

		// We return what we know
		return myValue;
	}
	// End of getCellEditorValue Method
	

	/* (non-Javadoc)
	 * @see javax.swing.table.TableCellEditor#getTableCellEditorComponent(javax.swing.JTable, java.lang.Object, boolean, int, int)
	 */
	public Component getTableCellEditorComponent(
			JTable table, 
			Object value,
			boolean isSelected, 
			int row, 
			int column) {
		
		// Quick Assign
		myValue = (value == null)
			? "0"
			: value.toString();
		
		/*
		 * We have to take the value and use it to generate the actual display.
		 * By default the value will be zero accounting for instances where the
		 * current value is null.
		 */
		
		// Safety assign
		int actual = 0;
		
		// Parse in the actual value if not already assigned
		if (value != null) {
			
			// Parse
			actual = Integer.parseInt(value.toString());
		
			// Safety
			if (actual > Constants.getMaxRating())
				actual = 0;
		}
		
		// Update values
		updateRating(actual);
		
		// Return generated element
		return getPanelRating();
	}
	// End of getTableCellEditorComponent Method

	
	/**
	 * Ratings have to be updated visually otherwise the interface seems a bit
	 * less then authentic.
	 * <p>
	 * @param rating Number indicating rating level.
	 */
	private void updateRating(int rating) {

		// Create an Array of Image Icons
		ImageIcon[] state = new ImageIcon[Constants.getMaxRating() + 1];
		
		// Loop through and populate array
		for (int count=1; count <= Constants.getMaxRating(); count++) {
		
			// Generate icon based on context
			state[count] = (count <= rating)
				? iconFull
				: iconEmpty;
		}
		
		// Individually Set Elements
		getLabelFirst().setIcon(state[1]);
		getLabelSecond().setIcon(state[2]);
		getLabelThird().setIcon(state[3]);
		getLabelFourth().setIcon(state[4]);
		getLabelFifth().setIcon(state[5]);
	}
	// End of updateRating Method
	
	
	
	/**
	 * Initialises the panelRating element.  Contains all of the ratings
	 * allowing a degree of control.
	 * <p>
	 * @return javax.swing.JPanel
	 */
	private JPanel getPanelRating() {
		
		// Check for Existence
		if (panelRating == null) {
			
			// Establish Holder
			panelRating = new JPanel();
			
			// Establish Layout
			panelRating.setLayout(new BoxLayout(getPanelRating(), BoxLayout.X_AXIS));
			
			// Add in Elements
			panelRating.add(getLabelZero(),   null);
			panelRating.add(getLabelFirst(),  null);
			panelRating.add(getLabelSecond(), null);
			panelRating.add(getLabelThird(),  null);
			panelRating.add(getLabelFourth(), null);
			panelRating.add(getLabelFifth(),  null);
			
			// Spacer
			panelRating.add(Box.createHorizontalGlue());
		}
		
		// Return Instance
		return panelRating;
	}
	// End of getPanelRating Method
	
	
	/**
	 * Initialises the labelZero element.  The Zero element in the rating
	 * series used to rate a song.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelZero() {
		
		// Check for Existence
		if (labelZero == null) {
			
			// Create Instance
			labelZero = new JLabel(iconZero);
			
			// Identifier and Listener
			labelZero.setName("0");
			labelZero.addMouseListener(Interface);
		}
		
		// Return instance
		return labelZero;
	}
	// End of getLabelZero method
	
	
	/**
	 * Initialises the labelFirst element.  The first element in the rating
	 * series used to rate a song.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelFirst() {
		
		// Check for Existence
		if (labelFirst == null) {
			
			// Create Instance
			labelFirst = new JLabel(iconEmpty);
			
			// Identifier and Listener
			labelFirst.setName("1");
			labelFirst.addMouseListener(Interface);
		}
		
		// Return instance
		return labelFirst;
	}
	// End of getLabelFirst method
	
	
	/**
	 * Initialises the labelSecond element.  The Second element in the rating
	 * series used to rate a song.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelSecond() {
		
		// Check for Existence
		if (labelSecond == null) {
			
			// Create Instance
			labelSecond = new JLabel(iconEmpty);
			
			// Identifier and Listener
			labelSecond.setName("2");
			labelSecond.addMouseListener(Interface);
		}
		
		// Return instance
		return labelSecond;
	}
	// End of getLabelSecond method
	
	
	/**
	 * Initialises the labelThird element.  The Third element in the rating
	 * series used to rate a song.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelThird() {
		
		// Check for Existence
		if (labelThird == null) {
			
			// Create Instance
			labelThird = new JLabel(iconEmpty);
			
			// Identifier and Listener
			labelThird.setName("3");
			labelThird.addMouseListener(Interface);
		}
		
		// Return instance
		return labelThird;
	}
	// End of getLabelThird method
	
	
	/**
	 * Initialises the labelFourth element.  The Fourth element in the rating
	 * series used to rate a song.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelFourth() {
		
		// Check for Existence
		if (labelFourth == null) {
			
			// Create Instance
			labelFourth = new JLabel(iconEmpty);
			
			// Identifier and Listener
			labelFourth.setName("4");
			labelFourth.addMouseListener(Interface);
		}
		
		// Return instance
		return labelFourth;
	}
	// End of getLabelFourth method
	
	
	/**
	 * Initialises the labelFift element.  The fifth element in the rating
	 * series used to rate a song.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelFifth() {
		
		// Check for Existence
		if (labelFifth == null) {
			
			// Create Instance
			labelFifth = new JLabel(iconEmpty);
			
			// Identifier and Listener
			labelFifth.setName("5");
			labelFifth.addMouseListener(Interface);
		}
		
		// Return instance
		return labelFifth;
	}
	// End of getLabelFifth method
	
	
	/**
	 * The code separation from the user interface.   This Class handles all
	 * of the complexities of making the interface interactive.
	 * <p>
	 * @author Martin Foster
	 */
	private class Interact implements MouseListener {

		/* (non-Javadoc)
		 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
		 */
		public void mouseClicked(MouseEvent evt) {

			// Confirm this is the correct element
			if (evt.getSource() instanceof JLabel) {
				
				// Make a copy
				JLabel source = (JLabel)evt.getSource();
				
				// Assign as necessary
				if (source.getName() != null)
					myValue = source.getName();
				
				// Complete Updates
				OneSelf.stopCellEditing();
			}
		}
		// End of mouseClicked Method
		
		/* (non-Javadoc)
		 * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
		 */
		public void mouseEntered(MouseEvent evt) {
			
			// Confirm we are dealing with labels
			if (evt.getSource() instanceof JLabel) {
				
				// Update Source Elements
				JLabel source = (JLabel)evt.getSource();
				
				// Update user interface
				updateRating(
					Integer.parseInt(source.getName()));
			}
		}
		// End of mouseEntered Method

		/* (non-Javadoc)
		 * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
		 */
		public void mouseExited(MouseEvent evt) {}

		/* (non-Javadoc)
		 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
		 */
		public void mousePressed(MouseEvent evt) {}

		/* (non-Javadoc)
		 * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
		 */
		public void mouseReleased(MouseEvent evt) {}
		
	}
	// End of Interact Class
}
