package ru.yandex.webmaster3.core.semantic.semantic_document_parser.rdfa.jsonld;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import ru.yandex.common.util.IOUtils;
import ru.yandex.webmaster3.core.semantic.semantic_document_parser.microdata.MicrodataUtils;
import ru.yandex.webmaster3.core.semantic.semantic_document_parser.rdfa.data.RDFaEntity;
import ru.yandex.webmaster3.core.semantic.semantic_document_parser.rdfa.data.RDFaProperty;
import ru.yandex.webmaster3.core.semantic.semantic_document_parser.rdfa.transformers.ExperimentalExtractor;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static ru.yandex.common.util.StringUtils.isEmpty;

/**
 * Created by IntelliJ IDEA.
 * User: rasifiel
 * Date: 18.02.14
 * Time: 1:36
 */
public class ContextManager {

    final Map<String, List<RDFaProperty>> contextMap = new ConcurrentHashMap<String, List<RDFaProperty>>();

    public ContextManager(Map<String,String> filenames) throws IOException {
        for (final String key : filenames.keySet()) {
            ClassLoader classLoader = ContextManager.class.getClassLoader();
            for(String keyAlias : MicrodataUtils.protocolAliases(key)) {
                loadContext(keyAlias, classLoader.getResourceAsStream(filenames.get(key)), Charset.forName("UTF-8"), MicrodataUtils.onlyProtocol(keyAlias));
            }
        }
    }

    public void loadContext(final String uri, final InputStream is, final Charset charset) throws IOException {
        final String json = IOUtils.readInputStream(is,charset);
        ObjectMapper objectMapper = new ObjectMapper();
        JsonFactory factory = objectMapper.getFactory();
        JsonParser parser = factory.createParser(json);
        TreeNode rr = parser.readValueAsTree();
        RDFaEntity entity = ExperimentalExtractor.extractLD(rr);
        if (!entity.hasProperty("@context")) {
            throw new JSONLDExpansionException("invalid remote context");
        }
        contextMap.put(normalize(uri), Collections.unmodifiableList(entity.getProperty("@context")));
    }

    public void loadContext(final String uri, final InputStream is, final Charset charset, String prefix) throws IOException {
        final String json = IOUtils.readInputStream(is,charset);
        ObjectMapper objectMapper = new ObjectMapper();
        JsonFactory factory = objectMapper.getFactory();
        JsonParser parser = factory.createParser(json);
        TreeNode rr = parser.readValueAsTree();
        RDFaEntity entity = ExperimentalExtractor.extractLD(rr, prefix);
        if (!entity.hasProperty("@context")) {
            throw new JSONLDExpansionException("invalid remote context");
        }
        contextMap.put(normalize(uri), Collections.unmodifiableList(entity.getProperty("@context")));
    }

    public List<RDFaProperty> getContext(final String uri) {
        List<RDFaProperty> res = contextMap.get(normalize(uri));
        return res;
    }

    private static String normalize(final String url) {
        try {
            URI uri = new URI(url).normalize();
            if (isEmpty(uri.getPath()))
                uri = new URI(uri.getScheme(),uri.getUserInfo(),uri.getHost(),uri.getPort(),"/",uri.getQuery(),uri.getFragment());
            return uri.toASCIIString();
        } catch (URISyntaxException e) {
            return url;
        }
    }

}
