/*
 * 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$, $Date$
 */
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();
                }
            };
        }
    }

}
