package com.acme.structure;


import com.acme.structure.util.IOUtility;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;


public class ServiceLocator
{
    private InitialContext ictx = null;
    private Map proxyCache = null;

    private static ServiceLocator sl;
    //private static Log logger = LogFactory.getFactory().getInstance(ServiceLocator.class);

    static
    {
        try
        {
            sl = new ServiceLocator();
            //logger.debug("***** ServiceLocator Object Created");
        }
        catch (Exception exc)
        {
            exc.printStackTrace();
            System.err.println(exc.toString());
        }
    }

    private ServiceLocator() throws Exception
    {
        try
        {
            Properties props = IOUtility.loadProperties("/com/accmee/structure/resource/jndiconnection.properties", this.getClass());
            //Properties props = EnvironmentReader.readEnvironmentVariableProps("conf.dir", "jndiconnection.properties");
            ictx = createInitialContext(props);
            proxyCache = Collections.synchronizedMap(new HashMap());
        }
        catch (Exception exc)
        {
            exc.printStackTrace();
            System.out.println(exc.toString());
        }
    }

    private ServiceLocator(InitialContext ictx) throws Exception
    {
        try
        {
            this.ictx = ictx;
            proxyCache = Collections.synchronizedMap(new HashMap());
        }
        catch (Exception exc)
        {
            exc.printStackTrace();
        }
    }

    private static InitialContext createInitialContext(Properties loadedProps) throws NamingException
    {
        //Properties loadedProps = IOUtility.loadProperties("/com/accmee/structure/resource/jndiconnection.properties", ServiceLocator.class);
        String serverType = loadedProps.getProperty("servertype");
        String userName = loadedProps.getProperty("username");
        String password = loadedProps.getProperty("password");
        String providerURL = loadedProps.getProperty("providerurl");
        String initialContextFactory = loadedProps.getProperty("jndicontextfactory");

        Properties confProps = new Properties();

        confProps.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);

        if (userName != null && password != null)
        {
            confProps.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
            confProps.put(Context.SECURITY_PRINCIPAL, userName);
            confProps.put(Context.SECURITY_CREDENTIALS, password);
        }

        if ("weblogic".equals(serverType))
            confProps.put(Context.PROVIDER_URL, providerURL);
        else if ("glassfish".equals(serverType))
        {
            confProps.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
            confProps.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
            confProps.put("org.omg.CORBA.ORBInitialHost", loadedProps.getProperty("org.omg.CORBA.ORBInitialHost"));
            confProps.put("org.omg.CORBA.ORBInitialPort", loadedProps.getProperty("org.omg.CORBA.ORBInitialPort"));
        }

        return new InitialContext(confProps);
    }

    public static ServiceLocator createNewInstance(Properties props) throws Exception
    {
        sl = new ServiceLocator(createInitialContext(props));
        return getInstance();
    }

    public static ServiceLocator getInstance()
    {
        return sl;
    }

    public Object getInitialContextProp(String propName) throws NamingException
    {
        return ictx.getEnvironment().get(propName);
    }

    public InitialContext getInitialContext() throws NamingException
    {
        return ictx;
    }

    public Object getResource(String jndiName) throws NamingException
    {
        return getResource(jndiName, false);
    }

    public Object getResource(Class beanClass) throws NamingException
    {
        String jndiName = beanClass.getSimpleName() + "#" + beanClass.getCanonicalName();
        return getResource(jndiName, false);
    }

    public Object getResource(String mappedName, Class beanClass) throws NamingException
    {
        String jndiName = mappedName + "#" + beanClass.getCanonicalName();
        return getResource(jndiName, false);
    }

    public Object getResource(String jndiName, boolean isLocal) throws NamingException
    {
        Object tempObject = null;

        if (proxyCache != null && proxyCache.containsKey(jndiName))
            return proxyCache.get(jndiName);

        // load proxy object with jndi lookup
        if (ictx != null)
            tempObject = ictx.lookup(jndiName);

        // put it into proxyCache
        if (proxyCache != null)
            proxyCache.put(jndiName, tempObject);

        return tempObject;
    }

}
