/**
 * 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.Interface.Options;

import javax.swing.JPanel;
import javax.swing.BoxLayout;
import javax.swing.BorderFactory;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.AbstractButton;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.JColorChooser;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JComboBox;
import javax.swing.JCheckBox;
import javax.swing.JButton;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;

import org.lyra.Ledger;
import org.lyra.Interface.Constants;

/**
 * The user interface has the ability to have unique colours and themes applied
 * to it.   While themes are Java based and will be selected from whatever the
 * Java Runtime Engine supports, the selection of colours and icons are
 * application specific.
 * <p>
 * @author Martin Foster
 * @version 1.0.1, %Revision, 99%, %LastChangedDate, 17/03/11 8:17PM%
 */
public class InterfacePanel extends JPanel {

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

	/*
	 * INTERFACE COMPONENTS
	 */
	
	// Theme Selection
	private JPanel groupTheme = null;
	private JLabel labelTheme = null;
	private JComboBox comboTheme = null;
	
	private JLabel labelSmooth = null;
	private JCheckBox checkSmooth = null;
	
	// Icon Selection
	private JLabel labelIcons = null;
	private JPanel panelOptions = null;
	
	// Icon Selection - Blue
	private JPanel panelOptionsBlue = null;
	private JRadioButton radioBlue = null;
	private JLabel labelBlue = null;
	
	// Icon Selection - Green
	private JPanel panelOptionsGreen = null;
	private JRadioButton radioGreen = null;
	private JLabel labelGreen = null;
	
	// Icon Selection - Orange
	private JPanel panelOptionsOrange = null;
	private JRadioButton radioOrange = null;
	private JLabel labelOrange = null;

	// Display of various components
	private JPanel groupDisplay = null;
	
	// Playlist Display
	private JLabel labelPlaylists = null;
	private JCheckBox checkPlaylists = null;
	
	// Artist Filtering
	private JLabel labelArtist = null;
	private JCheckBox checkArtist = null;
	
	// Album Filtering
	private JLabel labelAlbum = null;
	private JCheckBox checkAlbum = null;
	
	// Genre Filtering
	private JLabel labelGenre = null;
	private JCheckBox checkGenre = null;
	
	// Colour Selection
	private JLabel labelManage = null;
	private JCheckBox checkCustom = null;
	
	// Holder for all Colour Options
	private JPanel groupColors = null;
	
	// Primary Font Colour
	private JLabel labelPrimaryFont = null;
	private JButton buttonPrimaryFont = null;
	
	// Primary Line Colour
	private JLabel labelPrimaryColor = null;
	private JButton buttonPrimaryColor = null;
	
	// Secondary Line Colour
	private JLabel labelSecondaryColor = null;
	private JButton buttonSecondaryColor = null;
	
	// Highlighted Line Colour
	private JLabel labelHighlightColor = null;
	private JButton buttonHighlightColor = null;
	
	// Highlighted Font Colour
	private JLabel labelHighlightFont = null;
	private JButton buttonHighlightFont = null;

	
	/*
	 * PACKAGE INSTANCES
	 */
	private Map<String,String> Lang;

	private Map<String,String> Global;
	private Ledger Logger;
	
	private Component Parent;
	
	
	/*
	 * CLASS INSTANCES
	 */
	private Interact Interface;
	private ButtonGroup ColorGroup;
	
	/**
	 * This is the default constructor used for visual editors.  While it
	 * contains all of the necessary elements to make the class display but
	 * will not make it interactive.
	 */
	@SuppressWarnings("serial")
	public InterfacePanel() {
		
		// Super class processing
		super();
		
		/*
		 * Under normal circumstances this section will be passed on from the
		 * database.   However Visual Editors do not have this ability to we
		 * create a HashMap that can be used either way.
		 */
		Lang = new HashMap<String,String>(){
			{
				put("Options.Interface.Theme","Java Theme");
				put("Options.Interface.Icons","Icon Set");
				put("Options.Interface.Playlists","Playlist Display");
				put("Options.Interface.Artist","Artist Filtering");
				put("Options.Interface.Album","Album Filtering");
				put("Options.Interface.Genre","Genre Filtering");
				put("Options.Interface.Manage","Use Custom Colours");
				put("Options.Interface.PrimaryFont","Primary Font");
				put("Options.Interface.PrimaryColor","Primary Row");
				put("Options.Interface.SecondaryColor","Primary Row");
				put("Options.Interface.HighlightColor","Highlighted Row");
				put("Options.Interface.HighlightFont","Highlighted Font");
				put("Options.Interface.Icons.Blue","Blue Set");
				put("Options.Interface.Icons.Green","Green Set");
				put("Options.Interface.Icons.Orange","Orange Set");
				put("Options.Interface.Group.Color","Custom Colours");
				put("Options.Interface.Group.Theme","General");
				put("Options.Interface.Group.Display","Organiser Component Display");
				put("Options.Interface.Smooth","Smooth Ticker Display");
			}
		};
		
		/*
		 * The Global hash is required in order to fill in the default values
		 * necessary to provide a user interface.   This map creates the
		 * most basic defaults.
		 */
		Global = new HashMap<String,String>() {
			{
				put("Setting.Interface.Theme","Nimbus");
				put("Setting.Interface.Icons","BLUE");
				put("Setting.Interface.Album","true");
				put("Setting.Interface.Artist","true");
				put("Setting.Interface.Genre","true");
				put("Setting.Interface.Playlist","true");
				put("Setting.Interface.Custom","true");
				put("Setting.Interface.Color.Font.Primary","-16777216");
				put("Setting.Interface.Color.Row.Primary","-16777216");
				put("Setting.Interface.Color.Row.Secondary","-16777216");
				put("Setting.Interface.Color.Row.Highlight","-16777216");
				put("Setting.Interface.Color.Font.Highlight","-16777216");
			}
		};
		
		// Establish Baseline
		initFrame();
	}
	// End of Constructor Class
	

