/*
 * 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 com.screamingcoder.plebeians;

import com.screamingcoder.plebeians.beans.ParametersFactory;
import com.screamingcoder.plebeians.bootstrap.WebBeansBootstrap;
import com.screamingcoder.plebeians.events.Start;
import com.screamingcoder.plebeians.exception.CleanShutdownException;
import java.awt.HeadlessException;
import javax.webbeans.manager.Manager;
import org.jboss.webbeans.CurrentManager;
import org.jboss.webbeans.context.ApplicationContext;
import org.jboss.webbeans.context.DependentContext;
import org.jboss.webbeans.context.beanmap.SimpleBeanMap;

/**
 * This is the main class that should always be called from the command
 * line for a plebeians app. Something like:
 * <code>
 * java -jar MyApp.jar com.screamingcoder.plebeians.StarMain arguments
 * </code>
 * @author pete (at screamingcoder.com)
 */
public class StartMain {

    String[] args;

    public StartMain(String[] commandLineArgs) throws HeadlessException {
        this.args = commandLineArgs;
    }

    public void go() {
        WebBeansBootstrap webBeansBootstrap = new WebBeansBootstrap();
        webBeansBootstrap.boot();

        Manager manager = webBeansBootstrap.getManager();

        // init the bean map for the dependent and application context
        ApplicationContext.INSTANCE.setBeanMap(new SimpleBeanMap());
        manager.addContext(DependentContext.INSTANCE);
        manager.addContext(ApplicationContext.INSTANCE);

        // TODO: I have no idea if this is OK??? The WB spec says that the 
        // dependant scoe is only active when the manager is doing its work.
        // This leaves it open for the whole duration. I guess that's about
        // right since the main bean is in the dependant scope?
        DependentContext.INSTANCE.setActive(true);
        try {
            ParametersFactory paramsFactory = (ParametersFactory) CurrentManager.rootManager().getInstanceByType(ParametersFactory.class);
            paramsFactory.setArgs(this.args);

        } catch (Throwable e) {
            handleException(e);
        } finally {
            // clean up and shut down
            DependentContext.INSTANCE.setActive(false);
        }

        // The main method should be an observer of this event so it gets
        // called automatically by the WebBean manager.
        CurrentManager.rootManager().fireEvent(new Start());

    }

    /**
     * The main method called from the command line. This little puppy
     * will get the ball rolling.
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new StartMain(args).go();
    }

    /**
     * When an exception happens in your main app, you don't want
     * the manager to come down in a screaming heap. Well, not all the time.
     * Sometimes you just want to exit gently. This method will detect such
     * times and behave appropriately.
     * @param e
     */
    private void handleException(Throwable e) {
        // check for a 'special' root cause
        boolean dealtWith = false;
        Throwable cause = e.getCause();
        while (cause != null) {
            if (cause instanceof CleanShutdownException) {
                // This is a request to shut down silently, so swollow it.
                // Hoewver, if there's a message, then print it to stdout
                if (cause.getMessage() != null) {
                    System.out.println(cause.getMessage());
                }
                dealtWith = true;
            }
            cause = cause.getCause();
        }

        if (!dealtWith) {
            e.printStackTrace();
        }
    }
}
