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

import java.lang.Exception;
import java.util.Map;

import org.lyra.Ledger;

/**
 * This class provides a direct interface to the player capabilities of the
 * Multimedia Player Daemon (MPD).  For the most part, this is an interface
 * to the <i>Terminus</i>.  
 * <p>
 * @author Martin Foster
 * @version 1.0.4, %Revision, 87%, %LastChangedDate, 28/02/11 12:52PM%
 * @see org.lyra.Host.Terminus
 */
public class Playback {

	/*
	 * PACKAGE INSTANCES
	 */
	private Ledger Logger;
	private Terminus Host;
	private Map<String,String> Lang;
	
	/*
	 * CONSTANTS
	 */
	private static final String CLASS = "org.lyra.Host.Playback";
	
	/**
	 * Primary constructor for the class.  Will establish the base environment
	 * necessary to interact with the player side of the daemon.
	 * <p>
	 * @param logger Ledger instance for logging of events.
	 * @param host Host instance for interaction with the daemon.
	 * @param lang Map of language elements
	 */
	public Playback(Ledger logger, Terminus host, Map<String,String> lang) {
		
		// Pass up
		this.Logger = logger;
		this.Host = host;
		this.Lang = lang;
	}
	// End of Constructor Method
	
	
	/**
	 * Shifts the player to a song previous in the current playlist. 
	 * <p>
	 * @return Boolean on success of action.
	 */
	public boolean playPrevious() {
		
		// Attempt the connection
		try {
			
			// Log Event
			Logger.Info(
				CLASS,
				"playPrevious",
				Lang.get("Playback.Log.Previous")
			  );
			
			// Direct pass-through
			Host.writeBatch("Player.Previous");
			
			// Return result
			return Host.readResult();
		} 
		
		// Recover and try again
		catch (Exception e) {
			
			// Recover connect
			Host.Recover(e);
			
			// Try again
			return playPrevious();
		}

	}
	// End of playPrevious Method
	
	
	/**
	 * Stops the player and play back resetting the song position.
	 * <p>
	 * @return Boolean on success of action.
	 */
	public boolean playStop() {
		
		// Attempt the connection
		try {
			
			// Log Event
			Logger.Info(
				CLASS,
				"playStop",
				Lang.get("Playback.Log.Stop")
			  );
			
			// Direct pass-through
			Host.writeBatch("Player.Stop");
			
			// Return result
			return Host.readResult();
		} 
		
		// Recover and try again
		catch (Exception e) {
			
			// Recover connect
			Host.Recover(e);
			
			// Try again
			return playStop();
		}
	}
	// End of playStop Method
	
	
	/**
	 * Stops the plays but retains song position.
	 * <p>
	 * @return Boolean on success of action.
	 */
	public boolean playPause() {
		
		// Attempt the connection
		try {
			
			// Log Event
			Logger.Info(
				CLASS,
				"playPause",
				Lang.get("Playback.Log.Pause")
			  );

			// Direct pass-through
			Host.writeArgument("Player.Pause", "1");
			
			// Return result
			return Host.readResult();
		} 
		
		// Recover and try again
		catch (Exception e) {
			
			// Recover connect
			Host.Recover(e);
			
			// Try again
			return playPause();
		}

	}
	// End of playPause Method
	
	
	/**
	 * Starts playback resuming at last position.
	 * <p>
	 * @return Boolean on success of action.
	 */
	public boolean playResume() {
		
		// Attempt the connection
		try {
			
			// Log Event
			Logger.Info(
				CLASS,
				"playResume",
				Lang.get("Playback.Log.Resume")
			  );
			
			// Direct pass-through
			Host.writeArgument("Player.Pause", "0");
			
			// Return result
			return Host.readResult();
		} 
		
		// Recover and try again
		catch (Exception e) {
			
			// Recover connect
			Host.Recover(e);
			
			// Try again
			return playResume();
		}
	}
	// End of playResume Method
	
	
	/**
	 * Starts song play back.   This is based on a no element selected basis
	 * so it will simply assume the first element if it exists.
	 * <p>
	 * @return Boolean on success of action.
	 */
	public boolean playStart() {
		
		// Let the main method process
		return playStart(0);
	}
	// End of playStart Method
	
	
	/**
	 * Starts song play back.
	 * <p>
	 * @param pos Song position in the current playlist.
	 * @return Boolean on success of action.
	 */
	public boolean playStart(int pos) {
		
		// Quick single conversion
		String str_pos = Integer.toString(pos);
		
		// Attempt the connection
		try {
			
			// Log Event
			Logger.Info(
				CLASS,
				"playStart",
				Lang.get("Playback.Log.Play")
					.replaceAll("MPOS", str_pos)
			  );
			
			// Pass-through with the arguments
			Host.writeArgument("Player.Play", str_pos);
			
			// Return result
			return Host.readResult();	
		} 
		
		// Recover and try again
		catch (Exception e) {
			
			// Recover connect
			Host.Recover(e);
			
			// Try again
			return playStart(pos);
		}
	}
	// End of playStart Method
	
	
	/**
	 * This starts the play back of a specific song within the current playlist
	 * based on the song identifier.
	 * <p>
	 * @param ident Song Identifier
	 * @return Boolean on success of action.
	 */
	public boolean playStartByIdentifier(int ident) {
		
		// Quick conversion
		String str_ident = Integer.toString(ident);
		
		// Attempt the connection
		try {
			
			// Log Event
			Logger.Info(
				CLASS,
				"playStartByIdentifier",
				Lang.get("Playback.Log.Play.ID")
				  .replaceAll("MIDENT", str_ident)
			  );
			
			// Pass-through with the arguments
			Host.writeArgument("Player.Play.ID", str_ident);
			
			// Return result
			return Host.readResult();
		} 
		
		// Recover and try again
		catch (Exception e) {
			
			// Recover connect
			Host.Recover(e);
			
			// Try again
			return playStartByIdentifier(ident);
		}
	}
	// End of playStartByIdentifier Method
	
	
	/**
	 * Shifts the player to a song next in the current playlist. 
	 * <p>
	 * @return Boolean on success of action.
	 */
	public boolean playNext() {
		
		// Attempt the connection
		try {
			
			// Log Event
			Logger.Info(
				CLASS,
				"playNext",
				Lang.get("Playback.Log.Next")
			  );
					
			// Direct pass-through
			Host.writeBatch("Player.Next");
			
			// Return result
			return Host.readResult();
		} 
		
		// Recover and try again
		catch (Exception e) {
			
			// Recover connect
			Host.Recover(e);
			
			// Try again
			return playNext();
		}
	}
	// End of playNext Method
	
	
	/**
	 * Seeks to the position in seconds of entry in position in the playlist. 
	 * <p>
	 * @param pos Position in the current playlist.
	 * @param seconds Seconds to set the position of playback to.
	 * @return Boolean on success of action.
	 */
	public boolean playSeek(int pos, int seconds) {
		
		// Quick single conversion
		String str_pos     = Integer.toString(pos);
		String str_seconds = Integer.toString(seconds);
		
		// Attempt the connection
		try {
			
			// Log Event
			Logger.Info(
				CLASS,
				"playSeek",
				Lang.get("Playback.Log.Seek")
				 .replaceAll("MPOS", str_pos)
				 .replaceAll("MSEC", str_seconds)
			  );
			
			// Pass-through with the arguments
			Host.writeArgument(
				"Player.Seek", 
				str_pos,
				str_seconds
			  );
			
			// Return result
			return Host.readResult();
		} 
		
		// Recover and try again
		catch (Exception e) {
			
			// Recover connect
			Host.Recover(e);
			
			// Try again
			return playSeek(pos,seconds);
		}
	}
	// End of playSeek Method
	
	
	/**
	 * Seeks to the position in seconds of entry in identifier in the playlist. 
	 * <p>
	 * @param ident Identifier number for song in the current playlist.
	 * @param seconds Seconds to set the position of playback to.
	 * @return Boolean on success of action.
	 */
	public boolean playSeekByIdentifier(int ident, int seconds) {
		
		// Quick single conversion
		String str_ident   = Integer.toString(ident);
		String str_seconds = Integer.toString(seconds);
		
		// Attempt the connection
		try {
			
			// Log Event
			Logger.Info(
				CLASS,
				"playSeekByIdentifier",
				Lang.get("Playback.Log.Seek.ID")
				 .replaceAll("IDENT", str_ident)
				 .replaceAll("MSEC", str_seconds)
			  );
			
			// Pass-through with the arguments
			Host.writeArgument(
				"Player.Seek", 
				Integer.toString(ident),
				Integer.toString(seconds)
			  );
			
			// Return result
			return Host.readResult();
		} 
		
		// Recover and try again
		catch (Exception e) {
			
			// Recover connect
			Host.Recover(e);
			
			// Try again
			return playSeekByIdentifier(ident,seconds);
		}
	}
	// End of playSeekByIdentifier Method
}
