/**
 * 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.Box;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;

import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.Font;
import java.awt.Color;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import org.lyra.Ledger;
import org.lyra.Lyra;
import org.lyra.Interface.Constants;
import org.lyra.LastDotFm.Demarcation;
import org.lyra.Widgets.RapidDialog;


/**
 * Certain host features such as consume can be modified from this particular
 * panel.  While not necessarily application specific their location is
 * suitable.
 * <p>
 * @author Martin Foster
 * @version 1.0.4, %Revision, 147%, %LastChangedDate, 06/11/11 4:57PM%
 * @since 1.0.1
 */
public class LastDotFmPanel extends JPanel {

	// Serial Requirements
	private static final long serialVersionUID = 1L;
	
	// About Section
	private JTextArea areaAbout = null;
	private JPanel panelAbout = null;
	private JLabel iconAbout = null;
	
	// Additional About Sections
	private JPanel panelSupplemental = null;
	private JPanel panelGroup = null;
	private JTextArea areaClear = null;
	private JTextArea areaRegister = null;
	private JTextArea areaIntegrate = null;
	
	// Progress Bars
	private JProgressBar progressToken = null;
	private JProgressBar progressSession = null; 
	
	// Registration
	private JPanel panelRegister = null;
	private JPanel panelJoin = null;
	private JPanel panelAuthorize = null;
	private JLabel labelJoin = null;
	private JLabel labelRegister = null;
	
	// Integration Panel
	private JPanel panelIntegrate = null;
	private JLabel labelIntegrate = null;
	
	// Clear Out Integration
	private JPanel panelClear = null;
	private JLabel labelClear = null;
	
	
	/*
	 * PACKAGE INSTANCES
	 */
	
	// Logging
	Ledger Logger;
	
	// Language independence and global settings
	Map<String,String> Global;
	Map<String,String> Lang;
	
	
	/*
	 * CLASS INSTANCES
	 */
	
	// Interactivity
	private Interact Interface;
	private Window Parent;
	
	// Integration Token Issued from Last.fm
	private String myToken;
	