	/**
	 * Primary application constructor which is passed all of the necessary
	 * elements in order to display settings and handle interaction.
	 * <p>
	 * @param logger Ledger instances for debugging and information.
	 * @param lang Language map for independent language elements.
	 * @param global Global settings and configuration options.
	 * @param parent Component in which this JPanel is a part of.
	 */
	public InterfacePanel(Ledger logger, Map<String,String> lang, Map<String,String> global, Component parent) {
		
		// Have super class do its thing
		super();
		
		// Pass up
		this.Logger    = logger;
		this.Lang      = lang;
		this.Global    = global;
		this.Parent    = parent;
		
		// Create Instance of Action
		this.Interface = new Interact();
		
		// Initialise the Dialog
		initFrame();
		
		
		/*
		 * The other panels control their state establishment through the
		 * parent container.   This one however does not update at all times
		 * and will instead display static information.
		 */
		Interface.setState();
	 }
	// End of Constructor Class
	
	
	
	/**
	 * This method initialises this.  This will configure elements of the 
	 * panel and add in the necessary visual components for display.
	 */
	private void initFrame() {
		
		// Establish Layout
		this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
		
		// Insert Components
		this.add(getGroupTheme(), null);
		this.add(getGroupDisplay(), null);
		this.add(getGroupColors(), null);
		
		// Spacer Component
		this.add(Box.createVerticalGlue());
	}
	// End of initFrame Method

	
	/**
	 * This method initialises groupTheme.  Contains elements necessary to 
	 * change the basic look and feel such as the Java Theme and Icons used
	 * in display.	
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getGroupTheme() {
		
		// Check for Existence
		if (groupTheme == null) {
			
			// Establish layout elements
			GridLayout themeLayout = new GridLayout();
			themeLayout.setRows(3);
			themeLayout.setColumns(1);
			
			// Gaps
			themeLayout.setVgap(Constants.getRowGap());
			
			// Create Instance
			groupTheme = new JPanel();
			
			// Layout and Border
			groupTheme.setLayout(themeLayout);
			groupTheme.setBorder(BorderFactory.createTitledBorder(null, Lang.get("Options.Interface.Group.Theme"), TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, new Font("Dialog", Font.BOLD, 12), new Color(51, 51, 51)));

			/*
			 * Insert Elements in such a way as to look like they are being
			 * embedded into a table.
			 */
			
			// Themes
			groupTheme.add(
				getPanelRow(
					getLabelTheme(),
					getComboTheme()
			  ));
			
			// Icons 
			groupTheme.add(
				getPanelRow(
					getLabelIcons(),
					getPanelOptions()
			  ));
			
