/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.io.uri.impl;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.Optional;

import net.ranides.assira.collection.iterators.EnumerationUtils;
import net.ranides.assira.collection.iterators.IteratorUtils;
import net.ranides.assira.io.uri.*;
import net.ranides.assira.reflection.util.ClassUtils;
import net.ranides.assira.text.StringUtils;
import net.ranides.assira.trace.TraceUtils;

public class CClassPathHandler implements URIHandler {

    private final URIResolver resolver;

    public CClassPathHandler() {
        this.resolver = URIResolver.DEFAULT;
    }

    public CClassPathHandler(URIResolver resolver) {
        this.resolver = resolver;
    }

    @Override
    public URIHandle resolve(URI uri) throws IOException {
        String path = StringUtils.ltrim(URIUtils.getFile(uri), '/');
        Optional<URL> file = IteratorUtils.last(EnumerationUtils.iterator(loader().getResources(path)));

        if(!file.isPresent()) {
            return new CInvalidHandle(resolver, uri);
        }
        try {
            return resolver.resolve(file.get().toURI());
        } catch (URISyntaxException e) {
            throw new IOException(e);
        }
    }

    @Override
    public Collection<String> schemes() {
        return Arrays.asList("classpath", "cp");
    }

    public static ClassLoader loader() {
        ClassLoader caller  = caller().getClassLoader();
        ClassLoader context = Thread.currentThread ().getContextClassLoader();
        ClassLoader system  = ClassLoader.getSystemClassLoader();

        // If 'caller' and 'context' are in a parent-child relationship, choose the child
        ClassLoader result = ClassUtils.isParent(context, caller) ? caller : context;

        // Precaution for when deployed as a bootstrap or extension class:
        if (ClassUtils.isParent(result, system)) {
            result = system;
        }
        return result;
    }

    private static Class<?> caller() {
        for (Class<?> type : TraceUtils.getTypes()) {
            if( type.getName().startsWith("net.ranides.assira.io.uri.impl.CClassPathHandler$") ) {
                continue;
            }
            if( CClassPathHandler.class.equals(type) ) {
                continue;
            }
            if( URIResolver.class.equals(type) ) {
                continue;
            }
            return type;
        }
        return URIResolver.class;
    }

}
