/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.aries.blueprint.namespace;

import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.net.URI;
import java.net.URL;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.io.IOException;

import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.Source;
import javax.xml.XMLConstants;

import org.apache.aries.blueprint.NamespaceHandler;
import org.apache.aries.blueprint.container.NamespaceHandlerRegistry;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

/**
 * Default implementation of the NamespaceHandlerRegistry.
 * 
 * This registry will track NamespaceHandler objects in the OSGi registry and make
 * them available, calling listeners when handlers are registered or unregistered.
 *
 * @version $Rev: 964701 $, $Date: 2010-07-16 08:23:10 +0100 (Fri, 16 Jul 2010) $
 */
public class NamespaceHandlerRegistryImpl implements NamespaceHandlerRegistry, ServiceTrackerCustomizer {
    
    public static final URI BLUEPRINT_NAMESPACE = URI.create("http://www.osgi.org/xmlns/blueprint/v1.0.0");

    public static final String NAMESPACE = "osgi.service.blueprint.namespace";

    private static final Logger LOGGER = LoggerFactory.getLogger(NamespaceHandlerRegistryImpl.class);

    private final BundleContext bundleContext;
    private final Map<URI, Set<NamespaceHandler>> handlers;
    private final ServiceTracker tracker;
    private final Map<Map<URI, NamespaceHandler>, Reference<Schema>> schemas = new LRUMap<Map<URI, NamespaceHandler>, Reference<Schema>>(10);
    private SchemaFactory schemaFactory;
    private List<NamespaceHandlerSetImpl> sets;

    public NamespaceHandlerRegistryImpl(BundleContext bundleContext) {
        this.bundleContext = bundleContext;
        handlers = new HashMap<URI, Set<NamespaceHandler>>();
        sets = new ArrayList<NamespaceHandlerSetImpl>();
        tracker = new ServiceTracker(bundleContext, NamespaceHandler.class.getName(), this);
        tracker.open();
    }

    public Object addingService(ServiceReference reference) {
        LOGGER.debug("Adding NamespaceHandler "+reference.toString());
        NamespaceHandler handler = (NamespaceHandler) bundleContext.getService(reference);
        if(handler!=null){
            try {
                Map<String, Object> props = new HashMap<String, Object>();
                for (String name : reference.getPropertyKeys()) {
                    props.put(name, reference.getProperty(name));
                }
                registerHandler(handler, props);
            } catch (Exception e) {
                LOGGER.warn("Error registering NamespaceHandler", e);
            }
        }else{
            LOGGER.warn("Error resolving NamespaceHandler, null Service obtained from tracked ServiceReference {} for bundle {}, ver {}", new Object[]{reference.toString(), reference.getBundle().getSymbolicName(), reference.getBundle().getVersion()});
        }
        return handler;
    }

    public void modifiedService(ServiceReference reference, Object service) {
        removedService(reference, service);
        addingService(reference);
    }

    public void removedService(ServiceReference reference, Object service) {
        try {
            NamespaceHandler handler = (NamespaceHandler) service;
            Map<String, Object> props = new HashMap<String, Object>();
            for (String name : reference.getPropertyKeys()) {
                props.put(name, reference.getProperty(name));
            }
            unregisterHandler(handler, props);
        } catch (Exception e) {
            LOGGER.warn("Error unregistering NamespaceHandler", e);
        }
    }

    public synchronized void registerHandler(NamespaceHandler handler, Map properties) {
        List<URI> namespaces = getNamespaces(properties);
        for (URI uri : namespaces) {
            Set<NamespaceHandler> h = handlers.get(uri);
            if (h == null) {
                h = new HashSet<NamespaceHandler>();
                handlers.put(uri, h);
            }
            if (h.add(handler)) {
                for (NamespaceHandlerSetImpl s : sets) {
                    s.registerHandler(uri, handler);
                }
            }
        }
    }

