package tim.prune.data;

import java.io.File;

/**
 * Class to represent a general media object for correlation.
 * Subclasses are currently Photo and AudioClip
 */
public abstract class MediaObject
{
	/** File where media is stored (if any) */
	protected final File _file;
	/** Name of file */
	protected final String _name;
	/** Cached data if downloaded */
	protected final byte[] _data;
	/** URL if media came from net */
	protected String _url = null;
	/** Timestamp, if any */
	protected Timestamp _timestamp = null;
	/** Associated DataPoint if correlated */
	protected DataPoint _dataPoint = null;
	/** Status when loaded */
	private Status _originalStatus = Status.NOT_CONNECTED;
	/** Current status */
	private Status _currentStatus = Status.NOT_CONNECTED;

	/** Connection status */
	public enum Status
	{
		/** Media is not connected to any point */
		NOT_CONNECTED,
		/** Media has been connected to a point since it was loaded */
		TAGGED,
		/** Media is connected to a point */
		CONNECTED
	}


	/**
	 * Constructor
	 * @param inFile file object
	 * @param inStamp timestamp object
	 */
	public MediaObject(File inFile, Timestamp inStamp)
	{
		_file = inFile;
		_name = inFile.getName();
		_data = null;
		_timestamp = inStamp;
	}

	/**
	 * Constructor for byte arrays
	 * @param inData byte array containing data
	 * @param inName name of object
	 * @param inUrl source url of object or null
	 */
	public MediaObject(byte[] inData, String inName, String inUrl)
	{
		_file = null;
		_data = inData;
		_name = inName;
		_url = inUrl;
		_timestamp = null;
	}

	/**
	 * @return the file object
	 */
	public File getFile() {
		return _file;
	}

	/** @return media name */
	public String getName() {
		return _name;
	}

	/**
	 * @return the timestamp object
	 */
	public Timestamp getTimestamp() {
		return _timestamp;
	}

	/**
	 * @param inTimestamp Timestamp object
	 */
	public void setTimestamp(Timestamp inTimestamp) {
		_timestamp = inTimestamp;
	}

	/**
	 * @return byte data of media
	 */
	public byte[] getByteData() {
		return _data;
	}

	/**
	 * @return source Url (or null)
	 */
	public String getUrl() {
		return _url;
	}

	/**
	 * @return the full path to the media, either filename or url
	 */
	public String getFullPath()
	{
		if (_file != null) return _file.getAbsolutePath();
		return getUrl();
	}

	/**
	 * @return true if details are valid (might not have timestamp)
	 */
	public boolean isValid()
	{
		return ((_file != null && _file.exists() && _file.canRead())
			|| (_data != null && _data.length > 0));
	}

	/**
	 * @return true if file has timestamp
	 */
	public boolean hasTimestamp() {
		return _timestamp != null && _timestamp.isValid();
	}

	/**
	 * Check if this object refers to the same object as another
	 * @param inOther other MediaObject
	 * @return true if the objects are the same
	 */
	public boolean equals(MediaObject inOther)
	{
		if (_file != null)
		{
			// compare file objects
			return (inOther != null && inOther.getFile() != null && getFile() != null
				&& inOther.getFile().equals(getFile()));
		}
		// compare data arrays
		return (inOther != null && _name != null && inOther._name != null && _name.equals(inOther._name)
			&& _data != null && inOther._data != null && _data.length == inOther._data.length);
	}

	/** For completeness, also compare with an Object */
	public boolean equals(Object inOther)
	{
		MediaObject other = (inOther instanceof MediaObject ? (MediaObject) inOther : null);
		return equals(other);
	}

	/**
	 * Set the data point associated with the photo
	 * @param inPoint DataPoint with coordinates etc
	 */
	public void setDataPoint(DataPoint inPoint)
	{
		_dataPoint = inPoint;
		// set status according to point
		if (inPoint == null) {
			setCurrentStatus(Status.NOT_CONNECTED);
		}
		else {
			setCurrentStatus(Status.CONNECTED);
		}
	}

	/**
	 * @return the DataPoint object
	 */
	public DataPoint getDataPoint() {
		return _dataPoint;
	}

	/**
	 * @param inStatus status of file when loaded
	 */
	public void setOriginalStatus(Status inStatus)
	{
		_originalStatus = inStatus;
		_currentStatus = inStatus;
	}

	/**
	 * @return status of file when it was loaded
	 */
	public Status getOriginalStatus()
	{
		return _originalStatus;
	}

	/**
	 * @return current status
	 */
	public Status getCurrentStatus()
	{
		return _currentStatus;
	}
	/**
	 * @param inStatus current status
	 */
	public void setCurrentStatus(Status inStatus)
	{
		_currentStatus = inStatus;
	}

	/**
	 * @return true if this object is connected to a point
	 */
	public boolean isConnected()
	{
		return _currentStatus != Status.NOT_CONNECTED;
	}

	/**
	 * @return true if status has changed since load
	 */
	public boolean isModified()
	{
		return _currentStatus != _originalStatus;
	}
}
