/******************************************
 * Name: MenuElement
 * 
 * Copyright: ISET e.V.
 ******************************************/
package bemi.userinterface_mvc;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.*;

import org.eclipse.equinox.jsp.jasper.JspServlet;
import org.osgi.framework.*;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.NamespaceException;

import uitestbundle.UITest;

import bemi.util.Logger;
import bemi.util.ResourceExtractor;

/**
 * @author Heiko Waldschmidt
 * @version: %I%, %G% %U%
 */
public class Registry {
	
	public final static String SERVLET_STARTPATTERN = "ServletMap";
	public final static String JSP_STARTPATTERN = "JSPMap";
	public final static String WEB_RESOURCE_STARTPATTERN ="WebResourceMap";
	
	Set<Bundle> activated = new HashSet<Bundle>();
	
	/*< String for alias */
	Map<String, MenuElement> mainMenuElements = new ConcurrentHashMap<String, MenuElement>();
	UserInterface ui = null;
	
	public Registry(UserInterface ui){
		this.ui = ui;
	}
	
	public Map<String, MenuElement> getMainMenuElements(){
		return mainMenuElements;
	}

	public void register(Bundle bundle) {
		synchronized (activated) {
			if (activated.contains(bundle))
				return;
		}
		Map<String, _MenuElement> clauses = getClauses(bundle, SERVLET_STARTPATTERN);

		for (Map.Entry<String, _MenuElement> entry : clauses.entrySet()) {
			try {
				String alias = entry.getKey();
				String name = entry.getValue().name;
				registerServlet(bundle, alias, name);
				registerForMainMenu(entry.getValue());
			} catch (Throwable t) {
				ui.getLogger().log(Logger.LOG_ERROR,
						"[extender] Activating servlet from "
								+ bundle.getLocation(), t);
			}
		}
		
		clauses = getClauses(bundle, JSP_STARTPATTERN);
		for (Map.Entry<String, _MenuElement> entry : clauses.entrySet()) {
			try {
				String alias = entry.getKey();
				String name = entry.getValue().name;
				registerJSP(bundle, alias, name);
				registerForMainMenu(entry.getValue());
			} catch (Throwable t) {
				ui.getLogger().log(Logger.LOG_ERROR,
						"[extender] Activating servlet from "
								+ bundle.getLocation(), t);
			}
		}
		
		clauses = getClauses(bundle, WEB_RESOURCE_STARTPATTERN);
		for (Map.Entry<String, _MenuElement> entry : clauses.entrySet()) {
			try {
				String alias = entry.getKey();
				String name = entry.getValue().name;
				registerWebResource(bundle, alias, name);
				registerForMainMenu(entry.getValue());
			} catch (Throwable t) {
				ui.getLogger().log(Logger.LOG_ERROR,
						"[extender] Activating servlet from "
								+ bundle.getLocation(), t);
			}
		}
		synchronized (activated) {
			activated.add(bundle);
		}
	}
	
	private void registerWebResource(Bundle bundle, String alias, String name)
			throws NamespaceException, IOException {
		if (!alias.startsWith("/"))
			throw new IllegalArgumentException("Alias must start with / : "
					+ alias);
//		URL u = bundle.getResource(name);
//		System.out.println("URL: " + u);
//		System.out.println("alias: " + alias);
//		System.out.println("bundleEntry: " + bundle.getEntry(name));
//		System.out.println("bundleLoc: " + bundle.getLocation());
//		System.out.println(bundle.getBundleContext().getDataFile(name));
//		InputStream is;
//		
//		FileOutputStream fos;
//		try{
//			is = u.openStream();
//			//fos = new FileOutputStream(outFile);
//			byte[] buf = new byte[2048];
//			int bytesRead = 0;
//			while ((bytesRead = is.read(buf))!=-1)
//				System.out.write(buf, 0, bytesRead);
//			System.out.flush();
//			//ui.getHTTPService().createDefaultHttpContext().
//			ui.getHTTPService().registerResources(
//					"/html",
//					"/web2/html",
//					null);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		ResourceExtractor.extractSingleResource(
//				bundle.getBundleContext(),
//				name,
//				name,
//				ui.getLogger()
//		);
		
		HttpContext httpContext = ui.uitest.getHttpContext();
		ui.getHttpService().registerResources(alias, name, httpContext);
		
//		JspServlet jspServlet = new JspServlet(bundle, "/web2/html", "/html");
//		try {
//			ui.getHTTPService().registerServlet(alias,
//					jspServlet, null, null);
//		} catch (ServletException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		ui.getHTTPService().registerResources(alias, name, null);
	}
	
