/** 
 * 
 * Copyright 2004 Hiram Chirino
 * Copyright 2004 Protique Ltd
 * 
 * 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.activemq.store.journal;

import java.util.HashMap;
import java.util.Iterator;

import javax.jms.JMSException;

import org.activeio.journal.RecordLocation;
import org.activemq.message.ConsumerInfo;
import org.activemq.service.MessageContainer;
import org.activemq.service.MessageIdentity;
import org.activemq.service.SubscriberEntry;
import org.activemq.store.RecoveryListener;
import org.activemq.store.TopicMessageStore;
import org.activemq.util.Callback;

/**
 * A MessageStore that uses a Journal to store it's messages.
 * 
 * @version $Revision: 1.1 $
 */
public class JournalTopicMessageStore extends JournalMessageStore implements TopicMessageStore {

    private MessageContainer messageContainer;
    private TopicMessageStore longTermStore;
	private HashMap ackedLastAckLocations = new HashMap();
	private RecordLocation nextMark;	
	
    public JournalTopicMessageStore(JournalPersistenceAdapter adapter, TopicMessageStore checkpointStore, String destinationName) {
        super(adapter, checkpointStore, destinationName);
        this.longTermStore = checkpointStore;
    }
    
    public void recoverSubscription(String subscriptionId, MessageIdentity lastDispatchedMessage, RecoveryListener listener) throws JMSException {
        longTermStore.recoverSubscription(subscriptionId, lastDispatchedMessage, listener);
    }

    public SubscriberEntry getSubscriberEntry(ConsumerInfo info) throws JMSException {
        return longTermStore.getSubscriberEntry(info);
    }

    public void setSubscriberEntry(ConsumerInfo info, SubscriberEntry subscriberEntry) throws JMSException {
        longTermStore.setSubscriberEntry(info, subscriberEntry);
    }

    public MessageIdentity getLastestMessageIdentity() throws JMSException {
        return longTermStore.getLastestMessageIdentity();
    }

    public void incrementMessageCount(MessageIdentity messageId) throws JMSException {
        longTermStore.incrementMessageCount(messageId);
    }
    
    public void decrementMessageCountAndMaybeDelete(MessageIdentity messageId) throws JMSException {
        longTermStore.decrementMessageCountAndMaybeDelete(messageId);
    }

    /**
     */
    public void setLastAcknowledgedMessageIdentity(String subscription, MessageIdentity messageIdentity) throws JMSException {

        RecordLocation location = peristenceAdapter.writePacket(destinationName, subscription, messageIdentity, false);        
		synchronized(this) {
		    nextMark = location;
		    ackedLastAckLocations.put(subscription,messageIdentity);
		}
        
    }
    
    public RecordLocation checkpoint() throws JMSException {
        
		RecordLocation rc = super.checkpoint();		
		final HashMap cpAckedLastAckLocations;

		// swap out the hashmaps..
		synchronized(this) {
			if( rc==null || (this.nextMark!=null && rc.compareTo(this.nextMark)<0) ) {
				rc = this.nextMark;
			}					
		    cpAckedLastAckLocations = this.ackedLastAckLocations;
		    this.nextMark=null;
		    this.ackedLastAckLocations = new HashMap();
		}
		
		transactionTemplate.run(new Callback() {
			public void execute() throws Throwable {
				
				// Checkpoint the acked messages.
				Iterator iterator = cpAckedLastAckLocations.keySet().iterator();
				while (iterator.hasNext()) {					
				    String subscription = (String) iterator.next();
				    MessageIdentity identity = (MessageIdentity) cpAckedLastAckLocations.get(subscription);				    
					longTermStore.setLastAcknowledgedMessageIdentity(subscription, identity);
				}				
				
			}

		});
		
		return rc;
    }

    /**
	 * @return Returns the longTermStore.
	 */
	public TopicMessageStore getLongTermTopicMessageStore() {
		return longTermStore;
	}

    public void deleteSubscription(String subscription) throws JMSException {
        longTermStore.deleteSubscription(subscription);
    }
        
}