package com.ibm.emb.test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.StringTokenizer;

import javax.emb.MediaBean;
import javax.emb.MediaConverter;
import javax.emb.MediaConverterSpec;
import javax.emb.MediaException;
import javax.emb.MediaFormat;
import javax.emb.MediaFormatRegistry;

import junit.framework.Test;
import junit.framework.TestSuite;

import com.ibm.emb.junit.EMBStaticHelper;
import com.ibm.emb.junit.EMBTestCaseBase;

/**
 * <pre>
 * 
 *  
 *   
 *    Line Item: MFB API 
 *    Subcategory 1: javax.emb
 *    Subcategory 2: MediaConverter
 *    
 *    This abstract class provides test methods for all methods described in the interface 
 *    MediaConverter. 
 *    For testing implementations of this interface one needs to create a Tester
 *    class which extends this abstract class.
 *    
 *   
 *  
 * </pre>
 */
public abstract class MediaConverterTest extends EMBTestCaseBase {

    public MediaConverterTest(String name) throws MediaException {
        super(name);
    }

    /**
     * stdSuite method of this test class instantiates all tests necesssary to
     * for the standard compliance tests
     * @param String complete class Name of the implementor of the abstract test
     */
    public static Test stdSuite(String TestCaseImplementor) {
        TestSuite suite = new TestSuite(TestCaseImplementor);
        try {
            Class implementorClass = Class.forName(TestCaseImplementor);
            java.lang.reflect.Constructor implementorConstructor = implementorClass
                    .getDeclaredConstructor(new Class[] {String.class});
            suite.addTest((Test) implementorConstructor.newInstance(new String[] {"testEMB039"}));
            suite.addTest((Test) implementorConstructor.newInstance(new String[] {"testEMB040"}));
        } catch (java.lang.reflect.InvocationTargetException ex) {
            String msg = "error dynamically creating " + TestCaseImplementor + " " + ex.toString();
            EMBStaticHelper.testTrace(msg);
            throw new RuntimeException(msg);
        } catch (ClassNotFoundException ex) {
            String msg = "Class not found " + TestCaseImplementor + " " + ex.toString();
            EMBStaticHelper.testTrace(msg);
            throw new RuntimeException(msg);
        } catch (NoSuchMethodException ex) {
            String msg = "No such method in " + TestCaseImplementor + " " + ex.toString();
            EMBStaticHelper.testTrace(msg);
            throw new RuntimeException(msg);
        } catch (InstantiationException ex) {
            String msg = TestCaseImplementor + " " + ex.toString();
            EMBStaticHelper.testTrace(msg);
            throw new RuntimeException(msg);
        } catch (IllegalAccessException ex) {
            String msg = TestCaseImplementor + " " + ex.toString();
            EMBStaticHelper.testTrace(msg);
            throw new RuntimeException(msg);
        }
        return suite;
    }

    /**
     * abstract method to create an instance of MediaConverter this method needs
     * to be implemented in the test subclass and will create an instance of the
     * concrete implementation of the class under test
     */
    public abstract MediaConverter createMediaConverter() throws MediaException;

