/*   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package compile.scomp.checkin;

import compile.scomp.common.CompileCommon;
import compile.scomp.common.CompileTestBase;
import compile.scomp.common.mockobj.TestFiler;
import org.apache.xmlbeans.*;
import org.apache.xmlbeans.impl.schema.SchemaTypeSystemImpl;
import org.junit.After;
import org.junit.Test;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import static org.junit.Assert.*;

public class XmlBeansCompCheckinTests extends CompileTestBase
{   public final List xm_errors = new ArrayList();
    public final XmlOptions xm_opts = new XmlOptions();
    final Vector expBinType = new Vector();
    final Vector expSrcType = new Vector();

    public XmlBeansCompCheckinTests() {
        expBinType.add("org/apache/xmlbeans/metadata/system/apiCompile/atypedb57type.xsb");
        expBinType.add("org/apache/xmlbeans/metadata/system/apiCompile/elname429edoctype.xsb");
        expBinType.add("org/apache/xmlbeans/metadata/system/apiCompile/elnameelement.xsb");
        expBinType.add("org/apache/xmlbeans/metadata/system/apiCompile/index.xsb");
        expBinType.add("org/apache/xmlbeans/metadata/element/http_3A_2F_2Fbaz/elName.xsb");
        expBinType.add("org/apache/xmlbeans/metadata/type/http_3A_2F_2Fbaz/aType.xsb");
        expBinType.add("org/apache/xmlbeans/metadata/namespace/http_3A_2F_2Fbaz/xmlns.xsb");
        expBinType.add("org/apache/xmlbeans/metadata/javaname/baz/ElNameDocument.xsb");
        expBinType.add("org/apache/xmlbeans/metadata/javaname/baz/AType.xsb");
        expBinType.add("org/apache/xmlbeans/metadata/system/apiCompile/TypeSystemHolder.class");

        expSrcType.add("baz.AType");
        expSrcType.add("baz.impl.ATypeImpl");
        expSrcType.add("baz.ElNameDocument");
        expSrcType.add("baz.impl.ElNameDocumentImpl");

        xm_opts.setErrorListener(xm_errors);
        xm_opts.setSavePrettyPrint();
    }

    @After
    public void tearDown() throws Exception {
        if (xm_errors.size() > 0)
            xm_errors.clear();
    }

    @Test
    public void test_Filer_compilation() throws Exception
    {
        XmlObject obj1 = XmlObject.Factory.parse(forXsd);
        XmlObject[] schemas = new XmlObject[]{obj1};

        TestFiler f = new TestFiler();//FilerImpl(fClass, fSrc, repackage, true, false);
        SchemaTypeSystem apiSts = XmlBeans.compileXmlBeans("apiCompile", null,
                schemas, null, XmlBeans.getBuiltinTypeSystem(), f, xm_opts);


        for (int i = 0; i < apiSts.globalElements().length; i++) {
            System.out.println("El-" + apiSts.globalElements()[i].getName());
        }
        for (int i = 0; i < apiSts.globalTypes().length; i++) {
            System.out.println("Type-" + apiSts.globalTypes()[i].getBaseType());
        }

        //apiSts = XmlBeans.compileXmlBeans("apiCompile", null,
        //        schemas, null, XmlBeans.getBuiltinTypeSystem(), f, xm_opts);

        if (!f.isCreateBinaryFile())
            throw new Exception("Binary File method not invoked");
        if (!f.isCreateSourceFile())
            throw new Exception("Source File method not invoked");

        System.out.println("BIN");
        CompileCommon.comparefNameVectors(f.getBinFileVec(), expBinType);
        System.out.println("SRC");
        CompileCommon.comparefNameVectors(f.getSrcFileVec(), expSrcType);

    }

    /**
     * Verify Partial SOM cannot be saved to file system
     */
    @Test
    public void test_sts_noSave() throws Exception
    {
        XmlObject obj1 = XmlObject.Factory.parse(forXsd);
        XmlObject[] schemas = new XmlObject[]{obj1};
        XmlObject obj2 = XmlObject.Factory.parse(incrXsd);
        XmlObject[] schemas2 = new XmlObject[]{obj2};
        XmlObject obj3 = XmlObject.Factory.parse(errXsd);
        XmlObject[] schemas3 = new XmlObject[]{obj3};

        SchemaTypeSystem sts;
        TestFiler f = new TestFiler();
        ArrayList err = new ArrayList();
        XmlOptions opt = new XmlOptions().setErrorListener(err);
        opt.setCompilePartialTypesystem();

        try {
            // since you can't save a partial SOM, don't bother passing in a Filer
            sts = XmlBeans.compileXmlBeans(null,
                    null, schemas3, null,
                    XmlBeans.getBuiltinTypeSystem(), null, opt);
            boolean psom_expError = false;
            // print out the recovered xm_errors
            if (!err.isEmpty()) {
                System.out.println("Schema invalid: partial schema type system recovered");
                for (Iterator i = err.iterator(); i.hasNext();) {
                    XmlError xErr = (XmlError) i.next();
                    System.out.println(xErr);

                    if ((xErr.getErrorCode().compareTo("src-resolve") == 0) &&
                            (xErr.getMessage().compareTo("type 'bType@http://baz' not found.") ==
                            0))
                        psom_expError = true;
                }
            }
            if (!psom_expError)
                throw new Exception("Error Code was not as Expected");

        } catch (XmlException e) {
            //The above case should be recoverable so
            // spit out debug statement and throw the error
            System.out.println("Schema invalid: couldn't recover from xm_errors");
            if (err.isEmpty())
                System.err.println(e.getMessage());
            else
                for (Iterator i = err.iterator(); i.hasNext();)
                    System.err.println(i.next());
            throw e;
        }

        assertTrue("Expected partial schema type system", ((SchemaTypeSystemImpl)sts).isIncomplete());


        //call some stupid methods on STS
        printSTS(sts);

        // Check using saveToDirectory on Partial SOM
        File tempDir = null;
        try {
            //setUp outputDirectory
            tempDir = new File(OUTPUTROOT, "psom_save");
            tempDir.mkdirs();
            tempDir.deleteOnExit();
            assertEquals("Output Directory Init needed to be empty", 0, tempDir.listFiles().length);

            //This should not Work
            sts.saveToDirectory(tempDir);
            fail("Expected IllegalStateException");
        } catch (IllegalStateException e) {
            // ok
            System.out.println("sts.saveToDirectory() threw IllegalStateException as expected");
        }

        //make sure nothing was written
        assertEquals("Partial SOM output dir needed to be empty", 0, tempDir.listFiles().length);

        // Check using save(Filer) on Partial SOM
        TestFiler tf = null;
        try {
            //setUp outputDirectory
            tf = new TestFiler();
            assertEquals("Filer Source should have been size 0", 0, tf.getBinFileVec().size());

            //This should not Work
            sts.save(tf);
            fail("Expected IllegalStateException");
        } catch (IllegalStateException e) {
            // ok
            System.out.println("sts.save() threw IllegalStateException as expected");
        }

        //make sure nothing was written
        assertTrue("Filer -Bin- Partial SOM " +
            "output dir needed to be empty",
            tf.getBinFileVec().size() == 0);
        assertTrue("Filer -SRC- Partial SOM " +
            "output dir needed to be empty",
            tf.getSrcFileVec().size() == 0);

        assertFalse("Filer Create Source File " +
            "method should not have been invoked",
            tf.isCreateSourceFile());

        assertFalse("Filer Create Binary File " +
            "method should not have been invoked",
            tf.isCreateBinaryFile());

        // Check using filer in partial SOM compilation
        try {
            tf = new TestFiler();

            assertTrue("Filer Source should have been size 0",
                    tf.getBinFileVec().size() == 0);

            //reset data
            sts = null;
            err.clear();

            //filer methods on partial SOM should not be returned
            sts = XmlBeans.compileXmlBeans(null,
                    null, schemas3, null,
                    XmlBeans.getBuiltinTypeSystem(), tf, opt);

            assertTrue("Errors was not empty", !err.isEmpty());
            //make sure nothing was written
            assertTrue("Filer -Bin- Partial SOM " +
                    "output dir needed to be empty",
                    tf.getBinFileVec().size() == 0);
            assertTrue("Filer -SRC- Partial SOM " +
                    "output dir needed to be empty",
                    tf.getSrcFileVec().size() == 0);

            assertFalse("Filer Create Source File " +
                    "method should not have been invoked",
                    tf.isCreateSourceFile());

            assertFalse("Filer Create Binary File " +
                    "method should not have been invoked",
                    tf.isCreateBinaryFile());
        } catch (Exception e) {
            throw e;
        }


        System.out.println("Save Verification passed");

    }

    /**
     * ensure that entry point properly handles
     * different configs with null values
     */
    @Test
    public void test_entrypoint_nullVals() throws Exception
    {
        XmlObject obj1 = XmlObject.Factory.parse(forXsd);
        XmlObject[] schemas = new XmlObject[]{obj1};

        TestFiler f = new TestFiler();

        SchemaTypeSystem apiSts = XmlBeans.compileXmlBeans(null, null,
                schemas, null, XmlBeans.getBuiltinTypeSystem(), null, null);
        System.out.println("Name: " + apiSts.getName());
        printSTS(apiSts);

        apiSts = XmlBeans.compileXmlBeans(null, null,
                null, null, XmlBeans.getBuiltinTypeSystem(), null, null);
        printSTS(apiSts);

        boolean iArgExThrown = false;
        try {
            apiSts = XmlBeans.compileXmlBeans(null, null,
                    null, null, null, null, null);
            printSTS(apiSts);

        } catch (IllegalArgumentException iaEx) {
            iArgExThrown = true;
            System.err.println(iaEx.getMessage());
        }

        // svn revision 160341. SchemaTypeLoader is not expected to non null any more. All params can be null
        assertFalse(iArgExThrown);

        iArgExThrown = false;
        try {
            apiSts = XmlBeans.compileXmlBeans(null, null,
                    schemas, null, null, null, null);
            printSTS(apiSts);
        } catch (IllegalArgumentException iaEx) {
            iArgExThrown = true;
            System.err.println(iaEx.getMessage());
        }

        // svn revision 160341. SchemaTypeLoader is not expected to non null any more
        assertFalse(iArgExThrown);

    }

}
