/*
 *    GeoTools - OpenSource mapping toolkit
 *    http://geotools.org
 *    (C) 2002-2006, GeoTools Project Managment Committee (PMC)
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation;
 *    version 2.1 of the License.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 */
package org.geotools.gml3;

import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.util.XSDSchemaLocationResolver;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URI;
import java.util.List;
import org.geotools.xml.Configuration;
import org.geotools.xml.Schemas;
import org.geotools.xs.XSConfiguration;


/**
 * Structure of the files in the test folder:
 *
 * <pre>
 * <code>
 * a.xsd
 * b.xsd
 * c.xsd
 * </code>
 * Where a.xsd includes b.xsd, a.xsd imports c.xsd, c.xsd imports subfolder/d.xsd.
 * </pre>
 *
 * @author Gabriel Roldan
 * @version $Id: ApplicationSchemaConfigurationTest.java 29135 2008-02-07 19:49:09Z desruisseaux $
 * @URL $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/xml-gml3/src/test/java/org/geotools/gml3/ApplicationSchemaConfigurationTest.java $
 * @since 2.4.x
 *
 */
public class ApplicationSchemaConfigurationTest extends TestCase {
    private static final String namespace = "http://www.geotools.org/test";
    private static ApplicationSchemaConfiguration configuration;
    private static XSDSchema rootSchema;
    private static String rootSchemaLocationFolder;
    private static String rootSchemaLocation;

    /**
     * Builds a test suite for all this class' tests with per suite
     * initialization directed to {@link #oneTimeSetUp()} and per suite clean up
     * directed to {@link #oneTimeTearDown()}
     *
     * @return
     */
    public static Test suite() {
        TestSuite suite = new TestSuite();
        suite.addTestSuite(ApplicationSchemaConfigurationTest.class);

        TestSetup wrapper = new TestSetup(suite) {
                protected void setUp() throws Exception {
                    oneTimeSetUp();
                }

                protected void tearDown() {
                    oneTimeTearDown();
                }
            };

        return wrapper;
    }

    private static void oneTimeSetUp() throws Exception {
        // test files located in src/test/resources/<this class package name>
        final String testFilesFolderName = "./ApplicationSchemaConfigurationTestFiles";
        final File file = new File(new URI(ApplicationSchemaConfigurationTest.class.getResource(
                        testFilesFolderName).toExternalForm()));

        if (!file.exists()) {
            throw new FileNotFoundException("test resources folder does not exists: "
                + file.getAbsolutePath());
        }

        rootSchemaLocationFolder = file.toURI().toString();
        rootSchemaLocation = new File(file, "a.xsd").toURI().toString();
        configuration = new ApplicationSchemaConfiguration(namespace, rootSchemaLocation);

        rootSchema = Schemas.parse(rootSchemaLocation);
    }

    private static void oneTimeTearDown() {
        configuration = null;
        rootSchema = null;
    }

    /**
     */
    protected void setUp() throws Exception {
        super.setUp();

        // may be we're running a single test instead of the whose suite
        if (configuration == null) {
            oneTimeSetUp();
        }
    }

    protected void tearDown() throws Exception {
        super.tearDown();
    }

    public void testGetDependencies() {
        List dependencies = configuration.getDependencies();
        assertNotNull(dependencies);
        assertEquals(2, dependencies.size());

        Configuration dep1 = (Configuration) dependencies.get(0);
        Configuration dep2 = (Configuration) dependencies.get(1);

        assertTrue(dep1 instanceof XSConfiguration);
        assertTrue(dep2 instanceof GMLConfiguration);
    }

    public void testGetSchemaLocationResolverPreconditions()
        throws Exception {
        final XSDSchemaLocationResolver resolver = configuration.getSchemaLocationResolver();

        //null schema is allowed if for the same namespace than the configuration
        String location = resolver.resolveSchemaLocation(null, namespace, "a.xsd");
        assertEquals(rootSchemaLocation, location);

        try {
            //but now allowed otherwise
            resolver.resolveSchemaLocation(null, namespace + "/2", "");
            fail("Expected NPE on null schema");
        } catch (NullPointerException e) {
            assertTrue(true);
        }

        try {
            resolver.resolveSchemaLocation(rootSchema, null, "");
            fail("Expected NPE on null uri");
        } catch (NullPointerException e) {
            assertTrue(true);
        }

        try {
            resolver.resolveSchemaLocation(rootSchema, namespace, null);
            fail("Expected NPE on null schema location");
        } catch (NullPointerException e) {
            assertTrue(true);
        }
    }

    /**
     * a.xsd include b.xsd
     */
    public void testGetSchemaLocationResolverRelativeInclude()
        throws Exception {
        final XSDSchemaLocationResolver resolver = configuration.getSchemaLocationResolver();

        // simulate an include, empty locationUri
        final String locationUri = "";
        final String schemaLocation = "b.xsd";

        final String importLocation = resolver.resolveSchemaLocation(rootSchema, locationUri,
                schemaLocation);
        final String expectedLocation = new File(new File(new URI(rootSchemaLocationFolder)),
                schemaLocation).toURL().toExternalForm();
        assertEquals(expectedLocation, importLocation);
    }

    /**
     * a.xsd imports c.xsd
     */
    public void testGetSchemaLocationResolverRelativeImport()
        throws Exception {
        final XSDSchemaLocationResolver resolver = configuration.getSchemaLocationResolver();

        // simulate a relative path import
        final String locationUri = "http://www.geotools.org/test/2";
        final String schemaLocation = "c.xsd";

        final String importLocation = resolver.resolveSchemaLocation(rootSchema, locationUri,
                schemaLocation);
        final String expectedLocation = new File(new File(new URI(rootSchemaLocationFolder)),
                schemaLocation).toURL().toExternalForm();
        assertEquals(expectedLocation, importLocation);
    }

    /**
     * a.xsd imports http://www.w3.org/2001/xml.xsd
     */
    public void testGetSchemaLocationResolverAbsoluteImport()
        throws Exception {
        final XSDSchemaLocationResolver resolver = configuration.getSchemaLocationResolver();

        // simulate an absolute path import
        final String locationUri = "http://www.w3.org/XML/1998/namespace";
        final String schemaLocation = "http://www.w3.org/2001/xml.xsd";

        final String importLocation = resolver.resolveSchemaLocation(rootSchema, locationUri,
                schemaLocation);

        assertNull(importLocation);
    }
}
