package net.floodlightcontroller.core.module;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import net.floodlightcontroller.core.test.MockFloodlightProvider;
import net.floodlightcontroller.core.test.MockThreadPoolService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FloodlightTestModuleLoader extends FloodlightModuleLoader {
	protected final static Logger log = LoggerFactory.getLogger(FloodlightTestModuleLoader.class);
	
	// List of default modules to use unless specified otherwise
	public static final Class<? extends IFloodlightModule> DEFAULT_FLOODLIGHT_PRPOVIDER =
			MockFloodlightProvider.class;
	public static final Class<? extends IFloodlightModule> DEFAULT_THREADPOOL =
			MockThreadPoolService.class;
	
	
	protected static final Collection<Class<? extends IFloodlightModule>> DEFAULT_MODULE_LIST;
	
	static {
		DEFAULT_MODULE_LIST = new ArrayList<Class<? extends IFloodlightModule>>();
		DEFAULT_MODULE_LIST.add(DEFAULT_FLOODLIGHT_PRPOVIDER);
		DEFAULT_MODULE_LIST.add(DEFAULT_THREADPOOL);

	}
	
	protected IFloodlightModuleContext fmc;
	
	/**
	 * Adds default modules to the list of modules to load. This is done
	 * in order to avoid the module loader throwing errors about duplicate
	 * modules and neither one is specified by the user.
	 * @param userModules The list of user specified modules to add to.
	 */
	protected void addDefaultModules(Collection<Class<? extends IFloodlightModule>> userModules) {
		Collection<Class<? extends IFloodlightModule>> defaultModules =
				new ArrayList<Class<? extends IFloodlightModule>>(DEFAULT_MODULE_LIST.size());
		defaultModules.addAll(DEFAULT_MODULE_LIST);
		
		Iterator<Class<? extends IFloodlightModule>> modIter = userModules.iterator();
		while (modIter.hasNext()) {
			Class<? extends IFloodlightModule> userMod = modIter.next();
			Iterator<Class<? extends IFloodlightModule>> dmIter = defaultModules.iterator();
			while (dmIter.hasNext()) {
				Class<? extends IFloodlightModule> dmMod = dmIter.next();
				Collection<Class<? extends IFloodlightService>> userModServs;
				Collection<Class<? extends IFloodlightService>> dmModServs;
				try {
					dmModServs = dmMod.newInstance().getModuleServices();
					userModServs = userMod.newInstance().getModuleServices();
				} catch (InstantiationException e) {
					log.error(e.getMessage());
					break;
				} catch (IllegalAccessException e) {
					log.error(e.getMessage());
					break;
				}
				
				// If either of these are null continue as they have no services
				if (dmModServs == null || userModServs == null) continue;
				
				// If the user supplied modules has a service
				// that is in the default module list we remove
				// the default module from the list.
				boolean shouldBreak = false;
				Iterator<Class<? extends IFloodlightService>> userModServsIter 
					= userModServs.iterator();
				while (userModServsIter.hasNext()) {
					Class<? extends IFloodlightService> userModServIntf = userModServsIter.next();
					Iterator<Class<? extends IFloodlightService>> dmModsServsIter 
						= dmModServs.iterator();
					while (dmModsServsIter.hasNext()) {
						Class<? extends IFloodlightService> dmModServIntf 
							= dmModsServsIter.next();
						
						if (dmModServIntf.getCanonicalName().equals(
								userModServIntf.getCanonicalName())) {
							logger.debug("Removing default module {} because it was " +
									"overriden by an explicitly specified module",
									dmModServIntf.getCanonicalName());
							dmIter.remove();
							shouldBreak = true;
							break;
						}
					}
					if (shouldBreak) break;
				}
				if (shouldBreak) break;
			}
		}
		
		// Append the remaining default modules to the user specified ones.
		// This avoids the module loader throwing duplicate module errors.
		userModules.addAll(defaultModules);
		log.debug("Using module set " + userModules.toString());
	}
	
	/**
	 * Sets up all modules and their dependencies.
	 * @param modules The list of modules that the user wants to load.
	 * @param mockedServices The list of services that will be mocked. Any
	 * module that provides this service will not be loaded.
	 */
	public void setupModules(Collection<Class<? extends IFloodlightModule>> modules,
			Collection<IFloodlightService> mockedServices) {
		addDefaultModules(modules);
		Collection<String> modulesAsString = new ArrayList<String>();
		for (Class<? extends IFloodlightModule> m : modules) {
			modulesAsString.add(m.getCanonicalName());
		}
		
		try {
			fmc = loadModulesFromList(modulesAsString, null, mockedServices);
		} catch (FloodlightModuleException e) {
			log.error(e.getMessage());
		}
	}
	
	/**
	 * Gets the inited/started instance of a module from the context.
	 * @param ifl The name if the module to get, i.e. "LearningSwitch.class".
	 * @return The inited/started instance of the module.
	 */
	public IFloodlightModule getModuleByName(Class<? extends IFloodlightModule> ifl) {
		Collection<IFloodlightModule> modules = fmc.getAllModules();
		for (IFloodlightModule m : modules) {
			if (ifl.getCanonicalName().equals(m.getClass().getCanonicalName())) {
				return m;
			}
		}
		return null;
	}
	
	/**
	 * Gets an inited/started instance of a service from the context.
	 * @param ifs The name of the service to get, i.e. "ITopologyService.class".
	 * @return The inited/started instance of the service from teh context.
	 */
	public IFloodlightService getModuleByService(Class<? extends IFloodlightService> ifs) {
		Collection<IFloodlightModule> modules = fmc.getAllModules();
		for (IFloodlightModule m : modules) {
			Collection<Class<? extends IFloodlightService>> mServs = m.getModuleServices();
			if (mServs == null) continue;
			for (Class<? extends IFloodlightService> mServClass : mServs) {
				if (mServClass.getCanonicalName().equals(ifs.getCanonicalName())) {
					assert(m instanceof IFloodlightService);
					return (IFloodlightService)m;
				}
			}
		}
		return null;
	}
}
