package com.hpe.caf.worker.testing.validation;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hpe.caf.api.Codec;
import com.hpe.caf.api.worker.DataStore;
import com.hpe.caf.util.ref.DataSourceException;
import com.hpe.caf.util.ref.ReferencedData;
import com.hpe.caf.worker.testing.ContentComparer;
import com.hpe.caf.worker.testing.ContentFileTestExpectation;
import com.hpe.caf.worker.testing.TestResultHelper;
import com.hpe.caf.worker.testing.data.ContentComparisonType;
import com.hpe.caf.worker.testing.data.ContentDataHelper;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;

/**
 * Created by ploch on 07/12/2015.
 */
public class ReferenceDataValidator extends PropertyValidator {

    private final DataStore dataStore;
    private final Codec codec;
    private final String testDataFolder;

    public ReferenceDataValidator(DataStore dataStore, Codec codec, String testDataFolder) {

        this.dataStore = dataStore;
        this.codec = codec;
        this.testDataFolder = testDataFolder;
    }

    @Override
    public boolean isValid(Object testedPropertyValue, Object validatorPropertyValue) {

        if (testedPropertyValue == null && validatorPropertyValue == null) return true;

        ObjectMapper mapper = new ObjectMapper();

        ContentFileTestExpectation expectation = mapper.convertValue(validatorPropertyValue, ContentFileTestExpectation.class);

        ReferencedData referencedData = mapper.convertValue(testedPropertyValue, ReferencedData.class);

        InputStream dataStream;

        try {
            System.out.println("About to retrieve content for " + referencedData.toString());
            dataStream = ContentDataHelper.retrieveReferencedData(dataStore, codec, referencedData);
            System.out.println("Finished retrieving content for " + referencedData.toString());
        }
        catch (DataSourceException e) {
            e.printStackTrace();
            System.err.println("Failed to acquire referenced data.");
            e.printStackTrace();
            TestResultHelper.testFailed("Failed to acquire referenced data. Exception message: " + e.getMessage(), e);
            return false;
        }
        try {
            String contentFileName = expectation.getExpectedContentFile();
            Path contentFile = Paths.get(contentFileName);
            if (Files.notExists(contentFile)) {
                contentFile = Paths.get(testDataFolder, contentFileName);
            }

            byte[] expectedFileBytes = Files.readAllBytes(contentFile);

            if (expectation.getComparisonType() == ContentComparisonType.TEXT) {

                String actualText = IOUtils.toString(dataStream, StandardCharsets.UTF_8);
                String expectedText = new String(expectedFileBytes, StandardCharsets.UTF_8);

                if (expectation.getExpectedSimilarityPercentage() == 100) {
                    boolean equals = actualText.equals(expectedText);
                    if (!equals) {
                        String message = "Expected and actual texts were different.\n\n*** Expected Text ***\n" +
                        expectedText + "\n\n*** Actual Text ***\n" + actualText;
                        System.err.println(message);
                        TestResultHelper.testFailed(message);
                        return false;
                    }
                    return true;
                }

                double similarity = ContentComparer.calculateSimilarityPercentage(expectedText, actualText);

                System.out.println("Compared text similarity:" + similarity + "%");

                if (similarity < expectation.getExpectedSimilarityPercentage()) {
                    String message = "Expected similarity of " + expectation.getExpectedSimilarityPercentage() + "% but actual similarity was " + similarity + "%";
                    System.err.println(message);
                    TestResultHelper.testFailed(message);
                    return false;
                }
            }
            else {
                byte[] actualDataBytes = IOUtils.toByteArray(dataStream);
                boolean equals = Arrays.equals(actualDataBytes, expectedFileBytes);
                if (!equals) {
                    String message = "Data returned was different than expected for file: " + contentFileName;
                    System.err.println(message);
                    TestResultHelper.testFailed(message);
                    return false;
                }
            }
        }
        catch (IOException e) {
            e.printStackTrace();
            TestResultHelper.testFailed("Error while processing reference data! " + e.getMessage(), e);
            return false;
        }
        return true;
    }
}

@@ -4576,32 +4576,196 @@
 intln(message);%0A
+                    Path actualFilePath = Paths.get(testDataFolder, contentFileName + %22_actual%22);%0A                    Files.write(actualFilePath, actualDataBytes);%0A
                 

Write the actual content to disk when content fails to match expected.