/*
 * $RCSfile: RegistryClient.java,v $
 * $Date: 2006/04/28 15:58:59 $
 * $Revision: 1.5 $
 * $Author: xblanc $
 */

/*
 * Copyright (c) 2002-2003 IST-2004-2006-511731 ModelWare - ModelBus.
 * All rights reserved.
 *
 * This software is published under the terms of the ModelBus Software License
 * 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.
 * A copy of ModelBus Software License is provided with this distribution in
 * doc/LICENSE.txt file.
 */

/*
 * RegistryClient.java 
 * 
 * @author Prawee Sriplakich, Andrey Sadovykh (LIP6)
 * @version $Revision: 1.5 $ $Date: 2006/04/28 15:58:59 $
 */
package org.eclipse.mddi.modelbus.adapter.infrastructure.registry;

import java.io.IOException;
import java.net.URL;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

import org.apache.axis.AxisFault;
import org.apache.log4j.Logger;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.mddi.modelbus.adapter.infrastructure.LoggerConfigurator;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.GlobalResourceRegistry;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.ModelBusResourceSet;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.ModelUtil;
import org.eclipse.mddi.modelbus.adapter.infrastructure.registry.ws.AlreadyRegistered;
import org.eclipse.mddi.modelbus.adapter.infrastructure.registry.ws.WebRegistry;
import org.eclipse.mddi.modelbus.adapter.infrastructure.registry.ws.WebRegistryServiceLocator;
import org.eclipse.mddi.modelbus.adapter.infrastructure.serialize.emf_xmi.Emf2XmiConversion;
import org.eclipse.mddi.modelbus.adapter.infrastructure.serialize.emf_xmi.Xmi2EmfConversion;
import org.eclipse.mddi.modelbus.description.abstract_.ModelingServiceInterface;
import org.eclipse.mddi.modelbus.description.concrete.Tool;

/**
 * 
 * RegistryClient provides the communication between the Adapter and Registry *
 * 
 * @author Prawee Sriplakich, Andrey Sadovykh (LIP6)
 *  
 */
public class RegistryClient {

    String registry_location;

    WebRegistry registry;

    private static Logger logger = Logger.getLogger(RegistryClient.class);

    public RegistryClient(String _registry_location)
            throws RegistryNotAvailableException {
        LoggerConfigurator.configure();
        try {
            registry_location = _registry_location;
            WebRegistryServiceLocator loc = new WebRegistryServiceLocator();
            registry = loc.getWebRegistry(new URL(registry_location));
        } catch (Exception e) {
            throw new RegistryNotAvailableException(
                    "URL= " + registry_location, e);
        }
    }

    /**
     * set of Tool objects. Local cache of data from Registry
     */
    Collection tools = null;

    public Tool lookupToolByModelingService(String serviceName,
            ToolSelectionStrategy selector)
            throws RegistryNotAvailableException {

        // optimize performance by calling loadDescriptionsFromRegistry() less
        // often.
        // first we try to look in cach
        // if not found, we refresh the cach by loading from Registry
        Tool t;
        //try local tools
        t = selector.selectTool(serviceName, null);
        if (t != null)
            return t;
        //otherwise lookup cache
        if (tools != null)
            t = selector.selectTool(serviceName, tools);
        if (t != null)
            return t;
        //otherwise lookup again the registry
        loadDescriptionsFromRegistry();
        t = selector.selectTool(serviceName, tools);
        return t;
    }

    /**
     * 
     * getCachedToolDescription
     * 
     * @return a collection of "...modelbus.description.concrete.Tool" objects
     * @throws RegistryNotAvailableException
     * 
     *  
     */
    public Collection getCachedToolDescription()
            throws RegistryNotAvailableException {
        if (tools == null) {
            loadDescriptionsFromRegistry();
        }
        return tools;

    }

