package org.exoplatform.cs.service;

import java.lang.reflect.Method;
import java.util.Map;

import javax.servlet.ServletContext;

import org.picocontainer.Startable;

import org.exoplatform.container.PortalContainer;
import org.exoplatform.container.RootContainer.PortalContainerPostInitTask;
import org.exoplatform.portal.config.DataStorage;
import org.exoplatform.portal.config.UserPortalConfigService;
import org.exoplatform.portal.mop.page.PageService;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.social.core.space.SpaceApplicationConfigPlugin;
import org.exoplatform.social.core.space.spi.SpaceApplicationHandler;
import org.exoplatform.social.core.space.spi.SpaceService;

public class CSHandlerStarter implements Startable {

  private static final Log             LOG = ExoLogger.getLogger(CSHandlerStarter.class);

  private PortalContainer              container;

  private SpaceApplicationConfigPlugin spaceApplicationConfigPlugin;

  public CSHandlerStarter(PortalContainer container) {
    this.container = container;
  }

  @Override
  public void start() {
    LOG.info("Add specific Space handler when container finishes starting");
    PortalContainer.addInitTask(container.getPortalContext(), new PortalContainerPostInitTask() {
      @Override
      public void execute(ServletContext context, PortalContainer portalContainer) {
        addHandlerToSpaceService();
      }
    });
  }

  @Override
  public void stop() {
  }

  public void addHandlerToSpaceService() {
    try {
      SpaceService spaceService = getService(SpaceService.class);
      Method spaceSpaceApplicationHandler = spaceService.getClass().getDeclaredMethod("getSpaceApplicationHandlers");
      spaceSpaceApplicationHandler.setAccessible(true);

      if (spaceApplicationConfigPlugin == null) {
        throw new IllegalStateException("CS Space config is not loaded");
      }

      @SuppressWarnings("unchecked")
      Map<String, SpaceApplicationHandler> map = (Map<String, SpaceApplicationHandler>) spaceSpaceApplicationHandler.invoke(spaceService);
      if (!map.containsKey(CSSpaceApplicationHandler.NAME)) {
        LOG.info("Add specific Space handler");
        CSSpaceApplicationHandler appHandler = new CSSpaceApplicationHandler(getService(SpaceService.class),
                                                                             getService(DataStorage.class),
                                                                             getService(PageService.class),
                                                                             getService(UserPortalConfigService.class));
        appHandler.setSpaceApplicationConfigPlugin(spaceApplicationConfigPlugin);
        map.put(CSSpaceApplicationHandler.NAME, appHandler);
      }
    } catch (Exception e) {
      LOG.error(e);
      throw new IllegalStateException("Can't set specific handler", e);
    }
  }

  public void setSpaceApplicationConfigPlugin(SpaceApplicationConfigPlugin spaceApplicationConfigPlugin) {
    LOG.info("Load CS Space config");
    this.spaceApplicationConfigPlugin = spaceApplicationConfigPlugin;
  }

  public <T> T getService(Class<T> clazz) {
    return (T) container.getComponentInstanceOfType(clazz);
  }

}
