/**
 *
 * Copyright 2004 Hiram Chirino
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 **/
package org.codehaus.activemq.ra;

import javax.resource.ResourceException;
import javax.resource.spi.ActivationSpec;
import javax.resource.spi.InvalidPropertyException;
import javax.resource.spi.ResourceAdapter;
import javax.jms.Queue;
import javax.jms.Topic;
import javax.jms.Session;
import java.util.List;
import java.util.ArrayList;
import java.beans.PropertyDescriptor;
import java.beans.IntrospectionException;

/**
 * @version $Revision: 1.6 $ $Date: 2004/12/01 03:03:11 $
 */
public class ActiveMQActivationSpec implements ActivationSpec {

    /** Auto-acknowledge constant for <code>acknowledgeMode</code> property **/
    public static final String AUTO_ACKNOWLEDGE_MODE = "Auto-acknowledge";
    /** Auto-acknowledge constant for <code>acknowledgeMode</code> property * */
    public static final String AUTO_ACKNOWLEDGE_MODE_JBOSS = "AUTO_ACKNOWELDGE";
    /** Dups-ok-acknowledge constant for <code>acknowledgeMode</code> property * */
    public static final String DUPS_OK_ACKNOWLEDGE_MODE = "Dups-ok-acknowledge";
    
    /** Durable constant for <code>subscriptionDurability</code> property * */
    public static final String DURABLE_SUBSCRIPTION = "Durable";
    /** NonDurable constant for <code>subscriptionDurability</code> property * */
    public static final String NON_DURABLE_SUBSCRIPTION = "NonDurable";
    
    private ActiveMQResourceAdapter resourceAdapter;
    private String destinationType;
    private String messageSelector;
    boolean noLocal = false; //not part of spec
    private String destination;
    private String acknowledgeMode = AUTO_ACKNOWLEDGE_MODE;
    private String userName;
    private String password;
    private String clientId;
    private String subscriptionName;
    private String subscriptionDurability = NON_DURABLE_SUBSCRIPTION;
    public static final int INVALID_ACKNOWLEDGE_MODE = -1;


    /**
     * @see javax.resource.spi.ActivationSpec#validate()
     */
    public void validate() throws InvalidPropertyException {
        List propsNotSet = new ArrayList();
        try {
            if (destination == null || destination.equals(""))
                propsNotSet.add(new PropertyDescriptor("destination", ActiveMQActivationSpec.class));
            if (!isValidDestinationType())
                propsNotSet.add(new PropertyDescriptor("destinationType", ActiveMQActivationSpec.class));
            if (!isValidAcknowledgeMode())
                propsNotSet.add(new PropertyDescriptor("acknowledgeMode", ActiveMQActivationSpec.class));
            if (!isValidSubscriptionDurability())
                propsNotSet.add(new PropertyDescriptor("subscriptionDurability", ActiveMQActivationSpec.class));
            if (!isValidClientId())
                propsNotSet.add(new PropertyDescriptor("clientId", ActiveMQActivationSpec.class));
            if (!isValidSubscriptionName())
                propsNotSet.add(new PropertyDescriptor("subscriptionName", ActiveMQActivationSpec.class));
        } catch (IntrospectionException e) {
            e.printStackTrace();
        }
        
        if (propsNotSet.size() > 0) {
            InvalidPropertyException e = new InvalidPropertyException("Invalid settings.");
            final PropertyDescriptor[] descriptors = (PropertyDescriptor[]) propsNotSet.toArray(new PropertyDescriptor[propsNotSet.size()]);
            e.setInvalidPropertyDescriptors(descriptors);
            throw e;
        }
    }

    /**
     * @see javax.resource.spi.ResourceAdapterAssociation#getResourceAdapter()
     */
    public ResourceAdapter getResourceAdapter() {
        return resourceAdapter;
    }

    /**
     * @see javax.resource.spi.ResourceAdapterAssociation#setResourceAdapter(javax.resource.spi.ResourceAdapter)
     */
    public void setResourceAdapter(ResourceAdapter resourceAdapter) throws ResourceException {
        //spec section 5.3.3
        if (this.resourceAdapter != null) {
            throw new ResourceException("ResourceAdapter already set");
        }
        if (!(resourceAdapter instanceof ActiveMQResourceAdapter)) {
            throw new ResourceException("ResourceAdapter is not of type: " + ActiveMQResourceAdapter.class.getName());
        }
        this.resourceAdapter = (ActiveMQResourceAdapter) resourceAdapter;
    }


