/*
 * DefaultApplicationInstanceManager.java  $Revision: 1.6 $  $Date: 2007/10/03 04:39:39 $
 *
 * Copyright (C) 2007 Meldcraft Corporation
 *
 * This file is part of Scaffold.
 * 
 * Scaffold 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, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Scaffold 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.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with Scaffold.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.meldcraft.application.container;

import java.util.HashMap;
import java.util.Map;

import com.meldcraft.application.Application;
import com.meldcraft.application.ApplicationContextEvent;
import com.meldcraft.application.ApplicationContextListener;
import com.meldcraft.util.ConfigurationManager;
import com.meldcraft.util.PropertiesHelper;
import com.meldcraft.util.ReflectUtil;

/**
 * @version $Revision: 1.6 $ $Date: 2007/10/03 04:39:39 $
 * @author Rob Richards
 */
public class DefaultApplicationInstanceManager
    implements ApplicationInstanceManager, ApplicationContextListener
{
// Static variables
// Member variables
    protected Map       mOpenApps = new HashMap();

// Constructors and initialization
    public DefaultApplicationInstanceManager()
    {
    }

// Interface implemenations
    // ApplicationContextListener interface
    public void applicationContextChanged(ApplicationContextEvent e)
    {
        if (e.getKey().equals(Application.APPLICATION_CLOSED_KEY))
        {
            synchronized(mOpenApps)
            {
                mOpenApps.remove(e.getApplicationContext().getApplication());
            }
        }
    }

// Public methods
    public Application[] getAllApplicationInstances()
    {
        synchronized(mOpenApps)
        {
            return (Application[])mOpenApps.keySet().toArray(new Application[0]);
        }
    }

    public Application openApplicationInstance(String appName, Object args)
        throws UnsupportedApplicationException
    {
        Application ret = null;

        try
        {
            synchronized(mOpenApps)
            {
                boolean openExisting = true;
                try
                {
                    openExisting = PropertiesHelper.getBoolean(ConfigurationManager.getConfiguration(Class.forName(appName)), "Application.InstanceManager.openExistingApplication", true);
                }
                catch (Exception e)
                {
                    // ignored
                }

                if (openExisting)
                {
                    ret = openExistingApplication(appName, args);
                }

                if (ret == null)
                {
                    // open new application
                    ret = openApplication(appName, args);
                    mOpenApps.put(ret, new AppPackage(ret, appName, args));
                    ret.getApplicationContext().addApplicationContextListener(this, Application.APPLICATION_CLOSED_KEY);
                }
            }
        }
        catch (Throwable e)
        {
            throw new RuntimeException("Error opening application.", e);
        }

        return ret;
    }

// Protected methods
    protected Application openApplication(String appName, Object args)
        throws Exception
    {
        Application ret = null;

        String defClass = null;
        try
        {
            Class cls = Class.forName(appName);
            if (Application.class.isAssignableFrom(cls))
            {
                defClass = appName;
            }
        }
        catch (ClassNotFoundException e)
        {
        }

        if (defClass == null)
        {
            Map config = ConfigurationManager.getConfiguration("com.meldcraft.application.Application");
            defClass = PropertiesHelper.getString(config, "className", "com.meldcraft.application.swing.DefaultSwingApplication");
        }

        Map config = ConfigurationManager.getConfiguration(appName);
        String className = PropertiesHelper.getString(config, "className", defClass);
        Class cls = Class.forName(className);
        if (!Application.class.isAssignableFrom(cls))
        {
            throw new UnsupportedApplicationException(appName);
        }
        ret = (Application)ReflectUtil.createInstance(cls);
        ret.applicationInitialize(appName);
        ret.applicationOpen(args);

        return ret;
    }

    protected Application openExistingApplication(String name, Object args)
    {
        Application ret = null;

        Object[] apps = mOpenApps.keySet().toArray();

        if (apps != null)
        {
            for (int i=0 ; i < apps.length ; i++)
            {
                AppPackage pkg = (AppPackage)mOpenApps.get(apps[i]);
                String aname = pkg.getName();

                if (aname.equals(name))
                {
                    ret = pkg.getApplication();
                    ret.applicationOpen(args);
                    break;
                }
            }
        }

        return ret;
    }

// Private methods
// Inner classes
    protected static class AppPackage
    {
        private Application     mApp;
        private String          mName;
        private Object          mArgs;

        public AppPackage(Application app, String name, Object args)
        {
            mApp = app;
            mName = name;
            mArgs = args;
        }
        public Application getApplication()
        {
            return mApp;
        }
        public String getName()
        {
            return mName;
        }
        public Object getArgs()
        {
            return mArgs;
        }
    }
}
