package org.mockejb.jms;

import javax.jms.*;

/**
 * Sends message to destination.
 *  
 * @author Dimitar Gospodinov
  */
class MockProducer  implements MessageProducer {

    private MockDestination destination;
    private int deliveryMode = DeliveryMode.PERSISTENT;
    private int priority = 4;
    private long timeToLive = 0;
    private static int messageId = 1;

    /**
     * Creates producer for the specified destination.
     * @param destination
     */
    MockProducer(MockDestination destination) {
        this.destination = destination;
    }

    /**
     * Sends message.
     * @param msg
     */
    public void send(Message msg) throws JMSException {
        send(msg, getDeliveryMode(), getPriority(), getTimeToLive());
    }

    /**
     * Sends message with specified delivery mode, priority and time to live.
     * @param msg
     * @param deliveryMode
     * @param priority
     * @param timeToLive
     */
    public void send(
        Message msg,
        int deliveryMode,
        int priority,
        long timeToLive)
        throws JMSException {

        checkDestination(false);
        MockProducer.sendMessage(
            (MockDestination) getDestination(),
            msg,
            deliveryMode,
            priority,
            timeToLive);
    }

    /**
     * Generates unique number used to create message Id.
     * @return message Id
     */
    protected static synchronized int getMessageId() {
        return messageId++;
    }

    /**
     * Sends <code>msg</code> to <code>destination</code> using specified
     * delivery mode, priority and time to live.
     * @param destination
     * @param msg
     * @param deliveryMode
     * @param priority
     * @param timeToLive
     * @throws JMSException
     */
    protected static void sendMessage(
        MockDestination destination,
        Message msg,
        int deliveryMode,
        int priority,
        long timeToLive)
        throws JMSException {

        msg.setJMSMessageID("ID:MockMessage " + MockProducer.getMessageId());
        msg.setJMSDestination(destination);
        msg.setJMSDeliveryMode(deliveryMode);
        msg.setJMSPriority(priority);
        msg.setJMSTimestamp(System.currentTimeMillis());
        if (timeToLive == 0) {
            msg.setJMSExpiration(0);
        } else {
            msg.setJMSExpiration(msg.getJMSTimestamp() + timeToLive);
        }
        destination.addMessage(msg);
    }

    /**
     * Sends message to destination.
     */
    public void send(Destination destination, Message msg)
        throws JMSException {
        send(
            destination,
            msg,
            getDeliveryMode(),
            getPriority(),
            getTimeToLive());
    }

    /**
     * Sends message to destination, with specified delivery mode,
     * priority and time to live.
     */
    public void send(
        Destination destination,
        Message msg,
        int deliveryMode,
        int priority,
        long timeToLive)
        throws JMSException {

        checkDestination(true);
        if (destination instanceof MockDestination) {
            MockProducer.sendMessage(
                (MockDestination) destination,
                msg,
                deliveryMode,
                priority,
                timeToLive);
        }
        throw new InvalidDestinationException("Invalid destination specified!");
    }

    /**
     * Returns destination for this producer.
     */
    public Destination getDestination() throws JMSException {
        return destination;
    }

    /**
     * Does nothing.
     * @see javax.jms.MessageProducer#close()
     */
    public void close() throws JMSException {
        // Does nothing.
    }

    /**
     * Does nothing.
     * @see javax.jms.MessageProducer#setDisableMessageID(boolean)
     */
    public void setDisableMessageID(boolean arg0) throws JMSException {
        // Does nothing.
    }

    /**
     * Always returns <code>false</code>
     * @see javax.jms.MessageProducer#getDisableMessageID()
     */
    public boolean getDisableMessageID() throws JMSException {
        return false;
    }

    /**
     * Does nothing.
     * @see javax.jms.MessageProducer#setDisableMessageTimestamp(boolean)
     */
    public void setDisableMessageTimestamp(boolean arg0) throws JMSException {
        // Does nothing.
    }

    /**
     * Always returns <code>false</code>
     * @see javax.jms.MessageProducer#getDisableMessageTimestamp()
     */
    public boolean getDisableMessageTimestamp() throws JMSException {
        return false;
    }

    /**
     * @see javax.jms.MessageProducer#setDeliveryMode(int)
     */
    public void setDeliveryMode(int deliveryMode) throws JMSException {
        this.deliveryMode = deliveryMode;
    }

    /**
     * @see javax.jms.MessageProducer#getDeliveryMode()
     */
    public int getDeliveryMode() throws JMSException {
        return deliveryMode;
    }

    /**
     * @see javax.jms.MessageProducer#setPriority(int)
     */
    public void setPriority(int priority) throws JMSException {
        this.priority = priority;
    }

    /**
     * @see javax.jms.MessageProducer#getPriority()
     */
    public int getPriority() throws JMSException {
        return priority;
    }

    /**
     * @see javax.jms.MessageProducer#setTimeToLive(long)
     */
    public void setTimeToLive(long timeToLive) throws JMSException {
        this.timeToLive = timeToLive;
    }

    /**
     * @see javax.jms.MessageProducer#getTimeToLive()
     */
    public long getTimeToLive() throws JMSException {
        return timeToLive;
    }

    /**
     * Checks if there is or there is not destination specified for this producer.
     * Method is used in cases when <code>UnsupportedOperationException</code>
     * should be raised by a <code>MessageProducer</code> (for example
     * calling <code>send(Message)</code> when the producer has been created
     * without specifying a destination). 
     * @param unidentifiedDestinationCheck
     * @throws UnsupportedOperationException if unsupported operation is attempted
     */
    protected void checkDestination(boolean unidentifiedDestinationCheck) {
        if (unidentifiedDestinationCheck) {
            if (destination != null) {
                throw new UnsupportedOperationException();
            }
        } else {
            if (destination == null) {
                throw new UnsupportedOperationException();
            }
        }
    }
}