/**
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 *
 * Copyright (C)
 * <a href="http://www.inab.org">Spanish National Institute of Bioinformatics (INB)</a>
 * <a href="http://www.bsc.es">Barcelona Supercomputing Center (BSC)</a>
 * <a href="http://inb.bsc.es">Computational Node 6</a>
 */

package org.inb.biomoby.generator;

import java.io.StringWriter;
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
import javax.lang.model.SourceVersion;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.util.JAXBSource;
import javax.xml.namespace.QName;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

/**
 * @author Dmitry Repchevsky
 */

public class GeneratorUtil
{
    public final static String[] MOBY_RESERVED = {"Object", "String", "Integer", "Float", "Boolean", "DateTime"};

    private static Set<String> mobyReserved;

    private GeneratorUtil() {}

    public static <T> String transform(String xsl, T ... array) throws TransformerConfigurationException, TransformerException, JAXBException
    {
        JAXBElement<T> root = new JAXBElement(new QName("root"), array.getClass(), array);
        
        JAXBContext jaxbContext = JAXBContext.newInstance(array.getClass());
        JAXBSource jaxbSource = new JAXBSource(jaxbContext, root);

        return transform(xsl, jaxbSource);
    }

    public static String transform(String xsl, Object object) throws TransformerConfigurationException, TransformerException, JAXBException
    {
        JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
        JAXBSource jaxbSource = new JAXBSource(jaxbContext, object);

        return transform(xsl, jaxbSource);
    }

    private static String transform(String xsl, JAXBSource jaxbSource) throws TransformerConfigurationException, TransformerException, JAXBException
    {
        XMLReader reader = jaxbSource.getXMLReader();
        TemplateFilter filter = new TemplateFilter(reader);
        InputSource inputSource = jaxbSource.getInputSource();
        SAXSource saxSource = new SAXSource(filter, inputSource);
        
        Transformer transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(GeneratorUtil.class.getClassLoader().getResourceAsStream(xsl)));
        transformer.setOutputProperty(OutputKeys.METHOD, "text");

        // ********************************
        TransformerFactory f = TransformerFactory.newInstance();
        Transformer tr = f.newTransformer();
        tr.setOutputProperty(OutputKeys.INDENT, "yes");

        StringWriter sw = new StringWriter();
        StreamResult result = new StreamResult(sw);
        tr.transform(saxSource, result);
        //tr.transform(jaxbSource, result);
//        System.out.println("-------> ");
//        System.out.println(sw.toString());
        // ********************************
        
        StringWriter writer = new StringWriter();
        transformer.transform(saxSource, new StreamResult(writer));
       
        return writer.toString();
    }

    public static String getJavaAttributeName(String name)
    {
        if (name.length() == 0)
        {
            return name;
        }
        
        StringBuilder sb = new StringBuilder(name);
        sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
        normalize(sb);

        String attribute = sb.toString();

        if (isJavaReserved(attribute))
        {
            attribute = "_" + attribute;
        }

        return attribute;
    }

    public static String getJavaFileName(String name)
    {
        return getJavaClassName(name) + ".java";
    }

    public static boolean isMobyReserved(String name)
    {
        if (mobyReserved == null)
        {
           mobyReserved = new TreeSet(Arrays.asList(GeneratorUtil.MOBY_RESERVED));
        }
        
        return mobyReserved.contains(name);
    }
    
    public static String getJavaClassName(String name)
    {
        if (isMobyReserved(name))
        {
            return "Moby" + name;
        }

        StringBuilder sb = new StringBuilder(name);
        sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
        normalize(sb);

        return sb.toString();
    }

    private static void normalize(StringBuilder builder)
    {
        for(int i = builder.length() - 1; i > 0; i--)
        {
            char ch = builder.charAt(i);
            if ((ch != '_') && (!Character.isLetterOrDigit(ch)))
            {
                builder.setCharAt(i, '_');
                builder.insert(i, '_');
            }
        }
    }

    private static boolean isJavaReserved(String name)
    {
        return !SourceVersion.isName(name);
    }
}
