package jasync;

import java.io.Serializable;

/**
 * A class to represent messages.
 */
public class Message implements Serializable {
    /**
     * This value is always used as the ID number of asynchronous messages.
     */
    public static final int ASYNC_ID = -1;

    /**
     * ID number of the message
     */
    private int uniqueID;

    /**
     * Message type
     * @see MessageType
     */
    private MessageType type;

    /**
     * Synchronous or asynchronous
     * @see MessageSync
     */
    private MessageSync sync;

    /**
     * Error code.
     * @see MessageStatus
     */
    private MessageStatus status;

    /**
     * Command
     * @see MessageCommand
     */
    private MessageCommand command;

    /**
     * Data payload. Can be anything that's serializable.
     */
    private Object[] data;

    /**
     * Flag for whether or not data is present, so null can be used as data
     * if necessary.
     */
    private boolean dataPresent;

    /**
     * Constructor with no payload.
     * @param uniqueID ID number for the message
     * @param type Type of message
     * @param sync synchronous or asynchronous
     * @param status error code
     * @param command command
     * @see MessageType
     * @see MessageSync
     * @see MessageStatus
     * @see MessageCommand
     */
    public Message (int uniqueID, MessageType type, MessageSync sync,
		    MessageStatus status, MessageCommand command) {
	this.uniqueID = uniqueID;
	this.type = type;
	this.sync = sync;
	this.status = status;
	this.command = command;
	this.data = null;
	this.dataPresent = false;
    }

    /**
     * Constructor with payload.
     * @param uniqueID ID number for the message
     * @param type Type of message
     * @param sync synchronous or asynchronous
     * @param status error code
     * @param command command
     * @param data Payload. Must be serializable.
     * @see MessageType
     * @see MessageSync
     * @see MessageStatus
     * @see MessageCommand
     */
    public Message (int uniqueID, MessageType type, MessageSync sync,
		    MessageStatus status, MessageCommand command,
		    Object... data) {
	this.uniqueID = uniqueID;
	this.type = type;
	this.sync = sync;
	this.status = status;
	this.command = command;
	this.data = data;
	this.dataPresent = true;
    }

    /**
     * Copy constructor.
     * @param in Original.
     */
    public Message (Message in) {
	this.uniqueID = in.uniqueID;
	this.type = in.type;
	this.sync = in.sync;
	this.status = in.status;
	this.command = in.command;
	this.data = in.data;
	this.dataPresent = in.dataPresent;
    }

    /**
     * Returns the ID number of this message.
     * @return ID number, ASYNC_ID = -1 if it's asynchronous
     */
    public int getUniqueID () {
	return uniqueID;
    }
    
    /**
     * Returns the type.
     * @return type
     * @see MessageType
     */
    public MessageType getType () {
	return type;
    }
    
    /**
     * Returns SYNC or ASYNC.
     * @return SYNC or ASYNC
     * @see MessageSync
     */
    public MessageSync getSync () {
	return sync;
    }
    
    /**
     * Returns the message status.
     * @return MessageStatus of this message.
     * @see MessageStatus
     */
    public MessageStatus getStatus () {
	return status;
    }
    
    /**
     * Returns the message command.
     * @return command of this message.
     * @see MessageCommand
     */
    public MessageCommand getCommand () {
	return command;
    }

    /**
     * Returns whether or not there is payload.
     * @return true if there is payload.
     */
    public boolean isDataPresent () {
	return dataPresent;
    }

    /**
     * Returns the payload.
     * @return payload of this message.
     * @throws java.lang.NullPointerException if data is not present. Note that
     * it is valid to return null as the payload.
     */
    public Object[] getData () {
	if (dataPresent = true) {
	    return data;
	}
	else {
	    throw new java.lang.NullPointerException("This message may not" +
						     "contain data.");
	}
    }

    /**
     * Returns a string representation of the message in the format
     * "uniqueID:type:sync:status:command:data".
     * @return String representation of this message..
     */
    public String toString () {
	return Integer.toString(uniqueID) + ":" + type + ":" + sync + ":" +
	    status + ":" + command + ":" + data;
    }
}