    /**
     * <pre>
     * 
     *  
     *   
     *    Testcase Name: process(InputStream)
     *    Testcase Number: EMB039
     *    
     *    setup: access file containing a list of all implemented MediaConverterSpecs and sample files
     *    
     *    test procedure:
     *    1.for each converter spec, call process passing null
     *      expected result: NullPointerException
     *    
     *    2.for each converter spec, create input stream from matching input file 
     *      call process
     *      expected result: not null and no exceptions	
     *    
     *   
     *  
     * </pre>
     */
    public void testEMB039() throws MediaException, IOException {

        // retrieve all Media formats and bind with Media format registry
        String allMediaFormats = embTestConfig.getAllMediaFormats();
        allMediaFormats = allMediaFormats.trim();
        StringTokenizer mediaTokenizer = new StringTokenizer(allMediaFormats, ";");
        String formatInfo = null;
        StringTokenizer formatInfoTokenizer = null;

        String fullClassName = null;
        String fileExtension = null;
        String mediaFileName = null;

        MediaFormatRegistry formatRegistry = MediaFormatRegistry.SINGLETON;

        while (mediaTokenizer.hasMoreTokens()) {
            formatInfo = mediaTokenizer.nextToken();
            formatInfoTokenizer = new StringTokenizer(formatInfo);
            assertEquals("test initialization: ", 3, formatInfoTokenizer.countTokens());
            fullClassName = formatInfoTokenizer.nextToken();
            fileExtension = formatInfoTokenizer.nextToken();
            mediaFileName = formatInfoTokenizer.nextToken();

            try {
                formatRegistry.rebind(fileExtension, (MediaFormat) Class.forName(fullClassName).newInstance());
            } catch (ClassNotFoundException e) {
                fail("Class not found: " + e.getMessage());
            } catch (IllegalAccessException e) {
                fail("Illegal access: " + e.getMessage());
            } catch (InstantiationException e) {
                fail("Instantiation exception: " + e.getMessage());
            }
        }

        // retrieve Media converter specs
        String allMediaConverterSpecs = embTestConfig.getAllMediaConverterSpecs();
        allMediaConverterSpecs = allMediaConverterSpecs.trim();

        // token individual Media formats
        StringTokenizer converterSpecsTokenizer = new StringTokenizer(allMediaConverterSpecs, ";");
        String specInfo = null;
        StringTokenizer specInfoTokenizer = null;

        while (converterSpecsTokenizer.hasMoreTokens()) {
            specInfo = converterSpecsTokenizer.nextToken();
            specInfoTokenizer = new StringTokenizer(specInfo);

            assertEquals("test initialization: ", 2, specInfoTokenizer.countTokens());

            fullClassName = specInfoTokenizer.nextToken();
            mediaFileName = specInfoTokenizer.nextToken();

            String mediaFullPath = embTestConfig.getMediaDir() + File.separator + mediaFileName;

            try {
                File mediaFile = new File(mediaFullPath);
                InputStream mediaFileInputStream = new FileInputStream(mediaFile);
                MediaConverterSpec testSpec = (MediaConverterSpec) Class.forName(fullClassName).newInstance();
                MediaConverter testInstance = testSpec.getConverter();

                //
                // test 1
                //
                try {
                    testInstance.process(null);
                    fail("[" + fullClassName + "] test 1 should throw NullPointerException");
                } catch (NullPointerException e) {
                    testTrace("[" + fullClassName + "] test 1 passed");
                } catch (Exception e) {
                    fail("[" + fullClassName + "] test 1: Should throw NullPointerException but threw " + e.toString());
                }
                //
                // test 2
                //
                InputStream convertedMediaInputStream = testInstance.process(mediaFileInputStream);
                MediaBean testMedia = new MediaBean(convertedMediaInputStream, testSpec.getTargetMimeType(),
                        "convertedMedia." + testSpec.getTargetFileExtension());
                assertNotNull("[" + fullClassName + "] test 2: ", testMedia);
                assertEquals("[" + fullClassName + "] test 2: ", testMedia.getFormat(), formatRegistry.lookup(testSpec
                        .getTargetFileExtension()));
                testTrace("[" + fullClassName + "] test 2 passed");

            } catch (ClassNotFoundException e) {
                fail("Class not found: " + e.getMessage());
            } catch (FileNotFoundException e) {
                fail("File not found: " + e.getMessage());
            } catch (IllegalAccessException e) {
                fail("Illegal access: " + e.getMessage());
            } catch (InstantiationException e) {
                fail("Instantiation exception: " + e.getMessage());
            }
        }

        succeed();
    }