	// State Information
	private Map<String,String> State;
	
	
	/**
	 * This is the default constructor used for Visual Editors only.  There
	 * is no user interaction capability built-in.
	 */
	@SuppressWarnings("serial")
	public LastDotFmPanel() {
		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>(){
			{
	        	// Label Elements
				put("Options.LastDotFm.Title", "Last.fm Integration");
				put("Options.LastDotFm.About", "Put in a useful about section here");
				put("Options.LastDotFm.Join", "Random");
				put("Options.LastDotFm.Register", "http://www.last.fm/api/auth/");
				put("Options.LastDotFm.Integrate", "Integrate Lyra with Last.fm");
				put("Options.LastDotFm.Clear", "I no longer wish to integrate Lyra with Last.fm");
				put("Options.LastDotFm.Note.Label", "Note:");
				put("Options.LastDotFm.Note.Message", "Your username and password are not collected nor stored with this integration.  They remain exclusively with the Last.fm service.");

				// Additionally appended instructions
				put("Options.LastDotFm.About.Clear", "Additional text about removing integration");
				put("Options.LastDotFm.About.Integrate", "Additional text about integration");
				put("Options.LastDotFm.About.Register", "Additional text for registering");

				// Progress Displays
				put("Options.LastDotFm.Progress.Token","Awaiting token generation...");
				put("Options.LastDotFm.Progress.Session","Awaiting session completion...");
			}
		};
		
		// Populate Elements
		initFrame();
	}
	// End of constructor class

	
	/**
	 * Primary constructor for the class with full interactive capabilities.
	 * <p>
	 * @param logger Ledger instance for logging of actions.
	 * @param global Global settings map.
	 * @param lang Language specific map.
	 * @param parent Parent window to block when calling.
	 */
	public LastDotFmPanel(Ledger logger, Map<String,String> global, Map<String,String> lang, Window parent) {
		
		// Pass Up
		this.Logger = logger;
		this.Global = global;
		this.Lang   = lang;
		this.Parent = parent;
		
		// Create Instance
		this.Interface = new Interact();
		
		/*
		 * We adjust the visibility of certain panels based on the current
		 * state.  However, at application startup there is either a
		 * non-integrated state or an integrated state.
		 */
		
		// Not Yet Integrated
		if (Global.get("LastDotFm.Session").equals("0")) {
			
			// Set Visibility
			getProgressToken().setVisible(true);
			
			// Perform the update
			Interface.fetchSessions();
		}
		
		// Integrated State
		else {
			
			// Set Visibility
			getAreaClear().setVisible(true);
			getPanelClear().setVisible(true);
		}
		
		/*
		 * We have created pseudo hyper link elements that are used to perform
		 * tasks.  In order to make sure the colours always work, we make use
		 * of the icon colour sets.
		 */
		
		// Holder with default blue
		Color link = Color.BLUE;
		
		// Determine colour
		
		// Orange
		if (Global.get("Setting.Interface.Icons").equals("ORANGE"))
			link = Color.ORANGE;
		
		// Green
		else if (Global.get("Setting.Interface.Icons").equals("GREEN"))
			link = Color.GREEN;
		
		
		// Adjust colours
		getLabelClear().setForeground(link);
		getLabelIntegrate().setForeground(link);
		getLabelJoin().setForeground(link);
		getLabelRegister().setForeground(link);

		// Populate Elements
		initFrame();
	}
	// End of Constructor Class
	
	
	/**
	 * Returns the collected state information so that it can be saved once
	 * prompted.   
	 * <p>
	 * @return Map containing integration elements.
	 */
	public Map<String,String> getState() {
		
		// Return element
		return State;
	}
	// End of getState Method
	
	
	/**
	 * This method inserts the baseline elements as required for the user
	 * interface.
	 */
	private void initFrame() {
		
		// Establish layout and border
		this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
		this.setBorder(BorderFactory.createTitledBorder(
			null, 
			Lang.get("Options.LastDotFm.Title"), 
			TitledBorder.DEFAULT_JUSTIFICATION, 
			TitledBorder.DEFAULT_POSITION, 
			new Font("Dialog", Font.BOLD, 12), 
			new Color(51, 51, 51)
		  ));

		// Insert Components
		this.add(getPanelAbout(), null);
		
		// Spacing and supplemental
		this.add(Box.createVerticalStrut(Constants.getRowGap()));
		this.add(getPanelSupplemental(), null);
		
		// Spacing and actions
		this.add(Box.createVerticalStrut(Constants.getRowGap()));
		this.add(getPanelRegister(), null);
		this.add(getPanelIntegrate(), null);
		this.add(getPanelClear(), null);
		
		// Spacing
		this.add(Box.createVerticalGlue());
	}
	// End of initFrame Method

	
	/**
	 * This method initialises areaAbout.  Contains a very basic blurb on what
	 * Last.fm is and what it can bring forth to the user.
	 * <p>
	 * @return javax.swing.JTextArea	
	 */
	private JTextArea getAreaAbout() {
		
		// Check for Existence
		if (areaAbout == null) {
			
			// Create Instance
			areaAbout = new JTextArea();

			/*
			 * We fake this textArea to look like a JLabel, since it supports
			 * line wrapping.  The only down side is the last of HTML support.
			 */
			
			// General look elements
			areaAbout.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
			areaAbout.setMargin(new Insets(2, 2, 2, 2));
			areaAbout.setBackground(new Color(0,0,0,0));
			areaAbout.setOpaque(false);

			// General behaviour elements
			areaAbout.setEditable(false);
			areaAbout.setLineWrap(true);
			areaAbout.setWrapStyleWord(true);

			// Text
			areaAbout.setText(Lang.get("Options.LastDotFm.About"));
			areaAbout.setRows(areaAbout.getLineCount());

			// Identifier
			areaAbout.setName("LAST.ABOUT");
		}
		
		// Return Instance
		return areaAbout;
	}
	// End of getAreaAbout Method

	
	/**
	 * This method initialises areaClear.  Contains a very basic blurb on the
	 * ability to clear out integration.
	 * <p>
	 * @return javax.swing.JTextArea	
	 */
	private JTextArea getAreaClear() {
		
		// Check for Existence
		if (areaClear == null) {
			
			// Create Instance
			areaClear = new JTextArea();

			/*
			 * We fake this textArea to look like a JLabel, since it supports
			 * line wrapping.  The only down side is the last of HTML support.
			 */
			
			// General look elements
			areaClear.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
			areaClear.setMargin(new Insets(2, 2, 2, 2));
			areaClear.setBackground(new Color(0,0,0,0));
			areaClear.setOpaque(false);

			// General behaviour elements
			areaClear.setEditable(false);
			areaClear.setLineWrap(true);
			areaClear.setWrapStyleWord(true);

			// Text
			areaClear.setText(Lang.get("Options.LastDotFm.About.Clear"));
			areaClear.setRows(areaClear.getLineCount());
			
			// Font Adjustment
			areaClear.setFont(
				areaClear.getFont().deriveFont(Font.BOLD));
			
			// Automatically hide until controls
			areaClear.setVisible(false);
		}
		
		// Return Instance
		return areaClear;
	}
	// End of getAreaClear Method
	
	
	/**
	 * This method initialises areaRegister.  Contains a very basic blurb on what
	 * requirements to register prior to integration.
	 * <p>
	 * @return javax.swing.JTextArea	
	 */
	private JTextArea getAreaRegister() {
		
		// Check for Existence
		if (areaRegister == null) {
			
			// Create Instance
			areaRegister = new JTextArea();

			/*
			 * We fake this textArea to look like a JLabel, since it supports
			 * line wrapping.  The only down side is the last of HTML support.
			 */
			
			// General look elements
			areaRegister.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
			areaRegister.setMargin(new Insets(2, 2, 2, 2));
			areaRegister.setBackground(new Color(0,0,0,0));
			areaRegister.setOpaque(false);

			// General behaviour elements
			areaRegister.setEditable(false);
			areaRegister.setLineWrap(true);
			areaRegister.setWrapStyleWord(true);

			// Text
			areaRegister.setText(Lang.get("Options.LastDotFm.About.Register"));
			areaRegister.setRows(areaRegister.getLineCount());
			
			// Font Adjustment
			areaRegister.setFont(
				areaRegister.getFont().deriveFont(Font.BOLD));
			
			// Automatically hide until controls
			areaRegister.setVisible(false);
		}
		
		// Return Instance
		return areaRegister;
	}
	// End of getAreaRegister Method
	
	
	/**
	 * This method initialises areaIntegrate.  Contains a very basic blurb on what
	 * process to integrate.
	 * <p>
	 * @return javax.swing.JTextArea	
	 */
	private JTextArea getAreaIntegrate() {
		
		// Check for Existence
		if (areaIntegrate == null) {
			
			// Create Instance
			areaIntegrate = new JTextArea();

			/*
			 * We fake this textArea to look like a JLabel, since it supports
			 * line wrapping.  The only down side is the last of HTML support.
			 */
			
			// General look elements
			areaIntegrate.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
			areaIntegrate.setMargin(new Insets(2, 2, 2, 2));
			areaIntegrate.setBackground(new Color(0,0,0,0));
			areaIntegrate.setOpaque(false);

			// General behaviour elements
			areaIntegrate.setEditable(false);
			areaIntegrate.setLineWrap(true);
			areaIntegrate.setWrapStyleWord(true);

			// Text
			areaIntegrate.setText(Lang.get("Options.LastDotFm.About.Integrate"));
			areaIntegrate.setRows(areaIntegrate.getLineCount());
			
			// Font Adjustment
			areaIntegrate.setFont(
				areaIntegrate.getFont().deriveFont(Font.BOLD));
			
			// Automatically hide until controls
			areaIntegrate.setVisible(false);
		}
			
		// Return Instance
		return areaIntegrate;
	}
	// End of getAreaIntegrate Method
	
