/*
 * 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.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;

/**
 * Test chameleon starting from the command line.
 * @author <a href="mailto:chameleon-dev@ow2.org">Chameleon Project Team</a>
 */
public class ChameleonStartFromCommandLineTest 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();
    }

    /**
     * Tests a start with the core only.
     * @throws Exception something bad happened.
     */
    public void testOnlyCoreStart() throws Exception {

        String[] args = new String[] {"--core=" + Constants.FULL_CORE};

        Chameleon chameleon = Main.createChameleon(args);
        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();
    }


    /**
     * Tests a start with the incomplete core only.
     * @throws Exception something bad happened.
     */
    public void testIncompleteCoreStart() throws Exception {
        String[] args = new String[] {"--core=" + Constants.INCOMPLETE_CORE};

        Chameleon chameleon = Main.createChameleon(args);
        assertNotNull(chameleon);
        try {
            chameleon.start();
            fail("Incomplete core undetected");
        } catch (Exception e) {
            // OK
        }
    }


    /**
     * Tests a start with the core and an empty runtime.
     * @throws Exception something bad happened.
     */
    public void testCoreAndEmptyRuntimeStart() throws Exception {
        String[] args = new String[] {"--runtime=" + Constants.NO_BUNDLES,
                "--core=" + Constants.FULL_CORE};

        Chameleon chameleon = Main.createChameleon(args);
        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();
    }


    /**
     * Tests a start with the core, an empty runtime and an empty application.
     * @throws Exception something bad happened.
     */
    public void testCoreAndEmptyRuntimeAndAnEmptyApp() throws Exception {
        String[] args = new String[] {"--runtime=" + Constants.NO_BUNDLES,
                "--core=" + Constants.FULL_CORE,
                "--app=" + Constants.NO_BUNDLES};

        Chameleon chameleon = Main.createChameleon(args);
        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();
    }


    /**
     * Tests a start with the core a runtime and a configuration folder (app).
     * @throws Exception something bad happened.
     */
    public void testCoreAndBundleRuntimeStartAndConfApp() throws Exception {
        String[] args = new String[] {"--runtime=" + Constants.BUNDLES,
                "--core=" + Constants.FULL_CORE,
                "--app=" + Constants.CONFIGURATION};

        Chameleon chameleon = Main.createChameleon(args);
        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();
    }


    /**
     * Tests a start with the core and an app and runtime with both
     * bundles and configurations.
     * @throws Exception something bad happened.
     */
    public void testCoreAndTwiceBoth() throws Exception {
        String[] args = new String[] {"--runtime=" + Constants.BOTH,
                "--core=" + Constants.FULL_CORE,
                "--app=" + Constants.ANOTHER_BOTH};
        Chameleon chameleon = Main.createChameleon(args);
        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
        ServiceReference ref = fmwk.getBundleContext().getServiceReference(
                ConfigurationAdmin.class.getName());
        assertNotNull(ref);

        ConfigurationAdmin admin = (ConfigurationAdmin) fmwk.getBundleContext().getService(ref);
        Configuration[] list = admin.listConfigurations(null);
        assertNotNull(list);
        assertTrue(list.length != 0);

        for (int i = 0; i < list.length; i++) {
            System.out.println(list[i].getProperties());
        }

        chameleon.stop();
    }

    /**
     * Checks file install configuration.
     * @throws Exception something bad happened.
     */
    public void testFileInstallConfiguration() throws Exception {
        String[] args = new String[] {
                "--deploy=myfolder",
                "--runtime=" + Constants.BOTH,
                "--core=" + Constants.FULL_CORE,
                "--app=" + Constants.ANOTHER_BOTH};

        Chameleon chameleon = Main.createChameleon(args);
        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 something bad happened.
     */
    public void testDebugMode() throws Exception {
        String[] args = new String[] {
                "--deploy=myfolder",
                "--runtime=" + Constants.BOTH,
                "--core=" + Constants.FULL_CORE,
                "--app=" + Constants.ANOTHER_BOTH,
                "--debug"};
        Chameleon chameleon = Main.createChameleon(args);
        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();
    }

    /**
     * Tests a fake folder for application.
     * @throws Exception something bad happened.
     */
    public void testBadApp() throws Exception {
        String[] args = new String[] {
                "--runtime=" + Constants.NO_BUNDLES,
                "--core=" + Constants.FULL_CORE,
                "--app=" + "BAD"};

        try {
            Main.createChameleon(args);
            fail("Incorrect app folder not detected");
        } catch (Exception e) {
            // OK
        }
    }

    /**
     * Tests a fake folder for runtime.
     * @throws Exception something bad happened.
     */
    public void testBadRuntime() throws Exception {
        String[] args = new String[] {
                "--runtime=" + "BAD",
                "--core=" + Constants.FULL_CORE,
                "--app=" + Constants.NO_BUNDLES};

        try {
            Main.createChameleon(args);
            fail("Incorrect app folder not detected");
        } catch (Exception e) {
            // OK
        }
    }

}
