/**
 * $id:  $
 */
package org.jvnet.lookout.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Platform;
import org.jvnet.lookout.core.adapter.SearchAdapter;
import org.jvnet.lookout.core.model.SearchResultSource;
import org.jvnet.lookout.core.util.Utilities;
import org.osgi.framework.BundleContext;

/**
 * The main plugin class to be used in the desktop.
 */
public class Plugin extends org.eclipse.core.runtime.Plugin {

    //The shared instance.
	private static Plugin plugin;
	
    //Resource bundle.
	private ResourceBundle resourceBundle;
	
    private Map<String, SearchAdapter> adapters;
    private Map<SearchAdapter, String> adaptersToNames;
    private Map<SearchAdapter, String> adaptersToIds;
    
    private static final String SEARCH_PLUGIN_ID = "org.jvnet.lookout.core";
    private static final String SEARCH_ADAPTER_EXTENTION_POINT_ID = "adapter"; 
    private static final String CLASS_ATTRIBUTE = "class"; 
    private static final String ID_ATTRIBUTE = "id"; 
    private static final String SEARCH_ENGINE_NAME_ATTRIBUTE = "search-engine-name"; 
    private static final String PLUGIN_ID = Plugin.class.getPackage().getName();
    
	/**
	 * The constructor.
	 */
	public Plugin() {
		super();
		plugin = this;
	}

	/**
	 * This method is called upon plug-in activation
	 */
	public void start(BundleContext context) throws Exception {
		super.start(context);
        
        locateAvailableSearchAdapters();        
	}

    public SearchAdapter getSearchAdapter(String adapterId) {
        return adapters.get(adapterId);
    }
    
    public String getSearchAdapterName(SearchAdapter searchAdapter) {
        return adaptersToNames.get(searchAdapter);
    }
    
    public String getSearchAdapterId(SearchAdapter searchAdapter) {
        return adaptersToIds.get(searchAdapter);
    }
    
    /**
     * Searches for a SearchAdapter that is associated with the provided SearchResultSource.
     * May return null if no SearchAdapter is found to be associated with the provided 
     * SearchResultSource.
     * 
     * @param source
     * @return
     */
    public SearchAdapter getSearchAdapter(SearchResultSource source) {
        
        for (Iterator iter = adapters.keySet().iterator(); iter.hasNext();) {
            SearchAdapter searchAdapter = adapters.get((String) iter.next());            
            if(source.equals(searchAdapter.getSearchResultSource())) {
                return searchAdapter;
            }
        }
        
        return null;
    }
   
    /**
     * Returns the SearchAdapters that this controller is aware of at this 
     * point. Note that not all adapter maybe active.
     *  
     * @return
     */
    public List<SearchAdapter> getSearchAdapters() {        
    	return  new ArrayList<SearchAdapter>(adapters.values());
    }
    
    private void locateAvailableSearchAdapters() {
        
    	int defaultSize = 10; 
        adapters = new HashMap<String, SearchAdapter>(defaultSize);
        adaptersToNames = new HashMap<SearchAdapter, String>(defaultSize);
        adaptersToIds = new HashMap<SearchAdapter, String>(defaultSize);
        
        IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
        
        IExtensionPoint extensionPoint 
        = extensionRegistry.getExtensionPoint(SEARCH_PLUGIN_ID, SEARCH_ADAPTER_EXTENTION_POINT_ID);
        
        IExtension[] extensions = extensionPoint.getExtensions();
        
        for (int i = 0; i < extensions.length; i++) {
            IExtension extension = extensions[i];
            IConfigurationElement[] configurationElements = extension.getConfigurationElements();
            
            for (int j = 0; j < configurationElements.length; j++) {
                IConfigurationElement element = configurationElements[j];

                //Eagerly load these...
                Object adapter = null;
                String adapterId = null;
                String searchEngineName = null;
                
                try {
                    adapter = element.createExecutableExtension(CLASS_ATTRIBUTE);                        
                    adapterId = element.getAttribute(ID_ATTRIBUTE);    
                    searchEngineName = element.getAttribute(SEARCH_ENGINE_NAME_ATTRIBUTE);
                    
                } catch (Exception e) {
                	MultiStatus status = Utilities.createPluginStatus(
                			Plugin.getDefault(),
                			//CXB_EXTERNALIZE
                			"Could not locate " + SearchAdapter.class.getName()+ ": '" + adapterId + "'",
                			IStatus.WARNING,
                			e
                	);                	
                	Plugin.getDefault().getLog().log(status);
                	
                    continue;
                }
                
                if(adapter instanceof SearchAdapter) {
                	SearchAdapter searchAdapter = (SearchAdapter)adapter;
                	
                    adapters.put(adapterId, searchAdapter);
                    adaptersToNames.put(searchAdapter, searchEngineName);
                    adaptersToIds.put(searchAdapter, adapterId);
                } else {
                	MultiStatus status = Utilities.createPluginStatus(
                			Plugin.getDefault(),
                			//CXB_EXTERNALIZE
                			"Could not locate " + SearchAdapter.class.getName()+ ": '" + adapterId + "'",
                			IStatus.WARNING,
                			new IllegalArgumentException
                			//CXB_EXTERNALIZE
                			("Class: '" + adapter.getClass().toString() + "' does not implement " + SearchAdapter.class.toString())
                	);                	
                	Plugin.getDefault().getLog().log(status);                	
                }                
            }            
        }
    }
        
	/**
	 * This method is called when the plug-in is stopped
	 */
	public void stop(BundleContext context) throws Exception {
		//Clear references...
        adapters = null;
        plugin = null;
        resourceBundle = null;
    
        super.stop(context);
	}

	/**
	 * Returns the shared instance.
	 */
	public static Plugin getDefault() {
		return plugin;
	}

	/**
	 * Returns the string from the plugin's resource bundle,
	 * or 'key' if not found.
	 */
	public static String getResourceString(String key) {
		ResourceBundle bundle = Plugin.getDefault().getResourceBundle();
		try {
			return (bundle != null) ? bundle.getString(key) : key;
		} catch (MissingResourceException e) {
			return key;
		}
	}

	/**
	 * Returns the plugin's resource bundle,
	 */
	public ResourceBundle getResourceBundle() {
		try {
			if (resourceBundle == null)
				resourceBundle = ResourceBundle.getBundle(PLUGIN_ID + ".PluginResources");
		} catch (MissingResourceException x) {
			resourceBundle = null;
		}
		return resourceBundle;
	}

}