    public void loadDescriptionsFromRegistry()
            throws RegistryNotAvailableException {

        tools = new HashSet();
        try {
            String[] results;
            Collection col;
            results = registry.lookupAllModelingServiceInterfaces();
            col = toEmf(results);
            Collection modelingServiceInterfaces = ModelUtil.findElementByType(
                    col, "ModelingServiceInterface");
            Iterator it = modelingServiceInterfaces.iterator();
            while (it.hasNext()) {
                ModelingServiceInterface interf = (ModelingServiceInterface) it
                        .next();
                results = registry.lookupToolsByModelingServiceInterface(interf
                        .getName());
                col = toEmf(results);
                Collection _tools = ModelUtil.findElementByType(col, "Tool");
                tools.addAll(_tools);
                
                //register all imported meta-models
                registerResources(_tools);
            }
        } catch (Exception e) {
            if (e instanceof AxisFault) {
                logger.error("Looking up: " + ((AxisFault) e).dumpToString());

                throw new RegistryNotAvailableException("URL= "
                        + registry_location, e);
            } else {
                throw new RegistryNotAvailableException("URL= "
                        + registry_location, e);
            }
        }
    }

    private Collection toEmf(String[] results) throws IOException {
        //DEBUG
        logger.debug("Registry lookup result: ");
        for (int i = 0; i < results.length; i++) {
            logger.debug(results[i]);
        }
        //
        Collection strings = new Vector();
        for (int i = 0; i < results.length; i++) {
            strings.add(results[i]);
        }
        Collection emfobjs = new Xmi2EmfConversion().convertFromStrings(
                strings, false);
        return emfobjs;
    }

    public String registerTool(Tool desc) throws RegistryNotAvailableException {
        String token = new String();
        try {
            Collection emfobjs = new Vector();
            emfobjs.add(desc);
            String s = Emf2XmiConversion.convertToString(emfobjs);
            token = registry.registerTool(s);
            return token;
        } catch (Exception e) {
            if (e instanceof AlreadyRegistered) {
                logger
                        .warn("Registering: Modeling Service is already registred");
                return token;
            } else if (e instanceof AxisFault) {
                logger.error("Registry not available: "
                        + ((AxisFault) e).dumpToString());
                throw new RegistryNotAvailableException("URL= "
                        + registry_location, e);
            } else {
                logger.error("Registry not available");
                throw new RegistryNotAvailableException("URL= "
                        + registry_location, e);
            }
        }
    }

    public void deregisterTool(String token)
            throws RegistryNotAvailableException {
        try {
            registry.deregisterTool(token);
        } catch (Exception e) {
            throw new RegistryNotAvailableException(
                    "URL= " + registry_location, e);
        }
    }

    /**
     * Tests the availability
     * 
     * @return TODO implement
     */
    public boolean isAvailable() {
        return true;
    }

    /**
     * @return Returns the tools.
     */
    public Collection getTools() {
        return tools;
    }

    /**
     * 
     * registerResources Registers all resources associated with tool
     * description. For example, meta-models.
     * 
     * @param tool
     *  
     */
    public static void registerResources(Tool tool) {
        Collection model = new Vector();
        model.add(tool);
        Resource[] res =  ModelUtil.getResourcesFromObjects(model, false, 
                GlobalResourceRegistry.GLOBAL_URI_PREFIX_SET);
        for(int j=0; j<res.length; j++) {

            Resource r = (Resource) res[j];

            for (int i = 0; i < r.getContents().size(); i++) {
                if (r.getContents().get(i) instanceof EPackage) {
                    EPackage p = (EPackage) r.getContents().get(i);
                    logger.debug("Package to register:" + p);
                    ModelBusResourceSet.registerEPackage(p);

                }

            }
        }

    }
    
    /**
     * 
     * registerResources regesters resources for all tools 
     * 
     * @param tools - Collection of Tools to register
     *
     */
    
    public static void registerResources(Collection tools){
        Iterator it = tools.iterator();
        while (it.hasNext()){
            Tool t = (Tool) it.next();
            registerResources(t);
        }
    }
}