    public synchronized void unregisterHandler(NamespaceHandler handler, Map properties) {
        List<URI> namespaces = getNamespaces(properties);
        for (URI uri : namespaces) {
            Set<NamespaceHandler> h = handlers.get(uri);
            if (h == null || !h.remove(handler)) {
                continue;
            }
            for (NamespaceHandlerSetImpl s : sets) {
                s.unregisterHandler(uri, handler);
            }
        }
        removeSchemasFor(handler);
    }

    private static List<URI> getNamespaces(Map properties) {
        Object ns = properties != null ? properties.get(NAMESPACE) : null;
        if (ns == null) {
            throw new IllegalArgumentException("NamespaceHandler service does not have an associated " + NAMESPACE + " property defined");
        } else if (ns instanceof URI[]) {
            return Arrays.asList((URI[]) ns);
        } else if (ns instanceof URI) {
            return Collections.singletonList((URI) ns);
        } else if (ns instanceof String) {
            return Collections.singletonList(URI.create((String) ns));
        } else if (ns instanceof String[]) {
            String[] strings = (String[]) ns;
            List<URI> namespaces = new ArrayList<URI>(strings.length);
            for (String string : strings) {
                namespaces.add(URI.create(string));
            }
            return namespaces;
        } else if (ns instanceof Collection) {
            Collection col = (Collection) ns;
            List<URI> namespaces = new ArrayList<URI>(col.size());
            for (Object o : col) {
                namespaces.add(toURI(o));
            }
            return namespaces;
        } else if (ns instanceof Object[]) {
            Object[] array = (Object[]) ns;
            List<URI> namespaces = new ArrayList<URI>(array.length);
            for (Object o : array) {
                namespaces.add(toURI(o));
            }
            return namespaces;
        } else {
            throw new IllegalArgumentException("NamespaceHandler service has an associated " + NAMESPACE + " property defined which can not be converted to an array of URI");
        }
    }

    private static URI toURI(Object o) {
        if (o instanceof URI) {
            return (URI) o;
        } else if (o instanceof String) {
            return URI.create((String) o);
        } else {
            throw new IllegalArgumentException("NamespaceHandler service has an associated " + NAMESPACE + " property defined which can not be converted to an array of URI");
        }
    }
    
    public synchronized NamespaceHandlerSet getNamespaceHandlers(Set<URI> uris, Bundle bundle) {
        NamespaceHandlerSetImpl s = new NamespaceHandlerSetImpl(uris, bundle);
        sets.add(s);
        return s;
    }

    public void destroy() {
        tracker.close();
    }

    public synchronized Schema getSchema(Map<URI, NamespaceHandler> handlers) throws IOException, SAXException {
        Schema schema = null;
        // Find a schema that can handle all the requested namespaces
        // If it contains additional namespaces, it should not be a problem since
        // they won't be used at all
        for (Map<URI, NamespaceHandler> key : schemas.keySet()) {
            if (key.equals(handlers)) {
                schema = schemas.get(key).get();
                break;
            }
        }
        if (schema == null) {
            List<StreamSource> schemaSources = new ArrayList<StreamSource>();
            try {
                schemaSources.add(new StreamSource(getClass().getResourceAsStream("/org/apache/aries/blueprint/blueprint.xsd")));
                // Create a schema for all namespaces known at this point
                // It will speed things as it can be reused for all other blueprint containers
                for (URI ns : handlers.keySet()) {
                    URL url = handlers.get(ns).getSchemaLocation(ns.toString());
                    if (url == null) {
                        LOGGER.warn("No URL is defined for schema " + ns + ". This schema will not be validated");
                    } else {
                        schemaSources.add(new StreamSource(url.openStream()));
                    }
                }
                schema = getSchemaFactory().newSchema(schemaSources.toArray(new Source[schemaSources.size()]));
                schemas.put(handlers, new SoftReference<Schema>(schema));
            } finally {
                for (StreamSource s : schemaSources) {
                    try {
                        s.getInputStream().close();
                    } catch (IOException e) {
                        // Ignore
                    }
                }
            }
        }
        return schema;
    }