	/**
	 * This method initialises panelAbout.  Contains the icon and about text
	 * necessary to inform a user about this specific integration.	
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPanelAbout() {
		
		// Check for Existence
		if (panelAbout == null) {
			
			// Create instance and layout
			panelAbout = new JPanel();
			panelAbout.setLayout(new BoxLayout(getPanelAbout(), BoxLayout.X_AXIS));
			
			// Insert Elements
			
			// Icon and Spacer
			panelAbout.add(getIconAbout(), null);
			panelAbout.add(Box.createHorizontalStrut(Constants.getSmallGap()));
			
			// Main body of text
			panelAbout.add(getAreaAbout(), null);
		}
		
		// Return Instance
		return panelAbout;
	}
	// End of getPanelAbout Method

	
	/**
	 * This method initialises panelSupplemental.  Contains all of the
	 * supplemental help documents necessary to fully describe the panel.	
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPanelSupplemental() {
		
		// Check for Existence
		if (panelSupplemental == null) {
			
			// Create instance and layout
			panelSupplemental = new JPanel();
			panelSupplemental.setLayout(new BoxLayout(getPanelSupplemental(), BoxLayout.X_AXIS));
			
			// Insert Elements
			
			// Icon and Spacer
			panelSupplemental.add(Box.createHorizontalStrut(getIconAbout().getIcon().getIconWidth()));
			panelSupplemental.add(Box.createHorizontalStrut(Constants.getSmallGap()));
			
			// Main body of text
			panelSupplemental.add(getPanelGroup(), null);
		}
		
		// Return Instance
		return panelSupplemental;
	}
	// End of getPanelSupplemental Method
	
	
	/**
	 * This method initialises panelGroup.  Contains all of the
	 * Group help documents necessary to fully describe the panel.	
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPanelGroup() {
		
		// Check for Existence
		if (panelGroup == null) {
			
			// Create instance and layout
			panelGroup = new JPanel();
			panelGroup.setLayout(new BoxLayout(getPanelGroup(), BoxLayout.Y_AXIS));
			
			// Insert Elements
			panelGroup.add(getProgressToken(), null);
			panelGroup.add(getAreaRegister(), null);
			panelGroup.add(getAreaIntegrate(), null);
			panelGroup.add(getProgressSession(), null);
			panelGroup.add(getAreaClear(), null);
		}
		
		// Return Instance
		return panelGroup;
	}
	// End of getPanelGroup Method
	
	
	/**
	 * This method initialises iconAbout.  The image displaying the site with
	 * which we are integrating with.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getIconAbout() {
		
		if (iconAbout == null) {

			// Create Instance
			iconAbout = new JLabel();
			
			// Establish Image
			iconAbout.setIcon(new ImageIcon(
					getClass().getResource(
							Lyra.getIconByMap("LastDotFm-Small"))));
		}
		
		// Return Instance
		return iconAbout;
	}
	// End of getIconAbout Method
	
	
	/**
	 * This method initialises panelRegister.  Register enables us to perform
	 * the necessary steps for integration and requires the user to register
	 * with the Last.fm web site directly.	
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPanelRegister() {
		
		// Check for Existence
		if (panelRegister == null) {
			
			// Create Instance and Establish Layout
			panelRegister = new JPanel();
			panelRegister.setLayout(new BoxLayout(getPanelRegister(), BoxLayout.Y_AXIS));

			// Insert Elements
			panelRegister.add(getPanelJoin(), null);
			panelRegister.add(getPanelAuthorize(), null);
			
			// Automatically hide until controls
			panelRegister.setVisible(false);
		}
		
		// Return Instance
		return panelRegister;
	}
	// End of getPanelRegister Method

	

	/**
	 * Produces the hyper link which will be used to generate an action.  For
	 * this element a new browser window will be forced open.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelRegister() {
		
		// Check for Existence
		if (labelRegister == null) {
			
			// Create Instance
			labelRegister = new JLabel();
			labelRegister.setText(Lang.get("Options.LastDotFm.Register"));

			// Emphasis text
			labelRegister.setFont(
				labelRegister.getFont().deriveFont(Font.BOLD));
			
			// Cursor Settings
			labelRegister.setCursor(new Cursor(Cursor.HAND_CURSOR));
			
			// Identifier
			labelRegister.setName("LAST.REGISTER");
			labelRegister.addMouseListener(Interface);
		}
		
		// Return Instance
		return labelRegister;
	}
	// End of getLabelRegister Method

	
	/**
	 * Produces the hyper link which will be used to generate an action.  For
	 * this element a new browser window will be forced open.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelJoin() {
		
		// Check for Existence
		if (labelJoin == null) {
			
			// Create Instance
			labelJoin = new JLabel();
			labelJoin.setText(Lang.get("Options.LastDotFm.Join"));

			// Emphasis text
			labelJoin.setFont(
				labelJoin.getFont().deriveFont(Font.BOLD));
			
			// Cursor Settings
			labelJoin.setCursor(new Cursor(Cursor.HAND_CURSOR));
			
			// Identifier
			labelJoin.setName("LAST.JOIN");
			labelJoin.addMouseListener(Interface);
		}
		
		// Return Instance
		return labelJoin;
	}
	// End of getLabelJoin Method


	/**
	 * This method initialises panelIntegrate.  Completes the integration
	 * process and permits Lyra and Last.fm to work together.	
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPanelIntegrate() {
		
		// Check for Existence
		if (panelIntegrate == null) {
			
			// Create Instance and Establish Layout
			panelIntegrate = new JPanel();
			panelIntegrate.setLayout(new BoxLayout(getPanelIntegrate(), BoxLayout.X_AXIS));

			// Insert Appropriate Spacing
			panelIntegrate.add(Box.createHorizontalStrut(getIconAbout().getIcon().getIconWidth()));
			panelIntegrate.add(Box.createHorizontalStrut(Constants.getNormalGap()));

			// Insert Element
			panelIntegrate.add(getLabelIntegrate(), null);
			
			// Fill in the rest to justify
			panelIntegrate.add(Box.createHorizontalGlue());
			
			// Automatically hide until controls
			panelIntegrate.setVisible(false);
		}
		
		// Return Instance
		return panelIntegrate;
	}
	// End of getPanelIntegrate Method
	
	
	/**
	 * Produces the hyper link which will be used to generate an action.  For
	 * this element a new browser window will be forced open.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelIntegrate() {
		
		// Check for Existence
		if (labelIntegrate == null) {
			
			// Create Instance
			labelIntegrate = new JLabel();
			labelIntegrate.setText(Lang.get("Options.LastDotFm.Integrate"));

			// Emphasis text
			labelIntegrate.setFont(
				labelIntegrate.getFont().deriveFont(Font.BOLD));
			
			// Cursor Settings
			labelIntegrate.setCursor(new Cursor(Cursor.HAND_CURSOR));
			
			// Identifier
			labelIntegrate.setName("LAST.INTEGRATE");
			labelIntegrate.addMouseListener(Interface);
		}
		
		// Return Instance
		return labelIntegrate;
	}
	// End of getLabelIntegrate Method
	

	/**
	 * This method initialises panelClear.	Prompt the user to clear out the
	 * information that is used in the integration process.
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPanelClear() {

		// Check for Existence
		if (panelClear == null) {

			// Create Instance and Establish Layout
			panelClear = new JPanel();
			panelClear.setLayout(new BoxLayout(getPanelClear(), BoxLayout.X_AXIS));
			
			// Insert Appropriate Spacing
			panelClear.add(Box.createHorizontalStrut(getIconAbout().getIcon().getIconWidth()));
			panelClear.add(Box.createHorizontalStrut(Constants.getNormalGap()));

			// Insert Element
			panelClear.add(getLabelClear(), null);
			
			// Fill in the rest to justify
			panelClear.add(Box.createHorizontalGlue());
			
			// Automatically hide until controls
			panelClear.setVisible(false);
		}
		
		// Return Instance
		return panelClear;
	}
	// End of getPanelClear Method
	
	
	/**
	 * Produces the hyper link which will be used to generate an action.  For
	 * this element all information will be reset.
	 * <p>
	 * @return javax.swing.JLabel
	 */
	private JLabel getLabelClear() {
		
		// Check for Existence
		if (labelClear == null) {
			
			// Create Instance
			labelClear = new JLabel();
			labelClear.setText(Lang.get("Options.LastDotFm.Clear"));

			// Emphasis text
			labelClear.setFont(
				labelClear.getFont().deriveFont(Font.BOLD));
			
			// Cursor Settings
			labelClear.setCursor(new Cursor(Cursor.HAND_CURSOR));
			
			// Identifier
			labelClear.setName("LAST.CLEAR");
			labelClear.addMouseListener(Interface);
		}
		
		// Return Instance
		return labelClear;
	}
	// End of getLabelClear Method

	
	/**
	 * This method initialises panelJoin.  Allows the user to join in in order
	 * to integrate.
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPanelJoin() {
		
		// Check for Existence
		if (panelJoin == null) {
			
			// Create Instance and Establish Layout
			panelJoin = new JPanel();
			panelJoin.setLayout(new BoxLayout(getPanelJoin(), BoxLayout.X_AXIS));

			// Insert Appropriate Spacing
			panelJoin.add(Box.createHorizontalStrut(getIconAbout().getIcon().getIconWidth()));
			panelJoin.add(Box.createHorizontalStrut(Constants.getNormalGap()));

			// Insert Element
			panelJoin.add(getLabelJoin(), null);
			
			// Fill in the rest to justify
			panelJoin.add(Box.createHorizontalGlue());
		}
		
		// Return Instance
		return panelJoin;
	}
	// End of getPanelJoin Method

	
	/**
	 * This method initialises panelAuthorize.	Holds the actual register label
	 * since we can't use the same panel name twice.
	 * <p>
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPanelAuthorize() {
		
		// Check for Existence
		if (panelAuthorize == null) {
			
			// Create Instance and Establish Layout
			panelAuthorize = new JPanel();
			panelAuthorize.setLayout(new BoxLayout(getPanelAuthorize(), BoxLayout.X_AXIS));

			// Insert Appropriate Spacing
			panelAuthorize.add(Box.createHorizontalStrut(getIconAbout().getIcon().getIconWidth()));
			panelAuthorize.add(Box.createHorizontalStrut(Constants.getNormalGap()));

			// Insert Element
			panelAuthorize.add(getLabelRegister(), null);
			
			// Fill in the rest to justify
			panelAuthorize.add(Box.createHorizontalGlue());
		}
		
		// Return Instance
		return panelAuthorize;
	}
	// End of getPanelAuthorize Method
	
	
	/**
	 * Initialises the progressToken element.   Used as an interim display
	 * to prevent locking the display.
	 * <p>
	 * @return javax.swing.JProgressBar
	 */
	private JProgressBar getProgressToken() {
		
		// Check for Existence
		if (progressToken == null) {
			
			// Create Instance
			progressToken = new JProgressBar(
					SwingConstants.HORIZONTAL);
			
			// Never ending progress bar
			progressToken.setIndeterminate(true);
			
			// Label Display
			progressToken.setStringPainted(true);
			progressToken.setString(Lang.get("Options.LastDotFm.Progress.Token"));
			
			// Set Visibility
			progressToken.setVisible(false);
		}
		
		// Return Instance
		return progressToken;
	}
	// End of getProgressToken Method
	
	
	/**
	 * Initialises the progressSession element.   Used as an interim display
	 * to prevent locking the display.
	 * <p>
	 * @return javax.swing.JProgressBar
	 */
	private JProgressBar getProgressSession() {
		
		// Check for Existence
		if (progressSession == null) {
			
			// Create Instance
			progressSession = new JProgressBar(
					SwingConstants.HORIZONTAL);
			
			// Never ending progress bar
			progressSession.setIndeterminate(true);
			
			// Label Display
			progressSession.setStringPainted(true);
			progressSession.setString(Lang.get("Options.LastDotFm.Progress.Session"));
			
			// Set Visibility
			progressSession.setVisible(false);
		}
		
		// Return Instance
		return progressSession;
	}
	// End of getProgressSession 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, Runnable {

		
		// Runnable Thread
		private Thread myThread;
		
		
		/**
		 * There are two elements that require a browser to load up in order
		 * to proceed.  Since the require a fair amount of similar code we
		 * throw it in here.
		 * <p>
		 * @param link Address to send to browser.
		 */
		private void loadBrowser(String link) {
			
			// Launch a browser
			try {
				
				// Send off link
				Desktop.getDesktop().browse(
					URI.create(link));
			} 

			// Something failed above
			catch (IOException e) {
				
				// Create Instance
				RapidDialog rapid = new RapidDialog(Lang);
				
				// Notify User
				rapid.noticeDialog(
					Parent,
					Lang.get("Options.Log.Browser.Fail")
					    .replaceAll("MADDRESS", link));
			}
		}
		// End of loadBrowser Method
		
		
		/**
		 * Fetching material off of the Internet can be slow.  So we cannot
		 * rely on its speed nor reliability.  We make that happen in a
		 * new thread as to not block. 
		 */
		public void fetchSessions() {
			
			// Execute the authentication information
			myThread = new Thread(this);
			myThread.run();
		}
		// End of fetchSession Method
		
		
		/* (non-Javadoc)
		 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
		 */
		public void mouseClicked(MouseEvent evt) {
			
			// No other elements should play a part
			if (evt.getSource() instanceof JLabel) {
				
				// Extract the identifier
				String ident = 
					((JLabel)evt.getSource()).getName();
				
				/*
				 * Now we run through the options and do the appropriate
				 * actions.  Two circumstances, those directly below will
				 * trigger a browser load up.
				 */
				
				// Joining Link
				if (ident.equals(getLabelJoin().getName()))
					loadBrowser(Global.get("LastDotFm.Join"));
				
				// Registration Link
				else if (ident.equals(getLabelRegister().getName())) {
					
					// Load the browser
					loadBrowser(
						Global.get("LastDotFm.Authorize") +
						"?api_key=" + Global.get("LastDotFm.Key") +
						"&token=" + myToken
					  );

					// Adjust visibility
					getAreaRegister().setVisible(false);
					getPanelRegister().setVisible(false);
					getAreaIntegrate().setVisible(true);
					getPanelIntegrate().setVisible(true);
				}
				
				
				/*
				 * These elements are responsible for the linking or reversal
				 * of the integration process.
				 */
				
				// Integration
				else if (ident.equals(getLabelIntegrate().getName())) {
					
					// Hide integration panels
					getAreaIntegrate().setVisible(false);
					getPanelIntegrate().setVisible(false);
					
					// Show Progress bar
					getProgressSession().setVisible(true);
					
					// Extract Sessions
					fetchSessions();
				}
				
				// Unlinking
				else if (ident.equals(getLabelClear().getName())) {
					
					// Hide integration panels
					getAreaClear().setVisible(false);
					getPanelClear().setVisible(false);
					
					// Show Progress bar
					getProgressToken().setVisible(true);
					
					
					/*
					 * Now we need to translate the elements and bring them
					 * into Lyra specific instances. 
					 */
					State = new HashMap<String,String>();
					
					// Names matching the Global parameters 
					State.put("LastDotFm.Session",  "0");
					State.put("LastDotFm.Username", "0");
					

					/*
					 * Start the process over for getting a new token put
					 * into place.
					 */
					fetchSessions();
				}
			}
		}
		// End of mouseClicked Method

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