    /**
     * <pre>
     * 
     *  
     *   
     *    Testcase Name: process(InputStream, OutputStream)
     *    Testcase Number: EMB040
     *    
     *    setup: access file containing a list of all implemented MediaConverterSpecs and sample files
     *    
     *    test procedure: 
     *    1.for each converter spec, call process passing null as input
     *      expected result: NullPointerException 
     *    
     *    2.for each converter spec, call process passing null as output
     *      expected result: NullPointerException 
     *    
     *    3.for each converter spec, create input stream from matching file and call process
     *      expected result: not null and no exception
     *    
     *   
     *  
     * </pre>
     */
    public void testEMB040() throws MediaException, IOException {

        // retrieve all Media formats and bind with Media format registry
        String allMediaFormats = embTestConfig.getAllMediaFormats();
        allMediaFormats = allMediaFormats.trim();
        StringTokenizer mediaTokenizer = new StringTokenizer(allMediaFormats, ";");
        String formatInfo = null;
        StringTokenizer formatInfoTokenizer = null;

        String fullClassName = null;
        String fileExtension = null;
        String mediaFileName = null;

        javax.emb.MediaFormatRegistry formatRegistry = MediaFormatRegistry.SINGLETON;

        while (mediaTokenizer.hasMoreTokens()) {
            formatInfo = mediaTokenizer.nextToken();
            formatInfoTokenizer = new StringTokenizer(formatInfo);
            assertEquals("test initialization: ", 3, formatInfoTokenizer.countTokens());
            fullClassName = formatInfoTokenizer.nextToken();
            fileExtension = formatInfoTokenizer.nextToken();
            mediaFileName = formatInfoTokenizer.nextToken();

            try {
                formatRegistry.rebind(fileExtension, (MediaFormat) Class.forName(fullClassName).newInstance());
            } catch (ClassNotFoundException e) {
                fail("Class not found: " + e.getMessage());
            } catch (IllegalAccessException e) {
                fail("Illegal access: " + e.getMessage());
            } catch (InstantiationException e) {
                fail("Instantiation exception: " + e.getMessage());
            }
        }

        // retrieve Media converter specs
        String allMediaConverterSpecs = embTestConfig.getAllMediaConverterSpecs();
        allMediaConverterSpecs = allMediaConverterSpecs.trim();

        // token individual Media formats
        StringTokenizer converterSpecsTokenizer = new StringTokenizer(allMediaConverterSpecs, ";");
        String specInfo = null;
        StringTokenizer specInfoTokenizer = null;

        while (converterSpecsTokenizer.hasMoreTokens()) {
            specInfo = converterSpecsTokenizer.nextToken();
            specInfoTokenizer = new StringTokenizer(specInfo);

            assertEquals("test initialization: ", 2, specInfoTokenizer.countTokens());

            fullClassName = specInfoTokenizer.nextToken();
            mediaFileName = specInfoTokenizer.nextToken();

            String mediaFullPath = embTestConfig.getMediaDir() + File.separator + mediaFileName;

            try {
                File mediaFile = new File(mediaFullPath);
                InputStream mediaFileInputStream = new FileInputStream(mediaFile);
                MediaConverterSpec testSpec = (MediaConverterSpec) Class.forName(fullClassName).newInstance();
                MediaConverter testInstance = testSpec.getConverter();
                ByteArrayOutputStream convertedMediaOutputStream = new ByteArrayOutputStream();
                //
                // test 1
                // 	
                try {
                    testInstance.process(null, convertedMediaOutputStream);
                    fail("[" + testSpec + "] test 1: Should throw a NullPointerException");
                } catch (NullPointerException e) {
                    testTrace("[" + testSpec + "] test 1 passed");
                } catch (Exception e) {
                    fail("[" + testSpec + "] test 1: Should throw a NullPointerException but threw " + e.toString());
                }
                //
                // test 2
                //	
                try {
                    testInstance.process(mediaFileInputStream, null);
                    fail("[" + testSpec + "] test 2: Should throw a NullPointerException");
                } catch (NullPointerException e) {
                    testTrace("[" + testSpec + "] test 2 passed");
                } catch (Exception e) {
                    fail("[" + testSpec + "] test 2: Should throw NullPointerException but threw " + e.toString());
                }
                //
                // test 3
                //
                testInstance.process(mediaFileInputStream, convertedMediaOutputStream);
                ByteArrayInputStream convertedMediaInputStream = new ByteArrayInputStream(convertedMediaOutputStream
                        .toByteArray());
                MediaBean testMedia = new MediaBean(convertedMediaInputStream, testSpec.getTargetMimeType(),
                        "convertedMedia." + testSpec.getTargetFileExtension());
                assertNotNull("[" + fullClassName + "] test 3: ", testMedia);
                assertEquals("[" + fullClassName + "] test 3: ", testMedia.getFormat(), formatRegistry.lookup(testSpec
                        .getTargetFileExtension()));
                testTrace("[" + testSpec + "] test 3 passed");

            } catch (ClassNotFoundException e) {
                fail("Class not found: " + e.getMessage());
            } catch (FileNotFoundException e) {
                fail("File not found: " + e.getMessage());
            } catch (IllegalAccessException e) {
                fail("Illegal access: " + e.getMessage());
            } catch (InstantiationException e) {
                fail("Instantiation exception: " + e.getMessage());
            }
        }
        succeed();
    }

}