/*
 * Copyright 2004,2005 The Apache Software Foundation.
 *
 * 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.apache.rampart;

import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * This is a basic implementation of UniqueMessageAttributeCache. In this implementation we will cache incomming
 * nonce value for a period of time. The life time can be defined in the services.xml. If not defined
 * the default value will be 5 minutes.
 */
public class NonceCache extends AbstractUniqueMessageAttributeCache {

    class Nonce
    {
        String nonceValue;
        String userName;

        public Nonce(String nonce, String user)
        {
            this.nonceValue = nonce;
            this.userName = user;
        }

        @Override
        public boolean equals(Object another)
        {
        	if (another == null){
        		return false;
        	} 
        	
        	if (another == this) {
        		return true;
        	}
        	
        	if (!(another instanceof Nonce)){
        		return false;
        	} 
        	
        	
            Nonce otherNonce = (Nonce)another;
            if (this.userName.equals(otherNonce.userName) && this.nonceValue.equals(otherNonce.nonceValue))
            {
                return true;
            }
            return false;
        }

        @Override
        public int hashCode()
        {
            return (this.userName.hashCode() * 13 +  this.nonceValue.hashCode() * 7);
        }
    }

    private Map<Nonce, Calendar> mapIdNonce = new HashMap<Nonce, Calendar>();

    private final ReentrantLock lock = new ReentrantLock();

    public NonceCache()
    {
        super();
    }
    
    public NonceCache(int maxLifeTime)
    {
        super(maxLifeTime);
    }

    public void addToCache(String id, String userName) {

        Nonce nonce = new Nonce(id, userName);
        Calendar rightNow = Calendar.getInstance();

        lock.lock();
        try {
            mapIdNonce.put(nonce, rightNow);
        } finally {
            lock.unlock();
        }

    }

    public boolean valueExistsInCache(String id, String userName) {

        lock.lock();

        try {
            clearStaleNonceIds();
        } finally {
            lock.unlock();
        }
        
        Nonce nonce = new Nonce(id, userName);
        return mapIdNonce.containsKey(nonce);
    }

    public void clearCache() {

        lock.lock();
        try {
            mapIdNonce.clear();
        } finally {
            lock.unlock();
        }
    }

    /**
     * This method will clear stale nonce ids from the map.
     */
    private void clearStaleNonceIds()
    {
        Calendar rightNow = Calendar.getInstance();

        int maxLifeTime = getMaximumLifeTimeOfAnAttribute();

        rightNow.add(Calendar.SECOND, -(maxLifeTime));
        long timeBeforeMaxLifeTime = rightNow.getTimeInMillis();
        
        Iterator<Map.Entry<Nonce, Calendar>> iterator = mapIdNonce.entrySet().iterator();

        while (iterator.hasNext()) {

            Map.Entry<Nonce, Calendar> pair = iterator.next();
            Calendar itemDate = pair.getValue();

            long itemAddedTime = itemDate.getTimeInMillis();

            if (timeBeforeMaxLifeTime > itemAddedTime)
            {
                iterator.remove();
            }
        }


    }
}