	private void registerJSP(Bundle bundle, String alias, String JSPName)
			throws ServletException, NamespaceException{
		if (!alias.startsWith("/"))
			throw new IllegalArgumentException("Alias must start with / : "
					+ alias);
		JspServlet jspServlet = new JspServlet(bundle, JSPName, alias);
		ui.getHttpService().registerServlet(alias,
				jspServlet, null, null);
	}

	private void registerForMainMenu(_MenuElement _menuElement){
		if (_menuElement.isMenuElement){
			mainMenuElements.put(_menuElement.alias,
					_menuElement.toMenuElement()
			);			
		}
	}
	
	private void registerServlet(Bundle bundle, String alias, String className)
			throws ClassNotFoundException, InstantiationException, IllegalAccessException,
			ServletException, NamespaceException {
		if (!alias.startsWith("/"))
			throw new IllegalArgumentException("Alias must start with / : "
					+ alias);

		Class clazz = bundle.loadClass(className);
		if (clazz != null) {
			HttpServlet servlet = (HttpServlet) clazz.newInstance();
			ui.getHttpService().registerServlet(
					alias,
					servlet,
					null,
					null
			);
		} else
			throw new IllegalArgumentException("Can not find class "
					+ className);
	}
	
	public void unregister(Bundle bundle) {
		synchronized (activated) {
			if (!activated.contains(bundle))
				return;
			activated.remove(bundle);
		}

		Map<String, _MenuElement> clauses = getClauses(bundle, SERVLET_STARTPATTERN);
		for (String alias: clauses.keySet()) {
			ui.getHttpService().unregister(alias);
			mainMenuElements.remove(alias);
		}
		clauses = getClauses(bundle, JSP_STARTPATTERN);
		for (String alias: clauses.keySet()) {
			ui.getHttpService().unregister(alias);
			mainMenuElements.remove(alias);
		}
		clauses = getClauses(bundle, WEB_RESOURCE_STARTPATTERN);
		for (String alias: clauses.keySet()) {
			ui.getHttpService().unregister(alias);
			mainMenuElements.remove(alias);
		}
	}

	private Map<String, _MenuElement> getClauses(Bundle bundle, String startPattern) {
		_MenuElement temp = null;
		Map<String, _MenuElement> map = new HashMap<String, _MenuElement>();
		//"ServletMap"
		String header = (String) bundle.getHeaders().get(startPattern);
		if (header != null) {
			String clauses[] = header.split(",");
			for (int i = 0; i < clauses.length; i++) {
				String parts[] = clauses[i].trim().split("\\s*=\\s*");
				if (parts.length == 3){
					temp = new _MenuElement(bundle, parts[0], parts[1], new Boolean(parts[2]));
					map.put(temp.alias, temp);
				}
			}
		}
		return map;
	}

	public void unregisterAll() {
		for (Bundle bundle: activated) {
			unregister(bundle);
		}
	}
	
	private class _MenuElement extends MenuElement{
		boolean isMenuElement;
		public _MenuElement(Bundle bundle, String alias, String name, boolean isMenuElement){
			super(bundle, alias, name);
			this.isMenuElement = isMenuElement;
		}
		
		public MenuElement toMenuElement(){
			return new MenuElement(this.bundle, this.alias, this.name);
		}
	}
}