/*
 * 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.tuscany.sca.databinding.jaxb;

import java.io.IOException;
import java.io.StringWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.namespace.QName;
import javax.xml.transform.Result;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamResult;

import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
import org.apache.tuscany.sca.core.ExtensionPointRegistry;
import org.apache.tuscany.sca.databinding.XMLTypeHelper;
import org.apache.tuscany.sca.interfacedef.DataType;
import org.apache.tuscany.sca.interfacedef.Interface;
import org.apache.tuscany.sca.interfacedef.util.JavaXMLMapper;
import org.apache.tuscany.sca.interfacedef.util.TypeInfo;
import org.apache.tuscany.sca.interfacedef.util.XMLType;
import org.apache.tuscany.sca.xsd.XSDFactory;
import org.apache.tuscany.sca.xsd.XSDefinition;
import org.oasisopen.sca.ServiceRuntimeException;
import org.w3c.dom.Document;

public class JAXBTypeHelper implements XMLTypeHelper {
    private static final String SCHEMA_NS = "http://www.w3.org/2001/XMLSchema";
    private static final String ANYTYPE_NAME = "anyType";
    private static final QName ANYTYPE_QNAME = new QName(SCHEMA_NS, ANYTYPE_NAME);

    private JAXBContextHelper contextHelper;
    
    public JAXBTypeHelper(ExtensionPointRegistry registry) {
        super();
        contextHelper = JAXBContextHelper.getInstance(registry);
    }

    public TypeInfo getTypeInfo(Class javaType, Object logical) {
        QName xmlType = JavaXMLMapper.getXMLType(javaType);
        if (xmlType != null) {
            return new TypeInfo(xmlType, true, null);
        } else if (javaType.isInterface()) {
            return new TypeInfo(ANYTYPE_QNAME, true, null);
        } else {
            // types.add(javaType);
            if (logical instanceof XMLType) {
                xmlType = ((XMLType)logical).getTypeName();
            }
            if (xmlType == null) {
                xmlType = new QName(JAXBContextHelper.jaxbDecapitalize(javaType.getSimpleName()));
            }
            return new TypeInfo(xmlType, false, null);
        }
    }

    /*
    public List<XSDefinition> getSchemaDefinitions(XSDFactory factory, ModelResolver resolver) {
        List<XSDefinition> definitions = new ArrayList<XSDefinition>();
        generateJAXBSchemas(definitions, factory);
        return definitions;
    }
    */

    public static Map<String, String> generateSchema(JAXBContext context) throws IOException {
        StringResolverImpl resolver = new StringResolverImpl();
        context.generateSchema(resolver);
        Map<String, String> xsds = new HashMap<String, String>();
        for (Map.Entry<String, StreamResult> xsd : resolver.getResults().entrySet()) {
            xsds.put(xsd.getKey(), xsd.getValue().getWriter().toString());
        }
        return xsds;
    }

//    private static class XSDResolver implements URIResolver {
//        private Map<String, String> xsds;
//
//        public XSDResolver(Map<String, String> xsds) {
//            super();
//            this.xsds = xsds;
//        }
//
//        public InputSource resolveEntity(java.lang.String namespace,
//                                         java.lang.String schemaLocation,
//                                         java.lang.String baseUri) {
//            String xsd = xsds.get(schemaLocation);
//            if (xsd == null) {
//                return null;
//            }
//            return new InputSource(new StringReader(xsd));
//        }
//
//    }

    /*
    private void generateJAXBSchemas1(List<XSDefinition> definitions, XSDFactory factory) {
        if (types.size() > 0) {
            try {
                XmlSchemaCollection collection = new XmlSchemaCollection();
                Class[] typesArray = new Class[types.size()];
                typesArray = types.toArray(typesArray);
                JAXBContext context = JAXBContextHelper.createJAXBContext(typesArray);
                Map<String, String> results = generateSchema(context);
                collection.setSchemaResolver(new XSDResolver(results));

                for (Map.Entry<String, String> entry : results.entrySet()) {
                    XSDefinition definition = factory.createXSDefinition();
                    int index = entry.getKey().lastIndexOf('#');
                    String ns = entry.getKey().substring(0, index);
                    String file = entry.getKey().substring(index + 1);
                    definition.setUnresolved(true);
                    definition.setNamespace(ns);
                    definition.setSchema(collection.read(new StringReader(entry.getValue()), null));
                    definition.setSchemaCollection(collection);
                    definition.setUnresolved(false);
                    definitions.add(definition);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    */

    private static class DOMResolverImpl extends SchemaOutputResolver {
        private Map<String, DOMResult> results = new HashMap<String, DOMResult>();

        @Override
        public Result createOutput(String ns, String file) throws IOException {
            DOMResult result = new DOMResult();
            // TUSCANY-2498: Set the system id to "" so that the xsd:import doesn't produce 
            // an illegal schemaLocation attr 
            result.setSystemId("");
            results.put(ns, result);
            return result;
        }

        public Map<String, DOMResult> getResults() {
            return results;
        }
    }

    /*
    private void generateJAXBSchemas(List<XSDefinition> definitions, XSDFactory factory) {
        if (types.size() > 0) {
            try {
                Class<?>[] typesArray = new Class<?>[types.size()];
                typesArray = types.toArray(typesArray);
                JAXBContext context = JAXBContext.newInstance(typesArray);
                generateSchemas(definitions, factory, context);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    */

    private void generateSchemas(List<XSDefinition> definitions, XSDFactory factory, JAXBContext context)
        throws IOException {
        DOMResolverImpl resolver = new DOMResolverImpl();
        context.generateSchema(resolver);
        Map<String, DOMResult> results = resolver.getResults();
        for (Map.Entry<String, DOMResult> entry : results.entrySet()) {
            XSDefinition definition = factory.createXSDefinition();
            definition.setUnresolved(true);
            definition.setDocument((Document)entry.getValue().getNode());
            definition.setNamespace(entry.getKey());
            URI location = null;
            try {
                location = new URI(entry.getValue().getSystemId());
            } catch (URISyntaxException e) {
                // ignore: use null value
            }    
            definition.setLocation(location);
            definitions.add(definition);
        }
    }

    private static class StringResolverImpl extends SchemaOutputResolver {
        private Map<String, StreamResult> results = new HashMap<String, StreamResult>();

        @Override
        public Result createOutput(String ns, String file) throws IOException {
            StringWriter sw = new StringWriter();
            StreamResult result = new StreamResult(sw);
            String sysId = ns + '#' + file;
            result.setSystemId(sysId);
            results.put(sysId, result);
            return result;
        }

        public Map<String, StreamResult> getResults() {
            return results;
        }
    }

    public List<XSDefinition> getSchemaDefinitions(XSDFactory factory, ModelResolver resolver, Interface intf) {
        try {
            JAXBContext context = contextHelper.createJAXBContext(intf, false);
            List<XSDefinition> definitions = new ArrayList<XSDefinition>();
            generateSchemas(definitions, factory, context);
            return definitions;
        } catch (Throwable e) {
            throw new ServiceRuntimeException(e);
        }
    }

    public List<XSDefinition> getSchemaDefinitions(XSDFactory factory, ModelResolver resolver, List<DataType> dataTypes) {
        try {

            JAXBContext context = contextHelper.createJAXBContext(dataTypes);
            List<XSDefinition> definitions = new ArrayList<XSDefinition>();
            generateSchemas(definitions, factory, context);
            return definitions;
        } catch (Throwable e) {
            throw new ServiceRuntimeException(e);
        }
    }

}
