/*
 *  Copyright (C) 2007  Takashi Kasuya <kasuya@sfc.keio.ac.jp>
 *
 * This library is free software; you can redistribute it and/or
 *　modify it under the terms of the GNU Lesser General Public
 *　License as published by the Free Software Foundation; either
 *　version 2.1 of the License, or (at your option) any later version.
 *　This library is distributed in the hope that it will be useful,
 *　but WITHOUT ANY WARRANTY; without even the implied warranty of
 *　MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *　Lesser General Public License for more details.
 *
 *　You should have received a copy of the GNU Lesser General Public
 *　License along with this library; if not, write to the Free Software
 *　Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

package jp.ac.naka.ec;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import javax.sip.address.SipURI;

import jp.ac.naka.ec.db.TupleSpaceAdapter;
import jp.ac.naka.ec.entity.Entity;
import jp.ac.naka.ec.entity.EntityContainer;
import jp.ac.naka.ec.entity.EntityContainerImpl;
import jp.ac.naka.ec.entity.EntityImpl;
import jp.ac.naka.ec.sip.SipCore;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.PropertyConfigurator;

/**
 * EntityContainerのラッパークラス。
 * @author Takashi Kasuya
 * 
 */
public class EntityCollaborator extends EntityImpl{
	
	private static Log logger = LogFactory.getLog(EntityCollaborator.class);
	private EntityContainer container;
	
	private static EntityCollaborator instance = new EntityCollaborator();
	private ArrayList<Plugin> plugins = new ArrayList<Plugin>();
	private EventDispatcher dispatcher;
	
	public static String sip_properties = "config/sip.properties";
	public static String log4j_properties = "config/log4j.properties";
	public static String base = ".";
	
	static {
		PropertyConfigurator.configure(base + "/" + log4j_properties);
	}
	
	private EntityCollaborator() {}
	
	
	public static EntityCollaborator getInstance() {
		
		SipCore core = SipCore.getInstance();
		try {
			core.initialize(base + "/" + sip_properties);
		} catch (Exception e) {
			e.printStackTrace();
			logger.warn("Error while initiating SIP setting.", e);
		}
		instance.init(null, core);
		return instance;
	}
	/**
	 * 
	 * @param config
	 * @return ec
	 */
	public static EntityCollaborator getInstance(Configuration config) {
		
		SipCore core = SipCore.getInstance();
		try {
			core.initialize(base + "/" + sip_properties);
		} catch (Exception e) {
			e.printStackTrace();
			logger.warn("Error while initiating SIP setting.", e);
		}
		instance.init(config, core);
		return instance;
	}
	
	/**
	 * ポートの指定
	 * @param port
	 * @return
	 */
	public static EntityCollaborator getInstance(int port) {
		
		SipCore core = SipCore.getInstance();
		try {
			core.initialize(port, base + "/" + sip_properties);
		} catch (Exception e) {
			e.printStackTrace();
			logger.warn("Error while initiating SIP setting.", e);
		}
		instance.init(null, core);
		return instance;
	}
	
	private void init(Configuration config, SipCore core) {
		dispatcher = TupleSpaceAdapter.getInstance();;
		PropertyConfigurator.configure(base + "/" + log4j_properties);
		container = new EntityContainerImpl(core.getURI());
		core.setEntityContainer(container);
		dispatcher.addEntityListener(container);
		//dispatcher.addEntityListener(SipCore.getInstance().listener);
	}

	private static void loadJars(String base) throws  IOException {
		//PluginClassLoader loader = PluginClassLoader.getClassLoader();
		// lib以下を参照
		File folder = new File("lib");
		if (!folder.exists() || !folder.isDirectory()) {
			folder.mkdir();
		}
		File[] jars = folder.listFiles(new FileFilter() {
			public boolean accept(File pathname) {
				// CVSは除く
				if (pathname.getName().equals("CVS"))
					return false;
				return (pathname.getName().indexOf(".jar") != -1);
			}
		});
		for (File jar : jars) {
			String jarfile = jar.getAbsolutePath();
			PluginClassLoader.addJarFile(jarfile);
		}
	}


	/**
	 * 親ノードの設定を行う。
	 * @param uri
	 */
	public void setParentNode(EntityContainer node) {
		container.setParent(node);
	}

	/**
	 * 親ノードの設定を文字列で行う。
	 * @param uri
	 */
	public void setParentURI(String uri) {
		SipCore core  = SipCore.getInstance();
		SipURI sip_uri = core.createURI(uri);
		EntityContainer parent = new EntityContainerImpl(sip_uri);
		container.setParent(parent);
	}
	
	/**
	 * 親ノードが設定されているか。
	 * @return flag 
	 */
	public boolean hasParentNode() {
		return container.hasParent();
	}

	/**
	 * EntityContainerが保持するEntityの追加
	 * @param btn
	 */
	public void addEntity(Entity e) {
		SipCore core = SipCore.getInstance();
		String host = core.getURI().getHost();
		int port = core.getURI().getPort();
		String name = e.getName();
		name = (name != null) ? name : e.getClass().getSimpleName();
		SipURI e_uri = core.createURI("sip:" + name + "@" + host
				+ ":" + port);
		e.setParent(container);
		e.setURI(e_uri);
		e.setName(name);
		Location location = container.getLocation();
		// 初期位置はコンテナの位置
		if (location != null) {
			e.setLocation(location);
		}
		
		container.addEntity(e);
		//logger.info("Added new Entity " + e.getName() + " successfully.");
	}
	
	/**
	 * 
	 * @return entities 保持しているEntityの数
	 */
	public Set<Entity> getEntities () {
		return container.getEntities();
	}

	/**
	 * 
	 * @param plugin
	 * @return a
	 */
	public boolean addPlugin(Plugin plugin) {
		String name = plugin.getPluginName();
		name = (name != null) ? name : plugin.getClass().getSimpleName(); 
		SipCore core = SipCore.getInstance();
		String host = core.getURI().getHost();
		int port = core.getURI().getPort();
		SipURI uri = core.createURI("sip:" + name + "@" + host
				+ ":" + port);
		plugin.setURI(uri);
		// TODO 仮のソース
		try {
			plugin.init(container);
			dispatcher.addEntityListener(plugin);
			plugins.add(plugin);
			logger.info("Added new Plugin " + name + " successfully.");
			return true;
		} catch (Exception e) {
			logger.warn("Error while adding Plugin :" + name, e);
			return false;
		}
		
	}

	public Set<Plugin> getPlugins() {
		Set<Plugin> set = new HashSet<Plugin>();
		for (Iterator<Plugin> iter = plugins.iterator(); iter.hasNext();) {
			set.add(iter.next());
		}
		return set;
	}


	


	
}