    protected synchronized void removeSchemasFor(NamespaceHandler handler) {
        List<Map<URI, NamespaceHandler>> keys = new ArrayList<Map<URI, NamespaceHandler>>();
        for (Map<URI, NamespaceHandler> key : schemas.keySet()) {
            if (key.values().contains(handler)) {
                keys.add(key);
            }
        }
        for (Map<URI, NamespaceHandler> key : keys) {
            schemas.remove(key);
        }
    }

    private SchemaFactory getSchemaFactory() {
        SchemaFactory schemaFactory = null;
        if (schemaFactory == null) {
            schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        }
        return schemaFactory;
    }

    protected class NamespaceHandlerSetImpl implements NamespaceHandlerSet {

        private final Map<Listener, Boolean> listeners;
        private final Bundle bundle;
        private final Set<URI> namespaces;
        private final Map<URI, NamespaceHandler> handlers;
        private Schema schema;

        public NamespaceHandlerSetImpl(Set<URI> namespaces, Bundle bundle) {
            this.listeners = new HashMap<Listener, Boolean>();
            this.namespaces = namespaces;
            this.bundle = bundle;
            handlers = new HashMap<URI, NamespaceHandler>();
            for (URI ns : namespaces) {
                findCompatibleNamespaceHandler(ns);
            }
        }

        public boolean isComplete() {
            return handlers.size() == namespaces.size();
        }

        public Set<URI> getNamespaces() {
            return namespaces;
        }

        public NamespaceHandler getNamespaceHandler(URI namespace) {
            return handlers.get(namespace);
        }

        public Schema getSchema() throws SAXException, IOException {
            if (!isComplete()) {
                throw new IllegalStateException("NamespaceHandlerSet is not complete");
            }
            if (schema == null) {
                schema = NamespaceHandlerRegistryImpl.this.getSchema(handlers);
            }
            return schema;
        }

        public synchronized void addListener(Listener listener) {
            listeners.put(listener, Boolean.TRUE);
        }

        public synchronized void removeListener(Listener listener) {
            listeners.remove(listener);
        }

        public void destroy() {
            NamespaceHandlerRegistryImpl.this.sets.remove(this);
        }

        public void registerHandler(URI uri, NamespaceHandler handler) {
            if (namespaces.contains(uri) && handlers.get(uri) == null) {
                if (findCompatibleNamespaceHandler(uri) !=  null) {
                    for (Listener listener : listeners.keySet()) {
                        try {
                            listener.namespaceHandlerRegistered(uri);
                        } catch (Throwable t) {
                            LOGGER.debug("Unexpected exception when notifying a NamespaceHandler listener", t);
                        }
                    }
                }
            }
        }

        public void unregisterHandler(URI uri, NamespaceHandler handler) {
            if (handlers.get(uri) == handler) {
                handlers.remove(uri);
                for (Listener listener : listeners.keySet()) {
                    try {
                        listener.namespaceHandlerUnregistered(uri);
                    } catch (Throwable t) {
                        LOGGER.debug("Unexpected exception when notifying a NamespaceHandler listener", t);
                    }
                }
            }
        }

        private NamespaceHandler findCompatibleNamespaceHandler(URI ns) {
            Set<NamespaceHandler> candidates = NamespaceHandlerRegistryImpl.this.handlers.get(ns);
            if (candidates != null) {
                for (NamespaceHandler h : candidates) {
                    Set<Class> classes = h.getManagedClasses();
                    boolean compat = true;
                    if (classes != null) {
                        Set<Class> allClasses = new HashSet<Class>();
                        for (Class cl : classes) {
                            for (Class c = cl; c != null; c = c.getSuperclass()) {
                                allClasses.add(c);
                                for (Class i : c.getInterfaces()) {
                                    allClasses.add(i);
                                }
                            }
                        }
                        for (Class cl : allClasses) {
                            Class clb;
                            try {
                                clb = bundle.loadClass(cl.getName());
                                if (clb != cl) {
                                    compat = false;
                                    break;
                                }
                            } catch (ClassNotFoundException e) {
                                // Ignore
                            } catch (NoClassDefFoundError e) {
                                // Ignore
                            }
                        }
                    }
                    if (compat) {
                        handlers.put(ns, h);
                        return h;
                    }
                }
            }
            return null;
        }
    }

