/*
 * Copyright 2009 OW2 Chameleon
 * 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 org.ow2.chameleon.core;

import java.io.File;

import junit.framework.TestCase;

import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.launch.Framework;
import org.osgi.service.cm.ConfigurationAdmin;

/**
 * Check chameleon starting (API).
 * @author <a href="mailto:chameleon-dev@ow2.org">Chameleon Project Team</a>
 */
public class ChameleonStartTest extends TestCase {

    /**
     * Deletes the load folder if exists.
     * @see junit.framework.TestCase#tearDown()
     */
    public void tearDown() {
        File load = new File("load");
        if (load.exists()) {
            load.delete();
        }

        File cache = new File("chameleon-cache");
        if (cache.exists()) {
            delete(cache);
        }

        try {
            // Wait to be sure that the cache is deleted.
            Thread.sleep(750);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void delete(File f) {
        File[] files = f.listFiles();
        for (int i = 0; i < files.length; i++) {
            File file = files[i];
            if (file.isDirectory()) {
                delete(file);
            } else {
                file.delete();
            }
        }
        f.delete();
    }

    /**
     * Checks with only a core.
     * @throws Exception if something bad happened
     */
    public void testOnlyCoreStart() throws Exception {
        Chameleon chameleon = new Chameleon(Constants.FULL_CORE,
                false, null, null, null,
                null, null);
        assertNotNull(chameleon);
        Framework fmwk = chameleon.start();
        // Check bundles
        assertEquals(fmwk.getBundleContext().getBundles().length,
                CoreActivator.COUNT + 1); // Core + SytemBundle
        // Check that all bundles are resolved
        Bundle[] bundles = fmwk.getBundleContext().getBundles();
        for (int i = 0; i < bundles.length; i++) {
            assertEquals("Check state of " + bundles[i].getSymbolicName(),
                    Bundle.ACTIVE, bundles[i].getState());
        }

        // Check configuration admin
        ServiceReference ref = fmwk.getBundleContext().getServiceReference(
                ConfigurationAdmin.class.getName());
        assertNotNull(ref);
        Object obj = fmwk.getBundleContext().getService(ref);
        assertTrue(obj instanceof ConfigurationAdmin);

        chameleon.stop();
    }

    /**
     * Checks with an incomplete core.
     * @throws Exception if something bad happened
     */
    public void testIncompleteCoreStart() throws Exception {
        Chameleon chameleon = new Chameleon(Constants.INCOMPLETE_CORE, false,
                null, null, null, null, null);
        assertNotNull(chameleon);
        try {
            chameleon.start();
            fail("Incomplete core undetected");
        } catch (Exception e) {
            // OK
        }
    }

    /**
     * Checks with the core and an empty runtime.
     * @throws Exception if something bad happened
     */
    public void testCoreAndEmptyRuntimeStart() throws Exception {
        Chameleon chameleon = new Chameleon(Constants.FULL_CORE, false,
                Constants.NO_BUNDLES, null, null, null, null);
        assertNotNull(chameleon);
        Framework fmwk = chameleon.start();
        // Check bundles
        assertEquals(fmwk.getBundleContext().getBundles().length,
                CoreActivator.COUNT + 1); // Core + SytemBundle
        // Check that all bundles are resolved
        Bundle[] bundles = fmwk.getBundleContext().getBundles();
        for (int i = 0; i < bundles.length; i++) {
            assertEquals("Check state of " + bundles[i].getSymbolicName(),
                    Bundle.ACTIVE, bundles[i].getState());
        }

        // Check configuration admin
        assertNotNull(fmwk.getBundleContext().getServiceReference(
                ConfigurationAdmin.class.getName()));

        chameleon.stop();
    }

    /**
     * Checks with the core and an empty runtime and app.
     * @throws Exception if something bad happened
     */
    public void testCoreAndEmptyRuntimeAndAnEmptyApp() throws Exception {
        Chameleon chameleon = new Chameleon(Constants.FULL_CORE, false,
                Constants.NO_BUNDLES, Constants.NO_BUNDLES, null, null, null);
        assertNotNull(chameleon);
        Framework fmwk = chameleon.start();
        // Check bundles
        assertEquals(fmwk.getBundleContext().getBundles().length,
                CoreActivator.COUNT + 1); // Core + SytemBundle
        // Check that all bundles are resolved
        Bundle[] bundles = fmwk.getBundleContext().getBundles();
        for (int i = 0; i < bundles.length; i++) {
            assertEquals("Check state of " + bundles[i].getSymbolicName(),
                    Bundle.ACTIVE, bundles[i].getState());
        }

        // Check configuration admin
        assertNotNull(fmwk.getBundleContext().getServiceReference(
                ConfigurationAdmin.class.getName()));

        chameleon.stop();
    }

    /**
     * Checks with the core and a runtime and a app containing
     * configuration files.
     * @throws Exception if something bad happened
     */
    public void testCoreAndBundleRuntimeStartAndConfApp() throws Exception {
        Chameleon chameleon = new Chameleon(Constants.FULL_CORE, false,
                Constants.BUNDLES, Constants.CONFIGURATION, null, null, null);
        assertNotNull(chameleon);
        Framework fmwk = chameleon.start();
        // Check bundles
        assertEquals(fmwk.getBundleContext().getBundles().length,
                CoreActivator.COUNT + 1 + 3); // Core + SytemBundle + 3 bundles (2 jars + 1 exploded)
        // Check that all bundles are resolved
        Bundle[] bundles = fmwk.getBundleContext().getBundles();
        for (int i = 0; i < bundles.length; i++) {
            assertEquals("Check state of " + bundles[i].getSymbolicName(),
                    Bundle.ACTIVE, bundles[i].getState());
        }

        // Check configuration admin
        assertNotNull(fmwk.getBundleContext().getServiceReference(
                ConfigurationAdmin.class.getName()));

        chameleon.stop();
    }

    /**
     * Checks with the core and a runtime and app containing
     * both bundles and configuration files.
     * @throws Exception if something bad happened
     */
    public void testCoreAndTwiceBoth() throws Exception {
        Chameleon chameleon = new Chameleon(Constants.FULL_CORE, false,
                Constants.BOTH, Constants.ANOTHER_BOTH, null, null, null);
        assertNotNull(chameleon);
        Framework fmwk = chameleon.start();
        // Check bundles
        assertEquals(fmwk.getBundleContext().getBundles().length,
                CoreActivator.COUNT + 1 + 2); // Core + SytemBundle + 2 bundles
        // Check that all bundles are resolved
        Bundle[] bundles = fmwk.getBundleContext().getBundles();
        for (int i = 0; i < bundles.length; i++) {
            assertEquals("Check state of " + bundles[i].getSymbolicName(),
                    Bundle.ACTIVE, bundles[i].getState());
        }

        // Check configuration admin
        assertNotNull(fmwk.getBundleContext().getServiceReference(
                ConfigurationAdmin.class.getName()));

        chameleon.stop();
    }

    /**
     * Checks file install configuration.
     * @throws Exception if something bad happened
     */
    public void testFileInstallConfiguration() throws Exception {
        Chameleon chameleon = new Chameleon(Constants.FULL_CORE, false,
                Constants.BOTH, Constants.ANOTHER_BOTH, "myfolder", null, null);
        assertNotNull(chameleon);
        Framework fmwk = chameleon.start();
        // Check bundles
        assertEquals(fmwk.getBundleContext().getBundles().length,
                CoreActivator.COUNT + 1 + 2); // Core + SytemBundle + 2 bundles
        // Check that all bundles are resolved
        Bundle[] bundles = fmwk.getBundleContext().getBundles();
        for (int i = 0; i < bundles.length; i++) {
            assertEquals("Check state of " + bundles[i].getSymbolicName(),
                    Bundle.ACTIVE, bundles[i].getState());
        }

        // Check configuration admin
        assertNotNull(fmwk.getBundleContext().getServiceReference(
                ConfigurationAdmin.class.getName()));

        chameleon.stop();
    }

    /**
     * Checks debug mode.
     * @throws Exception if something bad happened
     */
    public void testDebugMode() throws Exception {
        Chameleon chameleon = new Chameleon(Constants.FULL_CORE, true,
                Constants.BOTH, Constants.ANOTHER_BOTH, "myfolder", null, null);
        assertNotNull(chameleon);
        Framework fmwk = chameleon.start();
        // Check bundles
        Bundle[] bundles = fmwk.getBundleContext().getBundles();
        for (int i = 0; i < bundles.length; i++) {
            assertEquals("Check state of " + bundles[i].getSymbolicName(),
                    Bundle.ACTIVE, bundles[i].getState());
        }
        assertEquals(fmwk.getBundleContext().getBundles().length,
                CoreActivator.COUNT + 1 + 2 + + 3 + 1); // Core + SytemBundle + 2
        // bundles + Gogo (3) + Arch

        // Check configuration admin
        assertNotNull(fmwk.getBundleContext().getServiceReference(
                ConfigurationAdmin.class.getName()));

        chameleon.stop();
    }

    /**
     * Checks configuration files.
     * @throws Exception if something bad happened
     */
    public void testWithProperties() throws Exception {
        Chameleon chameleon = new Chameleon(Constants.FULL_CORE, true,
                Constants.BOTH, Constants.ANOTHER_BOTH, "myfolder",
                Constants.CONF_FILE, null);
        assertNotNull(chameleon);
        Framework fmwk = chameleon.start();
        // Check bundles
        Bundle[] bundles = fmwk.getBundleContext().getBundles();
        for (int i = 0; i < bundles.length; i++) {
            assertEquals("Check state of " + bundles[i].getSymbolicName(),
                    Bundle.ACTIVE, bundles[i].getState());
        }
        assertEquals(fmwk.getBundleContext().getBundles().length,
                CoreActivator.COUNT + 1 + 2 + 4); // Core + SytemBundle + 2
        // bundles + Gogo + Arch

        // Check configuration admin
        assertNotNull(fmwk.getBundleContext().getServiceReference(
                ConfigurationAdmin.class.getName()));

        // Check the chameleon-storage file (set by the configuration file
        File cache = new File("chameleon-cache");
        assertTrue(cache.exists());

        chameleon.stop();
        cache.delete();
    }

    /**
     * Checks bad configuration files.
     * @throws Exception if something bad happened
     */
    public void testWithBadProperties() throws Exception {
        try {
            new Chameleon(Constants.FULL_CORE, true, Constants.BOTH,
                    Constants.ANOTHER_BOTH, "myfolder",
                    Constants.CONF_FILE + "2", null);
            fail("Undetected missing props");
        } catch (Exception e) {
            // OK
        }

    }

    /**
     * Checks missing system properties files.
     * @throws Exception if something bad happened
     */
    public void testWithMissingSystemProperties() throws Exception {
        try {
            new Chameleon(Constants.FULL_CORE, true, Constants.BOTH,
                    Constants.ANOTHER_BOTH, "myfolder",
                    Constants.ANOTHER_SYS_FILE + "xxx", null);
            fail("Undetected missing props");
        } catch (Exception e) {
            // OK
        }
    }

    /**
     * Checks configuration files.
     * @throws Exception if something bad happened
     */
    public void testWithSystemProperties() throws Exception {
        Chameleon chameleon = new Chameleon(Constants.FULL_CORE, true,
                Constants.BOTH, Constants.ANOTHER_BOTH, "myfolder",
                null, Constants.SYS_FILE);
        assertNotNull(chameleon);
        Framework fmwk = chameleon.start();
        // Check bundles
        Bundle[] bundles = fmwk.getBundleContext().getBundles();
        for (int i = 0; i < bundles.length; i++) {
            assertEquals("Check state of " + bundles[i].getSymbolicName(),
                    Bundle.ACTIVE, bundles[i].getState());
        }
        assertEquals(fmwk.getBundleContext().getBundles().length,
                CoreActivator.COUNT + 1 + 2 + 4); // Core + SytemBundle + 2
        // bundles + Gogo + Arch

        // Check configuration admin
        assertNotNull(fmwk.getBundleContext().getServiceReference(
                ConfigurationAdmin.class.getName()));

        String p = System.getProperty("org.ow2.chameleon.test");
        assertNotNull(p);
        assertEquals("true", p);

        System.clearProperty("org.ow2.chameleon.test");

        chameleon.stop();
    }


}