		/* (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) {}
		
		
		/* (non-Javadoc)
		 * @see java.lang.Runnable#run()
		 */
		public void run() {
			
			// Token Generation
			if (myToken == null) {
				
				// Extract Token
				myToken = Demarcation.getInstance(Logger, Global, Lang)
				                     .extracAuthToken();
				
				// Safety Check
				if (myToken != null) {
					
					SwingUtilities.invokeLater(new Runnable(){

						/* (non-Javadoc)
						 * @see java.lang.Runnable#run()
						 */
						public void run() {
							
							// Hide Progress Bar
							getProgressToken().setVisible(false);
							
							// Now we can display the elements
							getAreaRegister().setVisible(true);
							getPanelRegister().setVisible(true);
						}
					  });
				}
			}
			
			// Session Generation
			else {
				
				// Extract Token
				Map<String,String> session = 
					Demarcation.getInstance(Logger, Global, Lang)
					           .extracAuthSession(myToken);
				
				// Safety Check
				if (session.size() > 0) {
					
					// User Inteface Elements
					SwingUtilities.invokeLater(new Runnable(){

						/* (non-Javadoc)
						 * @see java.lang.Runnable#run()
						 */
						public void run() {
							
							// Hide Progress Bar
							getProgressSession().setVisible(false);
							
							// Now we can display the elements
							getAreaClear().setVisible(true);
							getPanelClear().setVisible(true);
						}
					  });
					
					
					/*
					 * Now we need to translate the elements and bring them
					 * into Lyra specific instances. 
					 */
					State = new HashMap<String,String>();
					
					// Names matching the Global parameters 
					State.put("LastDotFm.Session",  session.get("key"));
					State.put("LastDotFm.Username", session.get("name"));
				}
			}
		}
		// End of run Method
		
	}
	// End of Interact Class

}  //  @jve:decl-index=0:visual-constraint="10,10"