			// Icons 
			groupTheme.add(
				getPanelRow(
					getLabelSmooth(),
					getCheckSmooth()
			  ));	
		}
		
		// Return Instance
		return groupTheme;
	}
	// End of getGroupTheme Method

	
	/**
	 * This method initialises groupDisplay. Certain display areas of the
	 * Organiser are actually optional, this allows a user to select which
	 * of those features are to be displayed.	
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getGroupDisplay() {
		
		// Check for Existence
		if (groupDisplay == null) {
			
			// Establish layout elements
			GridLayout displayLayout = new GridLayout();
			displayLayout.setRows(4);
			displayLayout.setColumns(1);
			
			// Gaps
			displayLayout.setVgap(Constants.getRowGap());
			
			// Create Instance
			groupDisplay = new JPanel();
			
			// Layout and Border
			groupDisplay.setLayout(displayLayout);
			groupDisplay.setBorder(BorderFactory.createTitledBorder(null, Lang.get("Options.Interface.Group.Display"), TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, new Font("Dialog", Font.BOLD, 12), new Color(51, 51, 51)));

			/*
			 * Insert Elements in such a way as to look like they are being
			 * embedded into a table.
			 */
			
			// Playlists
			groupDisplay.add(
				getPanelRow(
					getLabelPlaylists(),
					getCheckPlaylists()
			  ));
			
			// Artist Filtering
			groupDisplay.add(
				getPanelRow(
					getLabelArtist(),
					getCheckArtist()
			  ));
			
			// Album Filtering
			groupDisplay.add(
				getPanelRow(
					getLabelAlbum(),
					getCheckAlbum()
			  ));
			
			// Genre Filtering
			groupDisplay.add(
				getPanelRow(
					getLabelGenre(),
					getCheckGenre()
			  ));
		}
		
		// Return Instance
		return groupDisplay;
	}
	// End of getGroupDisplay Method
	
	
	/**
	 * This method initialises groupColours.  Group colours combines all of the
	 * elements necessary to permit colour selection and choices.	
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getGroupColors() {
		
		// Check for Existence
		if (groupColors == null) {
			
			// Establish layout elements
			GridLayout colourLayout = new GridLayout();
			colourLayout.setRows(6);
			colourLayout.setColumns(1);
			
			// Gaps
			colourLayout.setVgap(Constants.getRowGap());
			
			
			// Create Instance
			groupColors = new JPanel();
			
			// Layout and Border
			groupColors.setLayout(colourLayout);
			groupColors.setBorder(BorderFactory.createTitledBorder(null, Lang.get("Options.Interface.Group.Color"), TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, new Font("Dialog", Font.BOLD, 12), new Color(51, 51, 51)));

			
			/*
			 * This is a control element which will determine if the others
			 * will be visible or not.
			 */
			groupColors.add(
				getPanelRow(
					getLabelManage(),
					getCheckCustom()
			  ));
			
			
			/*
			 * Insert Elements in such a way as to look like they are being
			 * embedded into a table.
			 */
			
			// Primary Font
			groupColors.add(
				getPanelRow(
					getLabelPrimaryFont(),
					getButtonPrimaryFont()
			  ));
			
			// Primary Row Colour
			groupColors.add(
				getPanelRow(
					getLabelPrimaryColor(),
					getButtonPrimaryColor()
			 ));	
			
			// Secondary Row Colour
			groupColors.add(
				getPanelRow(
					getLabelSecondaryColor(),
					getButtonSecondaryColor()
			  ));
			
			// Highlighted Row Colour
			groupColors.add(
				getPanelRow(
					getLabelHighlightColor(),
					getButtonHighlightColor()
			  ));

			// Highlighted Font Colour
			groupColors.add(
				getPanelRow(
					getLabelHighlightFont(),
					getButtonHighlightFont()
			  ));
			
			
			/*
			 * We will now determine if this should be enabled or disabled
			 * based on input from the user.   The custom colour checkbox
			 * determines initial action.
			 */
			if (!getCheckCustom().isSelected())
				groupColors.setEnabled(false);
		}
		
		// Return Instance
		return groupColors;
	}
	// End of getGroupColours Method
	
	
	/**
	 * This method initialises labelTheme.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelTheme() {
		
		// Check for Existence
		if (labelTheme == null) {
			
			// Create Instance
			labelTheme = new JLabel();
			
			// Set the Text
			labelTheme.setText(Lang.get("Options.Interface.Theme"));
		}
		
		// Return Instance
		return labelTheme;
	}
	// End of getLabelTheme Method
	
	
	/**
	 * This method initialises labelSmooth.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelSmooth() {
		
		// Check for Existence
		if (labelSmooth == null) {
			
			// Create Instance
			labelSmooth = new JLabel();
			
			// Set the Text
			labelSmooth.setText(Lang.get("Options.Interface.Smooth"));
		}
		
		// Return Instance
		return labelSmooth;
	}
	// End of getLabelSmooth Method
	

	/**
	 * This method initialises labelIcons.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelIcons() {
		
		// Check for Existence
		if (labelIcons == null) {
			
			// Create Instance
			labelIcons = new JLabel();
			
			// Set the Text
			labelIcons.setText(Lang.get("Options.Interface.Icons"));
		}
		
		// Return Instance
		return labelIcons;
	}
	// End of getLabelIcons Method
	

	/**
	 * This method initialises labelPlaylists.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelPlaylists() {
		
		// Check for Existence
		if (labelPlaylists == null) {
			
			// Create Instance
			labelPlaylists = new JLabel();
			
			// Set the Text
			labelPlaylists.setText(Lang.get("Options.Interface.Playlists"));
		}
		
		// Return Instance
		return labelPlaylists;
	}
	// End of getLabelPlaylists Method
	

	/**
	 * This method initialises labelArtist.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelArtist() {
		
		// Check for Existence
		if (labelArtist == null) {
			
			// Create Instance
			labelArtist = new JLabel();
			
			// Set the Text
			labelArtist.setText(Lang.get("Options.Interface.Artist"));
		}
		
		// Return Instance
		return labelArtist;
	}
	// End of getLabelArtist Method
	
	
	
	/**
	 * This method initialises labelAlbum.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelAlbum() {
		
		// Check for Existence
		if (labelAlbum == null) {
			
			// Create Instance
			labelAlbum = new JLabel();
			
			// Set the Text
			labelAlbum.setText(Lang.get("Options.Interface.Album"));
		}
		
		// Return Instance
		return labelAlbum;
	}
	// End of getLabelAlbum Method

	
	/**
	 * This method initialises labelGenre.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelGenre() {
		
		// Check for Existence
		if (labelGenre == null) {
			
			// Create Instance
			labelGenre = new JLabel();
			
			// Set the Text
			labelGenre.setText(Lang.get("Options.Interface.Genre"));
		}
		
		// Return Instance
		return labelGenre;
	}
	// End of getLabelGenre Method

	
	/**
	 * This method initialises labelManage.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelManage() {
		
		// Check for Existence
		if (labelManage == null) {
			
			// Create Instance
			labelManage = new JLabel();
			
			// Set the Text
			labelManage.setText(Lang.get("Options.Interface.Manage"));
		}
		
		// Return Instance
		return labelManage;
	}
	// End of getLabelManage Method
	
	
	/**
	 * This method initialises labelPrimaryFont.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelPrimaryFont() {
		
		// Check for Existence
		if (labelPrimaryFont == null) {
			
			// Create Instance
			labelPrimaryFont = new JLabel();
			
			// Set the Text
			labelPrimaryFont.setText(Lang.get("Options.Interface.PrimaryFont"));
		}
		
		// Return Instance
		return labelPrimaryFont;
	}
	// End of getLabelPrimaryFont Method
	

	/**
	 * This method initialises labelPrimaryColor.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelPrimaryColor() {
		
		// Check for Existence
		if (labelPrimaryColor == null) {
			
			// Create Instance
			labelPrimaryColor = new JLabel();
			
			// Set the Text
			labelPrimaryColor.setText(Lang.get("Options.Interface.PrimaryColor"));
		}
		
		// Return Instance
		return labelPrimaryColor;
	}
	// End of getLabelPrimaryColor Method

	
	/**
	 * This method initialises labelSecondaryColor.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelSecondaryColor() {
		
		// Check for Existence
		if (labelSecondaryColor == null) {
			
			// Create Instance
			labelSecondaryColor = new JLabel();
			
			// Set the Text
			labelSecondaryColor.setText(Lang.get("Options.Interface.SecondaryColor"));
		}
		
		// Return Instance
		return labelSecondaryColor;
	}
	// End of getLabelSecondaryColor Method


	/**
	 * This method initialises labelHighlightColor.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelHighlightColor() {
		
		// Check for Existence
		if (labelHighlightColor == null) {
			
			// Create Instance
			labelHighlightColor = new JLabel();
			
			// Set the Text
			labelHighlightColor.setText(Lang.get("Options.Interface.HighlightColor"));
		}
		
		// Return Instance
		return labelHighlightColor;
	}
	// End of getLabelHighlightColor Method

	
	/**
	 * This method initialises labelHighlightFont.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelHighlightFont() {
		
		// Check for Existence
		if (labelHighlightFont == null) {
			
			// Create Instance
			labelHighlightFont = new JLabel();
			
			// Set the Text
			labelHighlightFont.setText(Lang.get("Options.Interface.HighlightFont"));
		}
		
		// Return Instance
		return labelHighlightFont;
	}
	// End of getLabelHighlightFont Method


	/**
	 * This method initialises comboTheme.  Contains a list of all Java Runtime
	 * Engine available themes.	
	 * <p>
	 * @return javax.swing.JComboBox	
	 */
	private JComboBox getComboTheme() {
		
		// Check for Existence
		if (comboTheme == null) {

			/*
			 * Look and Feel elements or Themes are contained within the JRE
			 * itself.   We extract that information and display or for use.
			 */
			List<String> themes = new LinkedList<String>();
			
			// Generate a list of all themes
			for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
				themes.add(info.getName());
			
			
			/*
			 * With the theme information in place, we now have to populate
			 * the JComboBox and then of course set the application default. 
			 */
			comboTheme = new JComboBox(themes.toArray(new String[0]));
		}
		
		// Return Instance
		return comboTheme;
	}
	// End of getComboTheme Method

	
	/**
	 * This method initialises checkPlaylists.  Enables/Disables display of
	 * playlists in the organiser.	
	 * <p> 	
	 * @return javax.swing.JCheckBox	
	 */
	private JCheckBox getCheckPlaylists() {
		
		// Check for Existence
		if (checkPlaylists == null) {
			
			// Create Instance and Identifier
			checkPlaylists = new JCheckBox();
			checkPlaylists.setName("SHOW.PLAYLISTS");
		}
		
		// Return Instance
		return checkPlaylists;
	}
	// End of getCheckPlaylists Method

	/**
	 * 
	 * This method initialises checkArtist.  Enables/Disables the display of
	 * Artist filtering on the organiser.
	 * <p>	
	 * @return javax.swing.JCheckBox	
	 */
	private JCheckBox getCheckArtist() {
		
		// Check for Existence
		if (checkArtist == null) {
			
			// Create Instance and Identifier
			checkArtist = new JCheckBox();
			checkArtist.setName("SHOW.ARTIST");
		}
		
		// Pass Instance
		return checkArtist;
	}
	// End of getCheckArtist Method

	
	/**
	 * This method initialises checkAlbum.  Enables/Disables the display of
	 * the Album Filtering in the organiser.	
	 * <p> 	
	 * @return javax.swing.JCheckBox	
	 */
	private JCheckBox getCheckAlbum() {
		
		// Check for Existence
		if (checkAlbum == null) {
			
			// Create Instance and Identifier
			checkAlbum = new JCheckBox();
			checkAlbum.setName("SHOW.ALBUM");
		}
		
		// Return Instance
		return checkAlbum;
	}
	// End of getCheckAlbum Method

	
	/**
	 * This method initialises checkGenre.  Enables/Disables the display of
	 * Genre filtering in the organiser.	
	 * <p>	
	 * @return javax.swing.JCheckBox	
	 */
	private JCheckBox getCheckGenre() {
		
		// Check for Existence
		if (checkGenre == null) {
			
			// Create Instance and Set Identifier
			checkGenre = new JCheckBox();
			checkGenre.setName("SHOW.GENRE");
		}
		
		// Return Instance
		return checkGenre;
	}
	// End of getCheckGenre Method

	
	/**
	 * This method initialises checkManage.   Enables or disables the
	 * capability to manage custom colours for row rendering.	
	 * <p>
	 * @return javax.swing.JCheckBox	
	 */
	private JCheckBox getCheckCustom() {
		
		// Check for Existence
		if (checkCustom == null) {
			
			// Create Instance
			checkCustom = new JCheckBox();

			// Instance and Change Listener
			checkCustom.setName("SHOW.COLOR");
			checkCustom.addChangeListener(Interface);
		}
		
		// Return Instance
		return checkCustom;
	}
	// End of getCheckCustom Method

	
	/**
	 * This method initialises checkManage.   Enables or disables the
	 * capability to manage custom colours for row rendering.	
	 * <p>
	 * @return javax.swing.JCheckBox	
	 */
	private JCheckBox getCheckSmooth() {
		
		// Check for Existence
		if (checkSmooth == null) {
			
			// Create Instance
			checkSmooth = new JCheckBox();

			// Instance and Change Listener
			checkSmooth.setName("SHOW.SMOOTH");
			checkSmooth.addChangeListener(Interface);
		}
		
		// Return Instance
		return checkSmooth;
	}
	// End of getCheckSmooth Method
	
	/**
	 * This method initialises buttonPrimaryFont.  Used to trigger a colour
	 * selection prompt.	
	 * <p>
	 * @return javax.swing.JButton	
	 */
	private JButton getButtonPrimaryFont() {
		
		// Check for Existence
		if (buttonPrimaryFont == null) {
			
			// Create Instance
			buttonPrimaryFont = new JButton();
			
			// Identifier and Listener
			buttonPrimaryFont.setName("COLOR.PFONT");
			buttonPrimaryFont.addActionListener(Interface);
		}
		
		// Return Instance
		return buttonPrimaryFont;
	}
	// End of getButtonPrimaryFont Method

	
	/**
	 * This method initialises buttonPrimaryColor.  Used to trigger a colour
	 * selection prompt.		
	 * <p>
	 * @return javax.swing.JButton	
	 */
	private JButton getButtonPrimaryColor() {
		
		// Check for Existence
		if (buttonPrimaryColor == null) {
			
			// Create Instance
			buttonPrimaryColor = new JButton();
			
			// Identifier and Listener
			buttonPrimaryColor.setName("COLOR.PROW");
			buttonPrimaryColor.addActionListener(Interface);
		}
		
		// Return Instance
		return buttonPrimaryColor;
	}
	// End of getButtonPrimaryColor Method

	
	/**
	 * This method initialises buttonSecondaryColor.  Used to trigger a colour
	 * selection prompt.		
	 * <p>
	 * @return javax.swing.JButton	
	 */
	private JButton getButtonSecondaryColor() {
		
		// Check for Existence
		if (buttonSecondaryColor == null) {
			
			// Create Instance
			buttonSecondaryColor = new JButton();
			
			// Identifier and Listener
			buttonSecondaryColor.setName("COLOR.SROW");
			buttonSecondaryColor.addActionListener(Interface);
		}
		
		// Return Instance
		return buttonSecondaryColor;
	}
	// End of getButtonSecondaryColor Method
	

	/**
	 * This method initialises buttonHighlightColor.  Used to trigger a colour
	 * selection prompt.		
	 * <p> 	
	 * @return javax.swing.JButton	
	 */
	private JButton getButtonHighlightColor() {
		
		// Check for Existence
		if (buttonHighlightColor == null) {
			
			// Create Instance
			buttonHighlightColor = new JButton();
			
			// Identifier and Listener
			buttonHighlightColor.setName("COLOR.HROW");
			buttonHighlightColor.addActionListener(Interface);
		}
		
		// Return Instance
		return buttonHighlightColor;
	}
	// End of getButtonHighlightColor

	
	/**
	 * This method initialises buttonHighlightFont.  Used to trigger a colour
	 * selection prompt.		
	 * <p>
	 * @return javax.swing.JButton	
	 */
	private JButton getButtonHighlightFont() {
		
		// Check for Existence
		if (buttonHighlightFont == null) {
			
			// Create Instance
			buttonHighlightFont = new JButton();
			
			// Identifier and Listener
			buttonHighlightFont.setName("COLOR.SFONT");
			buttonHighlightFont.addActionListener(Interface);
		}
		
		// Return Instance
		return buttonHighlightFont;
	}
	// End of getButtonHighlightFont

	
	/**
	 * This method initialises panelOptions. Contains the necessary radio
	 * buttons to select which icon group to display.
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPanelOptions() {
		
		// Check for Existence
		if (panelOptions == null) {
			
			// Create Instance
			panelOptions = new JPanel();
			
			// Establish Layout
			panelOptions.setLayout(new BoxLayout(getPanelOptions(), BoxLayout.Y_AXIS));

			// Add in Elements
			panelOptions.add(getPanelOptionsBlue(), null);
			panelOptions.add(getPanelOptionsGreen(), null);
			panelOptions.add(getPanelOptionsOrange(), null);

		
			/*
			 * Radio buttons have to be part of a group in order for them to
			 * work as expected.   Here to initialise the group and put all
			 * of the options into them.
			 */
			ColorGroup = new ButtonGroup();
			
			// Insert Elements
			ColorGroup.add(getRadioBlue());
			ColorGroup.add(getRadioGreen());
			ColorGroup.add(getRadioOrange());
		}
		
		// Return Instance
		return panelOptions;
	}
	// End of getPanelOptions Method

	
	/**
	 * This method initialises panelOptionsBlue.   Allows a user to select the
	 * blue icon set.	
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPanelOptionsBlue() {
		
		// Check for Existence
		if (panelOptionsBlue == null) {

			// Create Instance and Set Layout
			panelOptionsBlue = new JPanel();
			panelOptionsBlue.setLayout(new BoxLayout(getPanelOptionsBlue(), BoxLayout.X_AXIS));

			// Insert Elements
			panelOptionsBlue.add(getRadioBlue(), null);
			panelOptionsBlue.add(getLabelBlue(), null);
			panelOptionsBlue.add(Box.createHorizontalGlue());
		}
		
		// Return Instance
		return panelOptionsBlue;
	}
	// End of getPanelOptionsBlue Method


	/**
	 * This method initialises labelBlue.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelBlue() {
		
		// Check for Existence
		if (labelBlue == null) {
			
			// Create Instance
			labelBlue = new JLabel();
			
			// Set the Text
			labelBlue.setText(Lang.get("Options.Interface.Icons.Blue"));
		}
		
		// Return Instance
		return labelBlue;
	}
	// End of getLabelBlue Method
	
	
	/**
	 * This method initialises panelOptionsGreen. Allows a user to select the
	 * green icon set.	
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPanelOptionsGreen() {
		
		// Check for Existence
		if (panelOptionsGreen == null) {
			
			// Create Instance and Establish Layout
			panelOptionsGreen = new JPanel();
			panelOptionsGreen.setLayout(new BoxLayout(getPanelOptionsGreen(), BoxLayout.X_AXIS));
			
			// Insert Element
			panelOptionsGreen.add(getRadioGreen(), null);
			panelOptionsGreen.add(getLabelGreen(), null);
			panelOptionsGreen.add(Box.createHorizontalGlue());
		}
		
		// Return Instance
		return panelOptionsGreen;
	}
	// End of getPanelOptionsGreen Method

	
	/**
	 * This method initialises labelGreen.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelGreen() {
		
		// Check for Existence
		if (labelGreen == null) {
			
			// Create Instance
			labelGreen = new JLabel();
			
			// Set the Text
			labelGreen.setText(Lang.get("Options.Interface.Icons.Green"));
		}
		
		// Return Instance
		return labelGreen;
	}
	// End of getLabelGreen Method
	
	
	/**
	 * This method initialises panelOptionsOrange.	Allows a user to select the
	 * orange icon set.
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPanelOptionsOrange() {
		
		// Check for Existence
		if (panelOptionsOrange == null) {

			// Create Instance and Establish Layout
			panelOptionsOrange = new JPanel();
			panelOptionsOrange.setLayout(new BoxLayout(getPanelOptionsOrange(), BoxLayout.X_AXIS));

			// Insert Elements
			panelOptionsOrange.add(getRadioOrange(), null);
			panelOptionsOrange.add(getLabelOrange(), null);
			panelOptionsOrange.add(Box.createHorizontalGlue());
		}
		
		// Return Instance
		return panelOptionsOrange;
	}
	// End of getPanelOptionsOrange Method

	
	/**
	 * This method initialises labelOrange.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelOrange() {
		
		// Check for Existence
		if (labelOrange == null) {
			
			// Create Instance
			labelOrange = new JLabel();
			
			// Set the Text
			labelOrange.setText(Lang.get("Options.Interface.Icons.Orange"));
		}
		
		// Return Instance
		return labelOrange;
	}
	// End of getLabelOrange Method
	
	
	/**
	 * This method initialises radioBlue.	
	 * <p>
	 * @return javax.swing.JRadioButton	
	 */
	private JRadioButton getRadioBlue() {
		
		// Check for Existence
		if (radioBlue == null) {
			
			// Create Instance
			radioBlue = new JRadioButton();
			
			// Identifier
			radioBlue.setName("ICONS.BLUE");
		}
		
		// Return Instance
		return radioBlue;
	}
	// End of getRadioBlue Method

	
	/**
	 * This method initialises radioGreen.	
	 * <p> 	
	 * @return javax.swing.JRadioButton	
	 */
	private JRadioButton getRadioGreen() {
		
		// Check for Existence
		if (radioGreen == null) {
			
			// Create new Instance
			radioGreen = new JRadioButton();
			
			// Identifier
			radioGreen.setName("ICONS.GREEN");
		}
		
		// Return Instance
		return radioGreen;
	}
	// End of getRadioGreen Method

	
	/**
	 * This method initialises radioOrange.	
	 * <p>
	 * @return javax.swing.JRadioButton	
	 */
	private JRadioButton getRadioOrange() {
		
		// Check for Existence
		if (radioOrange == null) {
			
			// Create Instance
			radioOrange = new JRadioButton();
			
			// Identifier
			radioOrange.setName("ICONS.ORANGE");
		}
		
		// Return Instance
		return radioOrange;
	}
	// End of getRadioOrange Method

	
	/**
	 * This method initialises a JPanel component providing row elements. 
	 * <p>
	 * @param label JLabel instance which will be resized.
	 * @param widget JComponent instance which will be added as-is.
	 * @return JPanel containing the elements properly established.
	 */
	private JPanel getPanelRow(JLabel label, JComponent widget) {
		
		/*
		 * In order to create a consistent look and feel with our use of 
		 * BoxLayout we will resize all the elements from this point.  However
		 * we maintain Height as to adjust if there are font changes.
		 */
		label.setPreferredSize(
			new Dimension(
				Constants.getLabelWidth(),
				label.getPreferredSize().height)
		  );
		
		/*
		 * Here we adjust the maximum values to be suitable for our needs.  
		 * Essentially we are not looking for text fields to grow exponentially
		 * when a user resizes itself.
		 */
		widget.setMaximumSize(
			new Dimension(
				widget.getMaximumSize().width,
				widget.getPreferredSize().height + Constants.getPaddingHeight())
		  );
		
		/*
		 * We create the element at this point.  We essentially throw all
		 * of the instances into a newly created section and call it the
		 * end of a day.
		 */
		
		// Create instance
		JPanel row = new JPanel();

		// Establish layout
		row.setLayout(new BoxLayout(row, BoxLayout.X_AXIS));
		
		// Insertion of the label and spacer
		row.add(label);
		row.add(Box.createHorizontalStrut(Constants.getLabelSpacer()));
		
		// Insertion of the widget and end spacer
		row.add(widget);
		row.add(Box.createHorizontalGlue());
		
		// Pass on row
		return row;
	}
	// End of getPanelRow Method
	
	
	/**
	 * Returns a map containing all of the necessary elements controlled in
	 * this panel.  This in turn can be used to directly replace the main map
	 * and database entry.
	 * <p>
	 * @return Map containing keys and attributes.
	 */
	public Map<String,String> getState() {
		
		// Create storage handle
		Map<String,String> state = new HashMap<String,String>();
		
		/*
		 * We parse and drop in the necessary information from all of the 
		 * instances that we have here.  A rather manual process, however there
		 * is little reason to complicate the matters due to the fact of the
		 * limited projected growth.
		 */
		
		// Theme Selection
		state.put(
			"Setting.Interface.Theme",
			getComboTheme().getSelectedItem().toString()
		  );
		
		// Ticker Smooth Display
		state.put(
			"Setting.Interface.Smooth",
			Boolean.toString(getCheckSmooth().isSelected())
		  );
		
		// Album Filtering Display
		state.put(
			"Setting.Interface.Album",
			Boolean.toString(getCheckAlbum().isSelected())
		  );
		
		// Artist Filtering Display
		state.put(
			"Setting.Interface.Artist",
			Boolean.toString(getCheckArtist().isSelected())
		  );
		
		// Genre Filtering Display
		state.put(
			"Setting.Interface.Genre",
			Boolean.toString(getCheckGenre().isSelected())
		  );
		
		// Playlist Display
		state.put(
			"Setting.Interface.Playlist",
			Boolean.toString(getCheckPlaylists().isSelected())
		  );
		
		
		/*
		 * COLOUR SELECTIONS
		 */
		
		// Colour Custom Selection
		state.put(
			"Setting.Interface.Custom",
			Boolean.toString(getCheckCustom().isSelected())
		  );
		
		// Primary Font Colour
		state.put(
			"Setting.Interface.Color.Font.Primary",
			Integer.toString(getButtonPrimaryFont().getBackground().getRGB())
		  );
		
		// Primary Row Colour
		state.put(
			"Setting.Interface.Color.Row.Primary",
			Integer.toString(getButtonPrimaryColor().getBackground().getRGB())
		  );
		
		// Secondary Row Colour
		state.put(
			"Setting.Interface.Color.Row.Secondary",
			Integer.toString(getButtonSecondaryColor().getBackground().getRGB())
		  );
		
		// Highlighted Row Colour
		state.put(
			"Setting.Interface.Color.Row.Highlight",
			Integer.toString(getButtonHighlightColor().getBackground().getRGB())
		  );
		
		// Highlighted Font Colour
		state.put(
			"Setting.Interface.Color.Font.Highlight",
			Integer.toString(getButtonHighlightFont().getBackground().getRGB())
		  );
				
		
		/*
		 * Icon selection is more complicated due to the fact that the group
		 * does not necessarily grant easy access for the selected items. The
		 * default icons that will be selected in case of failure will always
		 * be BLUE.
		 */
		
		// Green Potential
		if (getRadioGreen().isSelected())
			state.put("Setting.Interface.Icons", "GREEN");
		
		// Orange Potential
		else if (getRadioOrange().isSelected())
			state.put("Setting.Interface.Icons", "ORANGE");
		
		// Blue Default
		else
			state.put("Setting.Interface.Icons", "BLUE");
		
		
		// Return State
		return state;
	}
	// End of getState Method
	
	
	/**
	 * Establishes the defaults for the elements displayed within the
	 * panel.  Includes colours and checkbox states.
	 */
	public void setState() {
		
		// Direct pass through
		Interface.setState();
	}
	// End of setState 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 ActionListener, ChangeListener {

		// Class Logger Identifier
    	private static final String CLASS = "org.lyra.Interface.Options.InterfacePanel.Interact";

		
		/**
		 * Default constructor for the class. 
		 */
		public Interact() {}
		
		
		/**
		 * Establishes the defaults for the elements displayed within the
		 * panel.  Includes colours and checkbox states.
		 */
		public void setState() {
			
			/*
			 * Theme information is only dealt with at one element.  Hence 
			 * only one instance to configure. 
			 */
			getComboTheme().setSelectedItem(
					Global.get("Setting.Interface.Theme"));
			
			
			/*
			 * We loop through the elements and determine which one should be
			 * selected.  When we have a match we select and move on.
			 */
		    for (Enumeration<AbstractButton> e 
		    		= ColorGroup.getElements(); e.hasMoreElements();) {

		    	// Extract Element
		    	AbstractButton cur = e.nextElement();
		         
		         // Check for Match
		         if (cur.getName().endsWith(Global.get("Setting.Interface.Icons"))) {
		        	 
		        	 // Establish Selection
		        	 cur.setSelected(true);
		        	 
		        	 // End loop
		        	 break;
		         }
		     }
			
			
			/*
			 * This makes the buttons more visual overall.  They will show off
			 * the colour that will be assigned to a particular element/
			 */
			
			// Primary Row Colour
			getButtonPrimaryColor().setBackground(
					new Color(
						Integer.parseInt(Global.get("Setting.Interface.Color.Row.Primary"))
				  ));
			
			// Secondary Row Colour
			getButtonSecondaryColor().setBackground(
					new Color(
						Integer.parseInt(Global.get("Setting.Interface.Color.Row.Secondary"))
				  ));
			
			// Highlighted Row Background Colour
			getButtonHighlightColor().setBackground(
				new Color(
					Integer.parseInt(Global.get("Setting.Interface.Color.Row.Highlight"))
			  ));

			// Primary Font Colour
			getButtonPrimaryFont().setBackground(
					new Color(
						Integer.parseInt(Global.get("Setting.Interface.Color.Font.Primary"))
				  ));
			
			// Highlighted Row Font Colour
			getButtonHighlightFont().setBackground(
					new Color(
						Integer.parseInt(Global.get("Setting.Interface.Color.Font.Highlight"))
				  ));
			
			/*
			 * Establish the state on the check boxes displayed within this
			 * panel.
			 */
			
			// Smooth Ticker Display
			getCheckSmooth().setSelected(
				Boolean.parseBoolean(
					Global.get("Setting.Interface.Smooth")
			  ));
			
			// Album Filter Display
			getCheckAlbum().setSelected(
				Boolean.parseBoolean(
					Global.get("Setting.Interface.Album")
			  ));
			
			// Artist Filter Display
			getCheckArtist().setSelected(
				Boolean.parseBoolean(
					Global.get("Setting.Interface.Artist")
			  ));
			
			// Genre Filter Display
			getCheckGenre().setSelected(
				Boolean.parseBoolean(
					Global.get("Setting.Interface.Genre")
			  ));
			
			// Playlists Display
			getCheckPlaylists().setSelected(
				Boolean.parseBoolean(
					Global.get("Setting.Interface.Playlist")
			  ));
			
			// Custom Colour Selector
			getCheckCustom().setSelected(
				Boolean.parseBoolean(
					Global.get("Setting.Interface.Custom")
			  ));
			
		}
		
		
		/* (non-Javadoc)
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent evt) {
			
			// Confirm element we are dealing with
			if (evt.getSource() instanceof JButton) {
				
				// Extract Element
				JButton source = (JButton)evt.getSource();
				
				// Must be one of the colour options
				if (source.getName().startsWith("COLOR")) {
					
					/*
					 * Now we know to trigger a Dialog that will block the
					 * options window and permit the user to select a new
					 * colour.
					 */
					Color choice = JColorChooser.showDialog(
							Parent,
                            Lang.get("Options.Interface.Select"),
                            source.getBackground()
                      );
					
					// Update element based on choice
					if (choice != null) {
						
						// Change
						source.setBackground(choice);
						
						// Log the event
						Logger.Info(
							CLASS,
							"actionPerformed",
							Lang.get("Options.Log.Interface.Color")
								.replaceAll("MTYPE", source.getName())
								.replaceAll("MCOLOR", choice.toString())
						  );
					}
				}
			}
		}
		// End of actionPerformed Method


		/* (non-Javadoc)
		 * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
		 */
		public void stateChanged(ChangeEvent evt) {
			
			/*
			 * We only need to deal with an instance of JCheckBox and more
			 * specifically we only care about the checkCustom itself.
			 */
			if (evt.getSource() instanceof JCheckBox) {
				
				// Extract Source
				JCheckBox source = (JCheckBox)evt.getSource();
				
				// The exact Element we are looking for
				if (source.getName().equals(getCheckCustom().getName())) {
					
					// Change the enabled state for a panel
					SwingUtilities.invokeLater(new Runnable() {
						
						/* (non-Javadoc)
						 * @see java.lang.Runnable#run()
						 */
						public void run() {
							
							/*
							 * Adjust the settings in a worker thread in order
							 * to prevent some potential secondary trigger
							 * based on the change.
							 * 
							 * In this particular case we disable editing for
							 * elements when we choose not to make use of the
							 * custom colours.
							 */
							getButtonHighlightColor().setEnabled(
									getCheckCustom().isSelected());
							
							getButtonHighlightFont().setEnabled(
									getCheckCustom().isSelected());
							
							getButtonPrimaryColor().setEnabled(
									getCheckCustom().isSelected());
							
							getButtonPrimaryFont().setEnabled(
									getCheckCustom().isSelected());
							
							getButtonSecondaryColor().setEnabled(
									getCheckCustom().isSelected());

						}
					});
					
					// Log the event
					Logger.Info(
						CLASS,
						"stateChanged",
						Lang.get("Options.Log.Interface.Custom")
							.replaceAll("MSTATE", Boolean.toString(source.isSelected()))
					  );
				}
				
			}
			
		}
		// End of stateChanged Method
		
	}
	// End of Interact Class
	
}
