/*
 * Decompiled with CFR 0.152.
 */
package org.jivesoftware.smack.provider;

import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.provider.ExtensionProviderInfo;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.provider.IQProviderInfo;
import org.jivesoftware.smack.provider.ProviderLoader;
import org.jivesoftware.smack.provider.StreamFeatureProviderInfo;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;

public class ProviderFileLoader
implements ProviderLoader {
    private static final Logger LOGGER = Logger.getLogger(ProviderFileLoader.class.getName());
    private final Collection<IQProviderInfo> iqProviders = new LinkedList<IQProviderInfo>();
    private final Collection<ExtensionProviderInfo> extProviders = new LinkedList<ExtensionProviderInfo>();
    private final Collection<StreamFeatureProviderInfo> sfProviders = new LinkedList<StreamFeatureProviderInfo>();
    private List<Exception> exceptions = new LinkedList<Exception>();

    public ProviderFileLoader(InputStream providerStream) {
        this(providerStream, ProviderFileLoader.class.getClassLoader());
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public ProviderFileLoader(InputStream providerStream, ClassLoader classLoader) {
        try {
            XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
            parser.setFeature("http://xmlpull.org/v1/doc/features.html#process-namespaces", true);
            parser.setInput(providerStream, "UTF-8");
            int eventType = parser.getEventType();
            do {
                if (eventType != 2) continue;
                String typeName = parser.getName();
                try {
                    if ("smackProviders".equals(typeName)) continue;
                    parser.next();
                    parser.next();
                    String elementName = parser.nextText();
                    parser.next();
                    parser.next();
                    String namespace = parser.nextText();
                    parser.next();
                    parser.next();
                    String className = parser.nextText();
                    try {
                        Class<?> provider = classLoader.loadClass(className);
                        switch (typeName) {
                            case "iqProvider": {
                                if (IQProvider.class.isAssignableFrom(provider)) {
                                    this.iqProviders.add(new IQProviderInfo(elementName, namespace, (IQProvider)provider.newInstance()));
                                    break;
                                }
                                this.exceptions.add(new IllegalArgumentException(className + " is not a IQProvider"));
                                break;
                            }
                            case "extensionProvider": {
                                if (ExtensionElementProvider.class.isAssignableFrom(provider)) {
                                    this.extProviders.add(new ExtensionProviderInfo(elementName, namespace, (ExtensionElementProvider)provider.newInstance()));
                                    break;
                                }
                                this.exceptions.add(new IllegalArgumentException(className + " is not a PacketExtensionProvider"));
                                break;
                            }
                            case "streamFeatureProvider": {
                                this.sfProviders.add(new StreamFeatureProviderInfo(elementName, namespace, (ExtensionElementProvider)provider.newInstance()));
                                break;
                            }
                            default: {
                                LOGGER.warning("Unknown provider type: " + typeName);
                                break;
                            }
                        }
                    }
                    catch (ClassNotFoundException cnfe) {
                        LOGGER.log(Level.SEVERE, "Could not find provider class", cnfe);
                        this.exceptions.add(cnfe);
                    }
                    catch (InstantiationException ie) {
                        LOGGER.log(Level.SEVERE, "Could not instanciate " + className, ie);
                        this.exceptions.add(ie);
                    }
                }
                catch (IllegalArgumentException illExc) {
                    LOGGER.log(Level.SEVERE, "Invalid provider type found [" + typeName + "] when expecting iqProvider or extensionProvider", illExc);
                    this.exceptions.add(illExc);
                }
            } while ((eventType = parser.next()) != 1);
        }
        catch (Exception e) {
            LOGGER.log(Level.SEVERE, "Unknown error occurred while parsing provider file", e);
            this.exceptions.add(e);
        }
        finally {
            try {
                providerStream.close();
            }
            catch (Exception exception) {}
        }
    }

    @Override
    public Collection<IQProviderInfo> getIQProviderInfo() {
        return this.iqProviders;
    }

    @Override
    public Collection<ExtensionProviderInfo> getExtensionProviderInfo() {
        return this.extProviders;
    }

    @Override
    public Collection<StreamFeatureProviderInfo> getStreamFeatureProviderInfo() {
        return this.sfProviders;
    }

    public List<Exception> getLoadingExceptions() {
        return Collections.unmodifiableList(this.exceptions);
    }
}
