/*
 * Copyright (c) eHealth
 */
package be.ehealth.technicalconnector.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.Arrays;
import java.util.zip.*;

import org.apache.commons.io.IOUtils;
import org.bouncycastle.util.encoders.Base64;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import be.ehealth.technicalconnector.config.ConfigFactory;
import be.ehealth.technicalconnector.exception.TechnicalConnectorException;


/**
 * Test class which evaluates the differents compression algorithmes
 * 
 * @author EHP
 */
public class ConnectorIOUtilsTest {

    @BeforeClass
    public static void init() throws Exception {
        ConfigFactory.getConfigValidator()
                     .getConfig();
    }


    @Before
    public void initJavaTempDir() {
        System.setProperty("java.io.tmpdir", "c:\\Temp");
    }

    /**
     * Unit test to ensure backwards compability between version 2 of the connector.
     * 
     * @author EHP
     */
    @Test
    public void testDecompressionGzip() throws Exception {

        byte[] in = "ehealthplatform".getBytes();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream gzipos = new GZIPOutputStream(baos);
        gzipos.write(in);
        gzipos.flush();
        baos.flush();
        gzipos.close();
        baos.close();
        byte[] gzipin = baos.toByteArray();


        byte[] result = ConnectorIOUtils.decompress(gzipin);

        Assert.assertEquals(new String(in), new String(result));
    }

    /**
     * Unit test to ensure backwards compability between version 2 of the connector.
     * 
     * @author EHP
     */
    @Test
    public void testCompressionGzip() throws Exception {
        byte[] in = "ehealthplatform".getBytes();
        byte[] out = ConnectorIOUtils.compress(in);

        GZIPInputStream input = new GZIPInputStream(new ByteArrayInputStream(out));
        byte[] result = ConnectorIOUtils.getBytes(input);

        Assert.assertEquals(new String(in), new String(result));
    }

    @Test
    public void testDecompressionZlib() throws Exception {

        byte[] in = "ehealthplatform".getBytes();
        Deflater compresser = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
        compresser.setInput(in);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        compresser.finish();

        byte[] buffer = new byte[1024];
        while (!compresser.finished()) {
            int count = compresser.deflate(buffer);
            outputStream.write(buffer, 0, count);
        }
        outputStream.close();
        byte[] comout = outputStream.toByteArray();
        compresser.end();


        byte[] result = ConnectorIOUtils.decompress(comout);
        // result = ConnectorIOUtils.getBytes(is);
        Assert.assertEquals(new String(in), new String(result));
    }

    @Test
    public void testCompressionDEFLATER() throws Exception {

        StringBuilder sb = new StringBuilder("ehealthplatform 12345567890\n |é#'(§è!ççà einde string");

        final String inputString = sb.toString();
        byte[] original = inputString.getBytes();

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
        DeflaterInputStream deflateInputStream = new DeflaterInputStream(new ByteArrayInputStream(original), deflater);
        IOUtils.copy(deflateInputStream, bos);

        bos.flush();
        bos.close();
        byte[] expected = bos.toByteArray();

        byte[] actual = ConnectorIOUtils.compress(original, ConnectorIOUtils.COMPRESSION_ALGO_DEFLATE);
        Assert.assertEquals(new String(expected), new String(actual));

        // test decompres with result compression
        byte[] compressedDecompressed = ConnectorIOUtils.decompress(ConnectorIOUtils.compress(original, ConnectorIOUtils.COMPRESSION_ALGO_DEFLATE));
        String resultString = new String(compressedDecompressed);
        Assert.assertEquals(inputString, resultString);
        Assert.assertEquals(compressedDecompressed.length, original.length);
        Assert.assertTrue(Arrays.equals(compressedDecompressed, original));
    }