    /////////////////////////////////////////////////////////////////////////
    //
    // Java Bean getters and setters for this ActivationSpec class.
    //
    /////////////////////////////////////////////////////////////////////////
    /**
     * @return Returns the destinationType.
     */
    public String getDestinationType() {
        return destinationType;
    }

    /**
     * @param destinationType The destinationType to set.
     */
    public void setDestinationType(String destinationType) {
        this.destinationType = destinationType;
    }
    
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    
    /**
     * @return Returns the messageSelector.
     */
    public String getMessageSelector() {
        return messageSelector;
    }

    /**
     * @param messageSelector The messageSelector to set.
     */
    public void setMessageSelector(String messageSelector) {
        this.messageSelector = messageSelector;
    }

    /**
     * @return Returns the noLocal.
     */
    public boolean getNoLocal() {
        return noLocal;
    }

    /**
     * @param noLocal The noLocal to set.
     */
    public void setNoLocal(boolean noLocal) {
        this.noLocal = noLocal;
    }

    public String getAcknowledgeMode() {
        return acknowledgeMode;
    }

    public void setAcknowledgeMode(String acknowledgeMode) {
        this.acknowledgeMode = acknowledgeMode;
        //Work around for a JBoss bug
        if (AUTO_ACKNOWLEDGE_MODE_JBOSS.equals(acknowledgeMode))
            this.acknowledgeMode = AUTO_ACKNOWLEDGE_MODE;
    }
    
    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {        
        if (!isEmpty(clientId)) {
            this.clientId = clientId;            
        }        
    }

    public String getDestination() {
        return destination;
    }

    public void setDestination(String destination) {
        this.destination = destination;
    }

    public String getSubscriptionDurability() {
        return subscriptionDurability;
    }

    public void setSubscriptionDurability(String subscriptionDurability) {
        this.subscriptionDurability = subscriptionDurability;
    }

    public String getSubscriptionName() {
        return subscriptionName;
    }

    public void setSubscriptionName(String subscriptionName) {
        if (!isEmpty(subscriptionName)) {
            this.subscriptionName = subscriptionName;
        }                
    }
    
    private boolean isValidSubscriptionName() {
        return !isDurableSubscription() ? true : subscriptionName != null && subscriptionName.trim().length() > 0;
    }

    private boolean isValidClientId() {
        return !isDurableSubscription() ? true : clientId != null && clientId.trim().length() > 0;
    }

    public boolean isDurableSubscription() {
        return DURABLE_SUBSCRIPTION.equals(subscriptionDurability);
    }

    private boolean isValidSubscriptionDurability() {
        if (NON_DURABLE_SUBSCRIPTION.equals(subscriptionDurability) || DURABLE_SUBSCRIPTION.equals(subscriptionDurability))
            return true;
        return false;
    }

    private boolean isValidAcknowledgeMode() {
        if (AUTO_ACKNOWLEDGE_MODE.equals(acknowledgeMode) || DUPS_OK_ACKNOWLEDGE_MODE.equals(acknowledgeMode))
            return true;
        return false;
    }

    private boolean isValidDestinationType() {
        if (Queue.class.getName().equals(destinationType) || Topic.class.getName().equals(destinationType))
            return true;
        return false;
    }

     
    private boolean isEmpty(String value) {
        return value == null || "".equals(value.trim());
    }

   public String toString() {
        return "ActiveMQActivationSpec{" +
                "acknowledgeMode='" + acknowledgeMode + "'" +
                ", destinationType='" + destinationType + "'" +
                ", messageSelector='" + messageSelector + "'" +
                ", destination='" + destination + "'" +
                ", clientId='" + clientId + "'" +
                ", subscriptionName='" + subscriptionName + "'" +
                ", subscriptionDurability='" + subscriptionDurability + "'" +
                "}";
    }

    public String getSubscriptionId() {
        String subscriptionId = null;
        if (!isEmpty(subscriptionName) && !isEmpty(clientId)) {
            subscriptionId = clientId + "-" + subscriptionName;
        }
        return subscriptionId;
    }

    public int getAcknowledgeModeForSession() { 
        int retVal = INVALID_ACKNOWLEDGE_MODE;
        if (isValidAcknowledgeMode()) {
            retVal = AUTO_ACKNOWLEDGE_MODE.equals(acknowledgeMode) ? Session.AUTO_ACKNOWLEDGE : Session.DUPS_OK_ACKNOWLEDGE;
        }
        return retVal;
    }    
}