

package gov.va.med.cds.template;


import gov.va.med.cds.clinicaldata.TemplateMetaDataInterface;
import gov.va.med.cds.exception.ErrorCodeEnum;
import gov.va.med.cds.exception.InitializationException;
import gov.va.med.cds.util.LRUHashMap;
import gov.va.med.cds.xml.schema.SchemaHelper;
import gov.va.med.cds.xml.schema.SchemaHelperInterface;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;
import java.sql.Blob;
import java.util.Calendar;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;


public class TemplateCache
    implements
        TemplateCacheInterface
{
    private static final Log logger = LogFactory.getLog( TemplateCache.class );
    private final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    private final Lock readLock = reentrantReadWriteLock.readLock();
    private final Lock writeLock = reentrantReadWriteLock.writeLock();
    private LRUHashMap<String, TemplateCacheModelInterface> templateCacheModelMap = null;


    public TemplateCache( LRUHashMap<String, TemplateCacheModelInterface> aMap )
    {
        templateCacheModelMap = aMap;
    }


    /*
     * (non-Javadoc)
     * 
     * @see gov.va.med.cds.template.TemplateCacheInterface#loadSchemaIntoCache(org.springframework.core.io.Resource)
     */
    public void loadSchemaIntoCache( TemplateMetaDataInterface aTemplateMetaData )
        throws IOException
    {
        TemplateCacheModelInterface templateCacheModel = null;
        SchemaHelper schemaHelper;

        try
        {
            if ( logger.isDebugEnabled() )
            {
                logger.debug( "loading schema " + aTemplateMetaData.getTemplateName() );
            }
            Blob schemaJar = new javax.sql.rowset.serial.SerialBlob( aTemplateMetaData.getTemplateJar() );
            schemaHelper = getSchemaHelper( aTemplateMetaData, schemaJar );
            if ( logger.isDebugEnabled() )
            {
                logger.debug( "loaded schema " + aTemplateMetaData.getTemplateName() );
            }
        }
        catch ( Exception e )
        {
           throw new InitializationException( ErrorCodeEnum.UNABLE_TO_LOAD_SCHEMAS_INTO_CACHE, e, aTemplateMetaData.getTemplateName(), e.getMessage() );
        }

        String templateId = aTemplateMetaData.getTemplateId();

        if ( !templateCacheModelMap.containsKey( templateId ) )
        {
        	writeLock.lock();
        
	        try
	        {
		        if ( !templateCacheModelMap.containsKey( templateId ) )
		        {
	                templateCacheModel = new TemplateCacheModelData();
	                templateCacheModel.setTemplateMetaData( aTemplateMetaData );
	                templateCacheModel.setSchemaHelper( schemaHelper );
	                templateCacheModel.setLoadedIntoCache( Calendar.getInstance().getTimeInMillis() );
	                templateCacheModelMap.put( templateId, templateCacheModel );
		        }
		        else
		        {
		            //if ( logger.isInfoEnabled() )
		            //{
		              //  logger.info( "The template ID='" + templateId + "' already exists. The template registry will not add another one." );
		            //}
		            
		            if(logger.isInfoEnabled())
		            {
		                String msg = "The template ID='" + templateId + "' already exists. The template registry will not add another one.";

		                  logger.info( gov.va.med.cds.util.LogMessageUtil.buildMessage( null, null, null, msg ),null );
		            }
		        }
		        
	        }
	        finally
	        {
	            writeLock.unlock();
	        }
        
        }
        
    }


    /*
     * (non-Javadoc)
     * 
     * @see gov.va.med.cds.template.TemplateCacheInterface#getAllSchemaHelpers()
     */
    public TemplateCacheModelInterface getTemplateCacheModel( String aTemplateId )
    {
        TemplateCacheModelInterface templateCacheModel = null;

        try
        {
            readLock.lock();
            templateCacheModel = templateCacheModelMap.get( aTemplateId );
        }
        finally
        {
            readLock.unlock();
        }

        return templateCacheModel;
    }


    /*
     * (non-Javadoc)
     * 
     * @see gov.va.med.cds.template.TemplateCacheInterface#getAllSchemaHelpers()
     */
    public Collection<TemplateCacheModelInterface> getAllTemplateCacheModels( )
    {
        Collection<TemplateCacheModelInterface> allTemplateCacheModels = null;

        try
        {
            readLock.lock();
            allTemplateCacheModels = templateCacheModelMap.values();
        }
        finally
        {
            readLock.unlock();
        }

        return allTemplateCacheModels;
    }


    public TemplateMetaDataInterface getTemplateMetaData( String aTemplateId )
    {
        TemplateMetaDataInterface templateMetaData = null;
        TemplateCacheModelInterface templateCacheModel = getTemplateCacheModel( aTemplateId );
        if ( templateCacheModel != null )
        {
            templateMetaData = templateCacheModel.getTemplateMetaData();
        }

        return templateMetaData;
    }


    /*
     * (non-Javadoc)
     * 
     * @see gov.va.med.cds.template.TemplateCacheInterface#getSchemaHelper(java.lang.String)
     */
    public SchemaHelperInterface getSchemaHelper( String aTemplateId )
    {
        SchemaHelperInterface schemaHelper = null;
        TemplateCacheModelInterface templateCacheModel = getTemplateCacheModel( aTemplateId );
        if ( templateCacheModel != null )
        {
            schemaHelper = templateCacheModel.getSchemaHelper();
        }

        return schemaHelper;
    }


    /*
     * (non-Javadoc)
     * 
     * @see gov.va.med.cds.template.TemplateCacheInterface#isEmpty()
     */
    public boolean isEmpty( )
    {
        boolean isEmpty = true;

        try
        {
            readLock.lock();
            isEmpty = templateCacheModelMap.isEmpty();
        }
        finally
        {
            readLock.unlock();
        }

        return isEmpty;
    }


    /*
     * (non-Javadoc)
     * 
     * @see gov.va.med.cds.template.TemplateCacheInterface#clear()
     */
    public void clear( )
    {
        try
        {
            writeLock.lock();
            templateCacheModelMap.clear();
        }
        finally
        {
            writeLock.unlock();
        }
    }


    public void reSize( int newSize )
    {
        try
        {
            writeLock.lock();
            templateCacheModelMap.reSize( newSize );
        }
        finally
        {
            writeLock.unlock();
        }
    }


    /**
     * Gets the no. of schemas contained in template cache
     * 
     * @return number of templates
     */
    public int getNumberOfTemplatesLoadedIntoTemplateCache( )
    {
        return templateCacheModelMap.size();
    }


    /**
     * Gets the size of template cache threshold.
     * 
     * @return templateCacheThreshold value
     */
    public int getTemplateCacheThreshold( )
    {
        return templateCacheModelMap.getMapThreshold();
    }


    /**
     * gets available list of templateIds in template cache
     * 
     * @return Set of templateIds
     */
    public Set<String> getTemplateCacheTemplateIds( )
    {
        return templateCacheModelMap.keySet();
    }

    SchemaHelper getSchemaHelper( TemplateMetaDataInterface aTemplateMetaData, Blob schemaJar )
    {
        return new SchemaHelper( schemaJar, aTemplateMetaData.getTemplateName() );
    }
}
