package commons.application.core;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import basics.profiler.NoWatch;
import basics.unexpected.Failure;
import basics.utl.SysUtl;
import commons.cmd.bind;
import commons.cmd.call;
import commons.cmd.cc;
import commons.cmd.cls;
import commons.cmd.del;
import commons.cmd.dir;
import commons.cmd.echo;
import commons.cmd.env;
import commons.cmd.folderprocess;
import commons.cmd.info;
import commons.cmd.liststore;
import commons.cmd.ls;
import commons.cmd.newbean;
import commons.cmd.pl;
import commons.cmd.ps;
import commons.cmd.ren;
import commons.cmd.set;
import commons.cmd.setuser;
import commons.cmd.stop;
import commons.cmd.timer;
import commons.cmd.unset;
import commons.cmd.xmltransform;
public abstract class AbstractEngineFactory
{

@SuppressWarnings("unchecked")
private static final Map<Class, AbstractEngineFactory> environment 
   = Collections.synchronizedMap(new HashMap<Class, AbstractEngineFactory>());
private Engine engine = new Engine();

public abstract void registration ();

// called by derived class for registering id - service pairs. +++
public void register (Command service)
{
   service.signContract();
   engine.register(service);
   service.engine = engine;
}

/**
 * wrapper method, switching off the profiler (for system methods)
 */
private static final void register (AbstractEngineFactory factory, Command cmd)
{
   NoWatch.add(cmd.getId());
   factory.register(cmd);
}

private static final void registerSystemServices (AbstractEngineFactory factory)
{
   register(factory, new stop());
   register(factory, new echo());
   register(factory, new set());
   register(factory, new newbean());
   register(factory, new env());
   register(factory, new setuser());
   register(factory, new unset());
   register(factory, new cls());
   register(factory, new ren());
   register(factory, new cc());
   register(factory, new dir());
   register(factory, new del());
   register(factory, new ls());
   register(factory, new bind());
   register(factory, new call());
   register(factory, new pl());
   register(factory, new ps());
//   register(factory, new view());
   //   register(factory, new jdb());
   //   register(factory, new jdb$ds());
   //   register(factory, new jdb$createtable());
   //   register(factory, new jdb$close());
   //   register(factory, new jdb$execute());
   //   register(factory, new jdb$update());
   //   register(factory, new jdb$connect());
   //   register(factory, new jdb$query());
   // register(factory, new db4oopen(new db4oclose(), null));
   // register(factory, new db4oclose());
   register(factory, new xmltransform());
   register(factory, new folderprocess());
   register(factory, new liststore());
//   register(factory, new metaadjust());
   register(factory, new timer());
   register(factory, new info());
//   register(factory, new dbdisconnect());
   // ...
   SysUtl.trace("Registered " + factory.engine.registry.size() + " system services.");
}

@SuppressWarnings("unchecked")
public static Engine getServiceEngine (Class serviceFactoryClass)
{
   AbstractEngineFactory factory = null;
   synchronized (environment)
   {
      factory = (AbstractEngineFactory) environment.get(serviceFactoryClass);
      if (factory == null)
      {
         factory = newFactory(serviceFactoryClass);
         if (factory == null) { throw new Failure("Error loading: " + serviceFactoryClass); }
         // ------------------------!
         // OsUtl.trace("Start service registration, factory: " +
         // factory.getClass().getSimpleName());
         factory.registration();
         // ------------------------!
         environment.put(serviceFactoryClass, factory);
      }
   }
   registerSystemServices(factory);
   return factory.engine;
}

@SuppressWarnings("unchecked")
private synchronized static AbstractEngineFactory newFactory (Class clazz)
{
   AbstractEngineFactory instance = null;
   try
   {
      instance = (AbstractEngineFactory) clazz.newInstance();
   }
   catch (IllegalAccessException e)
   {
      throw new Failure("No access: " + clazz.getName());
   }
   catch (InstantiationException e)
   {
      throw new Failure("No instance: " + clazz.getName());
   }
   return instance;
}
}