    protected static Map<URI, NamespaceHandler> findHandlers(Map<URI, Set<NamespaceHandler>> allHandlers,
                                                             Set<URI> namespaces,
                                                             Bundle bundle) {
        Map<URI, NamespaceHandler> handlers = new HashMap<URI, NamespaceHandler>();
        Map<URI, Set<NamespaceHandler>> candidates = new HashMap<URI, Set<NamespaceHandler>>();
        // Populate initial candidates
        for (URI ns : namespaces) {
            Set<NamespaceHandler> h = new HashSet<NamespaceHandler>();
            if (allHandlers.get(ns) != null) {
                h.addAll(allHandlers.get(ns));
            }
            candidates.put(ns, h);
        }
        // Exclude directly incompatible handlers
        for (URI ns : namespaces) {
            for (Iterator<NamespaceHandler> it = candidates.get(ns).iterator(); it.hasNext();) {
                NamespaceHandler h = it.next();
                Set<Class> classes = h.getManagedClasses();
                boolean compat = true;
                if (classes != null) {
                    Set<Class> allClasses = new HashSet<Class>();
                    for (Class cl : classes) {
                        for (Class c = cl; c != null; c = c.getSuperclass()) {
                            allClasses.add(c);
                            for (Class i : c.getInterfaces()) {
                                allClasses.add(i);
                            }
                        }
                    }
                    for (Class cl : allClasses) {
                        Class clb;
                        try {
                            clb = bundle.loadClass(cl.getName());
                        } catch (Throwable t) {
                            clb = null;
                        }
                        if (clb != cl) {
                            compat = false;
                            break;
                        }
                    }
                }
                if (!compat) {
                    it.remove();
                }
            }
        }
        // TODO: do we need to check if there are incompatibilities between namespaces?
        // Pick the first ones
        for (URI ns : namespaces) {
            Set<NamespaceHandler> h = candidates.get(ns);
            if (!h.isEmpty()) {
                handlers.put(ns, h.iterator().next());
            }
        }
        return handlers;
    }

    public static class LRUMap<K,V> extends AbstractMap<K,V> {

        private final int bound;
        private final LinkedList<Entry<K,V>> entries = new LinkedList<Entry<K,V>>();

        private static class LRUEntry<K,V> implements Entry<K,V> {
            private final K key;
            private final V value;

            private LRUEntry(K key, V value) {
                this.key = key;
                this.value = value;
            }

            public K getKey() {
                return key;
            }

            public V getValue() {
                return value;
            }

            public V setValue(V value) {
                throw new UnsupportedOperationException();
            }
        }

        private LRUMap(int bound) {
            this.bound = bound;
        }

        public V get(Object key) {
            if (key == null) {
                throw new NullPointerException();
            }
            for (Entry<K,V> e : entries) {
                if (e.getKey().equals(key)) {
                    entries.remove(e);
                    entries.addFirst(e);
                    return e.getValue();
                }
            }
            return null;
        }

        public V put(K key, V value) {
            if (key == null) {
                throw new NullPointerException();
            }
            V old = null;
            for (Entry<K,V> e : entries) {
                if (e.getKey().equals(key)) {
                    entries.remove(e);
                    old = e.getValue();
                    break;
                }
            }
            if (value != null) {
                entries.addFirst(new LRUEntry<K,V>(key, value));
                while (entries.size() > bound) {
                    entries.removeLast();
                }
            }
            return old;
        }

        public Set<Entry<K, V>> entrySet() {
            return new AbstractSet<Entry<K,V>>() {
                public Iterator<Entry<K, V>> iterator() {
                    return entries.iterator();
                }

                public int size() {
                    return entries.size();
                }
            };
        }
    }

}
