/***************************************************************************
    Copyright          : (C) 2002 by Neoworks Limited. All rights reserved
    URL                : http://www.neoworks.com
 ***************************************************************************/
/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

/*
 * TrackSourcePipelineElementSkeleton.java
 *
 * Created on 02 May 2002, 14:48
 */

package com.neoworks.jukex.tracksource;

import com.neoworks.jukex.Track;

import java.sql.*;
import java.util.LinkedList;
import java.util.List;

import com.neoworks.connectionpool.PoolManager;
import java.util.Map;

import org.apache.log4j.Category;

/**
 * Skeleton class that implements the framework for taking part in a Pipeline
 * of PipelineElement objects.
 *
 * @author Nick Vincent <a href="mailto:nick@neoworks.com">nick@neoworks.com</a>
 */
public abstract class TrackSourcePipelineElementSkeleton implements TrackSourcePipelineElement
{
	private static final Category log = Category.getInstance(TrackSourcePipelineElementSkeleton.class.getName());
	private static final boolean logDebugEnabled = log.isDebugEnabled();
	private static final boolean logInfoEnabled = log.isInfoEnabled();
	
	protected String name = null;
	private boolean enabled = true;
	private TrackSourcePipelineElement nextTrackSource = null;
	private TrackSourcePipeline pipeline = null;

	/**
	 * Default Constructor
	 */
	public TrackSourcePipelineElementSkeleton()
	{
	}

	/**
	 * Public Constructor
	 *
	 * @param tsp The parent Pipeline of this PipelineElement
	 */
	public TrackSourcePipelineElementSkeleton(TrackSourcePipeline tsp)
	{
		pipeline = tsp;
	}

	/**
	 * Public Constructor
	 *
	 * @param tsp The parent Pipeline of this PipelineElement
	 * @param name The name of this element
	 */
	public TrackSourcePipelineElementSkeleton(TrackSourcePipeline tsp, String name)
	{
		pipeline = tsp;
		this.name = name;
	}

	/**
	 * Public Constructor
	 *
	 * @param name The name of this element
	 */
	public TrackSourcePipelineElementSkeleton(String name)
	{
		this.name = name;
	}

	/**
	 * Tells this tracksource of a new link in the chain
	 *
	 * @return The previous TrackSource
	 */
	public final TrackSourcePipelineElement setNextTrackSource(TrackSourcePipelineElement nextTrackSource)
	{
		TrackSourcePipelineElement retval = this.nextTrackSource;
		this.nextTrackSource = nextTrackSource;
		return retval;
	}

	/**
	 * Return the next TrackSourcePipelineElement
	 *
	 * @return The next TrackSourcePipelineElement
	 */
	public final TrackSourcePipelineElement getNextTrackSource()
	{
		return this.nextTrackSource;
	}

	/**
	 * Get the next TrackSource that is not disabled. This should only be used when absolutely necessary.
	 * Use delegateGetNextTrack() or delegatePeek() where possible.
	 */
	/*protected TrackSourcePipelineElement getNextEnabledTrackSource()
	{
		TrackSourcePipelineElement t = this.nextTrackSource;
		if (t != null)
		{
			if (logDebugEnabled) log.debug("checking next track source " + (t.isEnabled()?"enabled":"disabled"));
		} else {
			if (logDebugEnabled) log.debug("next track source is null");
		}
		while (t != null && !t.isEnabled())
		{
			t = t.getNextTrackSource();
			if (t != null)
			{
				if (logDebugEnabled) log.debug("checking next track source " + (t.isEnabled()?"enabled":"disabled"));
			} else {
				if (logDebugEnabled) log.debug("next track source is null");
			}
		}
		return t;
	}*/

	/**
	 * Get the next track from the next track source in the chain, or do something
	 * appropriate if there is no track source, like screaming or flapping your arms.
	 */
	protected Track delegateGetNextTrack()
	{
		TrackSource ts = getNextTrackSource();
		return ( (ts==null) ? null : ts.getNextTrack() );
	}

	/**
	 * Remove a track from this PipelineElement (or rather don't).
	 */
	public boolean removeTrack(int index)
	{
		// override this to enable removal of tracks
		return false;
	}

	/**
	 * Peek the next source for the specified number of tracks.
	 * 
	 * @param size The number of Tracks to peek
	 * @return A List of Track objects or <code>null</code> if there is no next
	 *         element
	 */
	protected List delegatePeekTracks( int size )
	{
		TrackSourcePipelineElement ts = getNextTrackSource();
		if ( ts != null )
		{
			if (logDebugEnabled) log.debug( "Delegating peek from : " + this.getClass().getName()+ " -> " + ts.getClass().getName() );
			return ( (ts==null) ? null : ts.peekTracks( size ) );
		}
		else
		{
			return new LinkedList();
		}
	}
	
	/**
	 * Persist the current state of the PipelineElement into the database
	 *
	 * @param conn The database connection to use, which must have AutoCommit disabled
	 * @return success
	 */
	public final boolean storeState(Connection conn)
	{
		// get the config map from the subclass
		return this.pipeline.storePipelineElementState( conn, this , this.getState() );
	}
	
	// Force the subclass to implement methods that persist the state of the 
	// PipelineElement at the current time.

	/**
	 * Get the current state of this PipelineElement for persisting
	 *
	 * @return a String keyed Map of objects representing the state of 
	 * this PipelineElement, e.g. for a Playlist this would be information
	 * allowing the reconstruction of the current playlist queue.
	 */
	public abstract Map getState();

	/**
	 * Load the configuration of this PipelineElement
	 *
	 * @param state a Map of values keyed by Strings representing the state of this PipelineElement.
	 * @return success
	 */
	public abstract boolean setState( Map state );

	/** 
	 * Get the name of this PipelineElement
	 *
	 * @return The name
	 */
	public final String getName()
	{
		return name;
	}

	/** 
	 * Set the owner of this PipelineElement
	 *
	 * @param name The new name for this PipelineElement
	 */
	public void setName(String name)
	{
		this.name = name;
	}

	/** 
	 * Get the owner of this PipelineElement
	 *
	 * @return The TrackSourcePipeline
	 */
	public TrackSourcePipeline getOwner()
	{
		return pipeline;
	}

	/** 
	 * Set the owner of this PipelineElement
	 *
	 * @param pipe The TrackSourcePipeline that owns this PipelineElement
	 * @return This PipelineElement for convenience
	 */
	public TrackSourcePipelineElement setOwner( TrackSourcePipeline pipe )
	{
		this.pipeline = pipe;
		return this;
	}

	public void enable()
	{
		enabled = true;
	}

	public void disable()
	{
		enabled = false;
	}

	public final boolean isEnabled()
	{
		return enabled;
	}

	/**
	 * Not much point cloning this
	 * Clone operations should not copy the nextTrackSource or pipeline fields
	 */
	public abstract Object clone();
}