    @Test
    public void testDeCompressionDEFLATER() throws Exception {


        byte[] in = "ehealthplatform".getBytes();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DeflaterOutputStream gzipos = new DeflaterOutputStream(baos, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
        gzipos.write(in);
        gzipos.flush();
        baos.flush();
        gzipos.close();
        baos.close();
        byte[] compressed = baos.toByteArray();


        byte[] actual = ConnectorIOUtils.decompress(compressed);


        Assert.assertEquals(new String(in), new String(actual));


    }

    @Test
    public void testBase64DecodeEmptyArray() throws Exception {
        byte[] base64Decode = ConnectorIOUtils.base64Decode("".getBytes(), false);
        Assert.assertNotNull(base64Decode);
    }

    @Test
    public void testBase64DecodeArrayWithLength1ReturnsWithoutDecoding() throws Exception {
        String original = "a";
        byte[] base64Decode = ConnectorIOUtils.base64Decode(original.getBytes(), false);
        Assert.assertNotNull(base64Decode);
        Assert.assertArrayEquals(original.getBytes(), base64Decode);
    }

    @Test
    public void testBase64DecodeArrayWithLength2ReturnsWithoutDecoding() throws Exception {
        String original = "ab";
        byte[] base64Decode = ConnectorIOUtils.base64Decode(original.getBytes(), false);
        Assert.assertNotNull(base64Decode);
        Assert.assertArrayEquals(original.getBytes(), base64Decode);
    }

    @Test
    public void testBase64DecodeArrayWithLength3ReturnsWithoutDecoding() throws Exception {
        String original = "abc";
        byte[] base64Decode = ConnectorIOUtils.base64Decode(original.getBytes(), false);
        Assert.assertNotNull(base64Decode);
        Assert.assertArrayEquals(original.getBytes(), base64Decode);
    }

    @Test
    public void testBase64DecodeArrayWithLength4() throws Exception {
        String original = "abcd";
        byte[] base64Decode = ConnectorIOUtils.base64Decode(original.getBytes(), false);
        Assert.assertNotNull(base64Decode);
        Assert.assertArrayEquals(original.getBytes(), Base64.encode(base64Decode));
    }

    @Test
    public void testBase64DecodeArrayWithLength5ReturnsWithoutDecoding() throws Exception {
        String original = "abcde";
        byte[] base64Decode = ConnectorIOUtils.base64Decode(original.getBytes(), false);
        Assert.assertNotNull(base64Decode);
        Assert.assertEquals(original, new String(base64Decode));
        Assert.assertArrayEquals(original.getBytes(), base64Decode);
    }

    @Test
    public void testCreateTempFile() throws Exception {
        String fileName = "testCreationTempFile.txt";
        File file = ConnectorIOUtils.createTempFile(fileName);
        Assert.assertTrue(file.exists());
        Assert.assertTrue(file.delete());
    }

    @Test
    public void testCreateTempFileWithoutFileSeparator() throws Exception {
        String fileName = "testCreationTempFile.txt";
        File file = ConnectorIOUtils.createTempFile(fileName);
        Assert.assertTrue(file.exists());
        Assert.assertTrue(file.delete());
    }

    @Test(expected = TechnicalConnectorException.class)
    public void testCreateTempFileErrorNameNull() throws Exception {
        String fileName = "";
        ConnectorIOUtils.createTempFile(fileName);
    }

    @Test(expected = TechnicalConnectorException.class)
    public void testCreateTempFileErrorPropertyNotFound() throws Exception {
        System.getProperties()
              .remove("java.io.tmpdir");
        String fileName = "testCreationTempFile.txt";
        ConnectorIOUtils.createTempFile(fileName);
    }

    @Test
    public void testGetTempFileLocation() throws Exception {
        String fileName = "testCreationTempFile.txt";
        String fileLocation = ConnectorIOUtils.getTempFileLocation(fileName);
        Assert.assertEquals("The path of the file is not the one expected", "c:\\Temp\\testCreationTempFile.txt", fileLocation);
    }

    @Test
    public void testGetTempFileLocationWithoutFileSeparator() throws Exception {
        String fileName = "testCreationTempFile.txt";
        String fileLocation = ConnectorIOUtils.getTempFileLocation(fileName);
        Assert.assertEquals("The path of the file is not the one expected", "c:\\Temp\\testCreationTempFile.txt", fileLocation);
    }

    @Test(expected = TechnicalConnectorException.class)
    public void testGetTempFileLocationErrorNameNull() throws Exception {
        String fileName = "";
        ConnectorIOUtils.getTempFileLocation(fileName);
    }

    @Test(expected = TechnicalConnectorException.class)
    public void testGetTempFileLocationErrorPropertyNotFound() throws Exception {
        System.getProperties()
              .remove("java.io.tmpdir");
        String fileName = "testCreationTempFile.txt";
        ConnectorIOUtils.getTempFileLocation(fileName);
    }
}
