package commons.application;

import basics.application.Binder;
import basics.profiler.Profiler;
import basics.unexpected.Failure;
import basics.utl.ObjectUtl;
import basics.utl.SysUtl;
import commons.application.core.AbstractEngineFactory;
import commons.application.core.EngineInterface;
import commons.application.ctx.Context;
import commons.persistence.PMFactory;
import commons.persistence.PersistenceManager;
import commons.persistence.Storable;
import commons.ui.UIController;
import commons.utl.CtxUtl;

public class Application
{
private static final Application instance = new Application();
private EngineInterface          engine   = null;
private UIController             ui       = null;
// @SuppressWarnings("unchecked")
private Context                  ctx      = null;
private PersistenceManager       pm       = null;
private String                   base     = null;

private Application()
{ /* config here if needed */
}

// ---------------------------------------------------
public static EngineInterface engine()
{
   return instance.engine;
}

@SuppressWarnings("unchecked")
public static void initEngine(Class serviceFactoryClass)
{
   instance.engine = AbstractEngineFactory.getServiceEngine(serviceFactoryClass);
}

// ---------------------------------------------------
public static UIController ui()
{
   if(instance.ui == null)
   {
      UIController ui = (UIController)Binder.createNew(UIController.class);
      if(ui == null)
      {
         SysUtl.trace("No UI bound that implements " + UIController.class.getName());
         throw new Failure("No UI bound that implements " + UIController.class.getName());
      }
      else
         instance.ui = ui;
   }
   return instance.ui;
}

//--new pm
public static void initPM(Context ctx)
{
   instance.pm = PMFactory.getPM();
   instance.base = CtxUtl.storageHome(ctx).getAbsolutePath();
}

public static Object load(Storable<?> template, String name, String extension)
{
   Profiler.resume(GLOBAL.IO_TOKEN);
   Storable<?> result = instance.pm.getPersistent(instance.base, template, name, extension);
   Profiler.stop(GLOBAL.IO_TOKEN);
   Profiler.increment(GLOBAL.IO_TOKEN, 1);
   return result;
}

public static boolean save(Storable<?> object, String name, String extension)
{
   try
   {
      Profiler.resume(GLOBAL.IO_TOKEN);
      instance.pm.makePersistent(instance.base, object, name, extension);
      Profiler.stop(GLOBAL.IO_TOKEN);
      Profiler.increment(GLOBAL.IO_TOKEN, 1);
      return true;
   }
   catch(Throwable t)
   {
   }
   return false;
}

//-----------------
/**
 * Create a new Context and bind to the current thread.
 */
public static void createNewContext()
{
   instance.ctx = new Context();
   SysUtl.trace("New " + ObjectUtl.getId(instance.ctx));
}

/**
 * Get current thread's context
 * @return ctx
 */
public static Context ctx()
{
   return instance.ctx;
}

/**
 * Change current context, associate thread and context
 * @return ctx
 */
public static void cc(Context ctx)
{
   instance.ctx = ctx;
}
}
