/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
// Package
package gov.va.med.fw.report.jasperreport;

// Java classes
import java.util.Set;
import java.util.Iterator;
import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.util.Map;

// Library classes
import org.springframework.core.io.ClassPathResource;
import org.apache.commons.lang.Validate;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.xml.JRXmlLoader;
import net.sf.jasperreports.engine.util.JRLoader;

// Framework classes
import gov.va.med.fw.report.AbstractReportTemplate;
import gov.va.med.fw.report.InvalidTemplateException;

/**
 * A jasper template in XML format.  A report template
 * is loaded and compiled into a jasper design object
 * that is ready for data population. 
 *
 * Project: Framework</br>
 * Created on: 9:49:52 AM </br>
 *
 * @author DNS   LEV
 */
public class JasperReportTemplate extends AbstractReportTemplate {

	private static final String REPORT_TEMPLATE_EXTENTION = ".jrxml";
	
	private static final String COMPILED_REPORT_EXTENTION = ".jasper";

	/**
	 * An instance of serialVersionUID
	 */
	private static final long serialVersionUID = 2415040386874612549L;

	/**
	 * A default constructor
	 */
	public JasperReportTemplate() {
		super();
	}
	
	/**
	 * @see gov.va.med.fw.report.AbstractReportTemplate#compileTemplates(java.util.Map)
	 */
	protected void compileTemplates( Map templates ) throws InvalidTemplateException {
		
		Set entries = templates.entrySet();
		for( Iterator i=entries.iterator(); i.hasNext(); ) {
			Map.Entry entry = (Map.Entry)i.next();
			Object key = entry.getKey();
			Object value = entry.getValue();
			String tplName = (value != null && value instanceof String) ? (String)value : null;
			this.getTemplateCache().cacheItem( key, this.loadJasperReportTemplate( tplName ) );
		}
	}
	
	/** Precompile a jasper report template 
	 * @return A precompiled jasper report 
	 * @throws InvalidTemplateException Thrown in case of errors compiling a report
	 */
	protected JasperReport loadJasperReportTemplate( String name ) throws InvalidTemplateException {
		
		JasperReport template = null; 
		InputStream inStream = null;
		try {
			// Validate a report template name first
			// Only accept *.jrxml or *.jasper
			this.validateTemplateName( name );
			
			// If a report template name is *.jrxml, compiles it into *.jasper = JasperReport
			inStream = getTemplateStream( name );
			if( name.endsWith( REPORT_TEMPLATE_EXTENTION ) ) {
				// Load a report template in XML format into memory
				JasperDesign design = JRXmlLoader.load( inStream );
				template = JasperCompileManager.compileReport( design );
			}
			else {
				Object compiled = JRLoader.loadObject( inStream );
				template = compiled instanceof JasperReport ? (JasperReport)compiled : null;
			}
		}
		catch( JRException e ) {
			throw new InvalidTemplateException( "Failed to compile a report template [" + name + "]", e );
		} finally {
			if (inStream != null) {
				org.apache.commons.io.IOUtils.closeQuietly(inStream);
			}
		}
		return template;
	}
	
	/** Gets an buffered input stream to a report template file
	 * 
	 * @param name A report template file name
	 * @return An input stream
	 * @throws InvalidTemplateException Thrown in case of errors accessing a file
	 */
	protected InputStream getTemplateStream( String name ) throws InvalidTemplateException {
		
		InputStream stream = null;
		
		try {
			ClassPathResource resource = new ClassPathResource( name );
			stream = new BufferedInputStream( resource.getInputStream() );
		}
		catch( IOException e ) {
			throw new InvalidTemplateException( "Template file not found ", e );
		}
		catch( SecurityException e ) {
			throw new InvalidTemplateException( "Access not granted to a template file ", e );
		}
		return stream;
	}
	
	protected void validateTemplateName( String name ) {
		
		// Validate for a report template name
		Validate.notNull( name, "A template name must not be NULL" );
		Validate.isTrue( (name.endsWith( REPORT_TEMPLATE_EXTENTION ) || 
				 				name.endsWith( COMPILED_REPORT_EXTENTION )), 
				 				"Invalid report template file" );
	}
}