/*
 * Copyright (c) eHealth
 */
package be.ehealth.businessconnector.dicsv3.validator;

import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertTrue;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;

import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import be.ehealth.technicalconnector.exception.TechnicalConnectorException;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.ehealth.technicalconnector.utils.MarshallerHelper;
import be.fgov.ehealth.dics.protocol.v3.FindAmpRequest;
import be.fgov.ehealth.dics.protocol.v3.FindAmpResponse;
import be.fgov.ehealth.dics.protocol.v3.FindCompanyRequest;
import be.fgov.ehealth.dics.protocol.v3.FindCompanyResponse;
import be.fgov.ehealth.dics.protocol.v3.FindCompoundingFormulaRequest;
import be.fgov.ehealth.dics.protocol.v3.FindCompoundingFormulaResponse;
import be.fgov.ehealth.dics.protocol.v3.FindCompoundingIngredientRequest;
import be.fgov.ehealth.dics.protocol.v3.FindCompoundingIngredientResponse;
import be.fgov.ehealth.dics.protocol.v3.FindLegislationTextRequest;
import be.fgov.ehealth.dics.protocol.v3.FindLegislationTextResponse;
import be.fgov.ehealth.dics.protocol.v3.FindReferencesRequest;
import be.fgov.ehealth.dics.protocol.v3.FindReferencesResponse;
import be.fgov.ehealth.dics.protocol.v3.FindReimbursementRequest;
import be.fgov.ehealth.dics.protocol.v3.FindReimbursementResponse;
import be.fgov.ehealth.dics.protocol.v3.FindVmpGroupRequest;
import be.fgov.ehealth.dics.protocol.v3.FindVmpGroupResponse;
import be.fgov.ehealth.dics.protocol.v3.FindVmpRequest;
import be.fgov.ehealth.dics.protocol.v3.FindVmpResponse;
import be.fgov.ehealth.dics.protocol.v3.FindVtmRequest;
import be.fgov.ehealth.dics.protocol.v3.FindVtmResponse;
import be.fgov.ehealth.technicalconnector.tests.junit.rule.RestoreSystemProperties;

/**
 * tests the class XmlValidator.
 * 
 * @author EHP
 * 
 */
public class XmlValidatorTest {

    @Rule
    public ExpectedException exception = ExpectedException.none();


    @ClassRule
    public static RestoreSystemProperties restoreSystemPropertiesRule = new RestoreSystemProperties();


    @Test
    public void testValidateFindAmpRequest() throws Exception {
        validate("/examples/findAmpRequest.xml", FindAmpRequest.class);
    }

    @Test
    public void testValidateFindAmpResponse() throws Exception {
        validate("/examples/findAmpResponse.xml", FindAmpResponse.class);
    }

    @Test
    public void testValidateFindCommentedClassificationRequest() throws Exception {
        validate("/examples/findCommentedClassificationRequest.xml", FindAmpRequest.class);
    }

    @Test
    public void testValidateFindCommentedClassificationResponse() throws Exception {
        validate("/examples/findCommentedClassificationResponse.xml", FindAmpResponse.class);
    }


    @Test
    public void testValidateFindCompanyRequest() throws Exception {
        validate("/examples/findCompanyRequest.xml", FindCompanyRequest.class);
    }

    @Test
    public void testValidateFindCompanyResponse() throws Exception {
        validate("/examples/findCompanyResponse.xml", FindCompanyResponse.class);
    }


    @Test
    public void testValidateFindFormulaRequest() throws Exception {
        validate("/examples/findFormulaRequest.xml", FindCompoundingFormulaRequest.class);
    }

    @Test
    public void testValidateFindFormulaResponse() throws Exception {
        validate("/examples/findFormulaResponse.xml", FindCompoundingFormulaResponse.class);
    }

    @Test
    public void testValidateFindIngredientRequest() throws Exception {
        validate("/examples/FindIngredientRequest.xml", FindCompoundingIngredientRequest.class);
    }

    @Test
    public void testValidateFindIngredientResponse() throws Exception {
        validate("/examples/FindIngredientResponse.xml", FindCompoundingIngredientResponse.class);
    }

    @Test
    public void testValidateFindLegislationTextRequest() throws Exception {
        validate("/examples/findLegislationTextRequest.xml", FindLegislationTextRequest.class);
    }

    @Test
    public void testValidateFindLegislationTextResponse() throws Exception {
        validate("/examples/findLegislationTextResponse.xml", FindLegislationTextResponse.class);
    }

    @Test
    public void testValidateFindReferencesRequest() throws Exception {
        validate("/examples/findReferencesRequest.xml", FindReferencesRequest.class);
    }

    @Test
    public void testValidateFindReferencesResponse() throws Exception {
        validate("/examples/findReferencesResponse.xml", FindReferencesResponse.class);
    }

    @Test
    public void testValidateFindReimbursementRequest() throws Exception {
        validate("/examples/findReimboursementRequest.xml", FindReimbursementRequest.class);
    }

    @Test
    public void testValidateFindReimbursementResponse() throws Exception {
        validate("/examples/findReimboursementResponse.xml", FindReimbursementResponse.class);
    }

    @Test
    public void testValidateFindVmpRequest() throws Exception {
        validate("/examples/findVmpRequest.xml", FindVmpRequest.class);
    }

    @Test
    public void testValidateFindVmpResponse() throws Exception {
        validate("/examples/findVmpResponse.xml", FindVmpResponse.class);
    }


    @Test
    public void testValidateFindVmpGroupRequest() throws Exception {
        validate("/examples/findVmpGroupRequest.xml", FindVmpGroupRequest.class);
    }

    @Test
    public void testValidateFindVmpGroupResponse() throws Exception {
        validate("/examples/findVmpGroupResponse.xml", FindVmpGroupResponse.class);
    }


    @Test
    public void testValidateFindVtmRequest() throws Exception {
        validate("/examples/findVtmRequest.xml", FindVtmRequest.class);
    }

    @Test
    public void testValidateFindVtmResponse() throws Exception {
        validate("/examples/findVtmResponse.xml", FindVtmResponse.class);
    }

    @Test
    public void testValidateInvalidFindVtmRequest() throws Exception {
        exception.expect(TechnicalConnectorException.class);
        exception.expectMessage(containsString("XML could not be validated against XSD"));

        validate("/examples/InvalidFindVtmRequest.xml", FindVtmRequest.class);
    }

    private static <T> void validate(String location, Class<T> clazz) throws Exception {
        MarshallerHelper<T, T> helper = new MarshallerHelper<T, T>(clazz, clazz);
        T xmlObject = helper.toObject(ConnectorIOUtils.getResourceAsStream(location));
        XmlValidator.validateXml(xmlObject);
    }

    @Test
    public void testConstructorIsPrivate() throws Exception {
        Constructor<XmlValidator> constructor = XmlValidator.class.getDeclaredConstructor();
        assertTrue("Constructor is not private", Modifier.isPrivate(constructor.getModifiers()));

        constructor.setAccessible(true);
        try {
            constructor.newInstance();
            Assert.fail("should have thrown UnsupportedOperationException");
        } catch (InvocationTargetException e) {
            Assert.assertTrue(e.getTargetException() instanceof UnsupportedOperationException);
            UnsupportedOperationException usoe = (UnsupportedOperationException) e.getTargetException();
            Assert.assertEquals("class may not be initialized, only static methods should be used", usoe.getMessage());
        }
    }
}
