

package gov.va.med.cds.filter;


import gov.va.med.cds.clinicaldata.FilterMetaData;
import gov.va.med.cds.clinicaldata.FilterMetaDataInterface;
import gov.va.med.cds.exception.ErrorCodeEnum;
import gov.va.med.cds.exceptionframework.ExceptionHandler;
import gov.va.med.cds.tfs.util.FilterMetaDataHelper;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;


public class FilterServiceSimulator
    implements
        FilterServiceInterface
{
    private Map<String, Properties> filterMetaDataMap = new HashMap<String, Properties>();


    private File getFilterXsdFile( String aFilterId )
    {
        File file = null;
        Properties properties = filterMetaDataMap.get( aFilterId );
        if ( null != properties )
        {
            String filePath = properties.getProperty( "file" );
            if ( ( null != filePath ) && ( 0 < filePath.length() ) )
            {
                filePath = filePath.replace( '\\', File.separatorChar );
                file = new File( filePath );
            }
        }

        return file;
    }


    // Returns the contents of the file in a byte array.
    private String getXsdFromFile( File file )
    {
    	InputStream is = null;
        // Create the byte array to hold the data
        byte[] bytes;
        try
        {
            is = new FileInputStream( file );

            // Get the size of the file
            long length = file.length();

            // You cannot create an array using a long type.
            // It needs to be an int type.
            // Before converting to an int type, check
            // to ensure that file is not larger than Integer.MAX_VALUE.
            if ( length > Integer.MAX_VALUE )
            {
                // File is too large
            }

            bytes = new byte[( int )length];

            // Read in the bytes
            int offset = 0;
            int numRead = 0;
            while ( offset < bytes.length && ( numRead = is.read( bytes, offset, bytes.length - offset ) ) >= 0 )
            {
                offset += numRead;
            }

            // Ensure all the bytes have been read in
            if ( offset < bytes.length )
            {
                throw new IOException( "Could not completely read file " + file.getName() );
            }

            // Close the input stream and return bytes
            is.close();
        }
        catch ( IOException e )
        {
            throw new FilterServiceException( ErrorCodeEnum.CANNOT_LOAD_FILTER_SCHEMA_FROM_FILESYSTEM, e,
                            "Couldn't create a File from the filter file path: " + file.getAbsolutePath(), e.getMessage() );
        }
		finally
		{
		    if ( is != null )
		    {
				try 
				{
				    is.close();
				} 
				catch (IOException e) 
				{
				    e.printStackTrace();
				}
				finally
				{
				    is = null;
				}
		    }
		}
        
        return new String( bytes );
    }


    public FilterMetaDataInterface getFilterMetaData( String aFilterId )
    {
        FilterMetaDataInterface metaData = null;
        Properties metaProps = filterMetaDataMap.get( aFilterId );
        if ( null != metaProps )
        {

            //            name=VW_VITAL_Single_Patient_Filter.xsd
            //   *         id=VW_VITAL_SINGLE_PATIENT_FILTER
            //   *         file=filtercache/vhim_4_00/VW_VITAL_Single_Patient_Filter.xsd
            //            requestType=Read
            //            testOnly=false
            //            targetNamespace=Clinicaldata
            //   *         vhimVersion=Vhim_4_00
            //   *         description=Filter
            //   *         entryPoint=[VitalSignObservationEvent]
            metaData = new FilterMetaData();
            metaData.setFilterId( metaProps.getProperty( "id" ) );
            //            metaData.setFilterName( metaProps.getProperty( "name" ) );
            metaData.setVhimVersions( FilterMetaDataHelper.buildVhimVersions( metaProps.getProperty( "vhimVersion" ) ) );
            metaData.setEntryFilters( FilterMetaDataHelper.buildEntryFilters( metaProps.getProperty( "entryPoint" ) ) );
            metaData.setFilterDescription( metaProps.getProperty( "description" ) );
            //            metaData.setTestOnly( metaProps.getProperty( "testOnly", "false" ) );
            metaData.setStatus( "ACTIVE" );

            File xsdFile = getFilterXsdFile( aFilterId );
            String xsd = getXsdFromFile( xsdFile );
            metaData.setFilterSchema( xsd );

        }

        return metaData;
    }


    public Collection<String> getVhimVersions( )
    {
        Collection<String> vhimVersions = new ArrayList<String>();
        for ( Map.Entry<String, Properties> entry : filterMetaDataMap.entrySet() )
        {
            Properties props = entry.getValue();
            String vhimVersion = props.getProperty( "vhimVersion" );
            if ( ( null != vhimVersion ) && ( 0 < vhimVersion.length() ) && ( !vhimVersions.contains( vhimVersion ) ) )
            {
                vhimVersions.add( vhimVersion );
            }
        }

        return vhimVersions;
    }


    public void initialize( )
    {
    }


    /**
     * This method is used to load test filters at startup.
     * 
     * @param testProperties a {@code Properties} object, which at present contains a single property named "path". The
     *            value of "path" is either a directory containing property files with a ".meta" suffix or a single
     *            property file. The property files contain the following properties which describe a filter:
     *            <ul>
     *            <li>file - the path to the xsd file of the filter</li>
     *            <li>id - the filter id</li>
     *            <li>name - the filter name</li>
     *            <li>domain - the filter domain</li>
     *            <li>description - the filter's description</li>
     *            <li>vhimVersion - the filter's version</li>
     *            <li>requestType - the operation for the filter</li>
     *            <li>entryPoint - the filter's entry point</li>
     *            <li>targetNamespace - the filter's target namespace</li>
     *            </ul>
     * 
     */
    public synchronized void setTestFilters( Properties testProperties )
        throws IOException
    {
        try
        {
            String path = testProperties.getProperty( "path", "." );
            boolean loadTestFilters = Boolean.parseBoolean( testProperties.getProperty( "loadTestFilters", "false" ) );

            File dir = new File( path );
            if ( !dir.exists() )
            {
                return;
            }

            if ( dir.isFile() )
            {
                loadFilterMetaDataIntoMap( dir, loadTestFilters );
            }
            else
            {
                File[] files = dir.listFiles( new FileFilter()
                {
                    public boolean accept( File pathname )
                    {
                        return ( pathname.isFile() && pathname.getName().endsWith( ".meta" ) );
                    }
                } );

                for ( int i = 0; i < files.length; i++ )
                {
                    loadFilterMetaDataIntoMap( files[i], loadTestFilters );
                }
            }
        }
        catch ( RuntimeException exception )
        {
            ExceptionHandler.handleException( exception, null, null, null );
        }
    }


    private void loadFilterMetaDataIntoMap( File filterPropFile, boolean loadTestFilters )
        throws IOException
    {
        FileInputStream propInputStream = null;
        try
        {
	        propInputStream = new FileInputStream( filterPropFile );
	        Properties filterProps = new Properties();
	        filterProps.load( propInputStream );
	        propInputStream.close();
	
	        boolean testonly = Boolean.parseBoolean( filterProps.getProperty( "testOnly", "false" ) );
	
	        if ( loadTestFilters || !testonly )
	        {
	            filterMetaDataMap.put( filterProps.getProperty( "id" ), filterProps );
	        }
        }
        finally
        {
            if ( propInputStream != null )
            {
                try 
                {
                    propInputStream.close();
                } 
                catch (IOException e) 
                {
                    e.printStackTrace();
                }
                finally
                {
                    propInputStream = null;
                }
            }
        }
    }


    @Override
    public Collection<String> getActiveFilterIds( String aVhimVersion )
        throws FilterServiceException
    {
        Collection<String> filterIds = new ArrayList<String>();
        for ( Map.Entry<String, Properties> entry : filterMetaDataMap.entrySet() )
        {
            if ( entry.getValue().getProperty( "vhimVersion" ).equals( aVhimVersion ) )
            {
                String filterId = entry.getKey();
                filterIds.add( filterId );
            }
        }
        return filterIds;
    }


    @Override
    public boolean isAlive( )
    {
        return true;
    }
}
