/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2008-2009 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */
package org.ow2.jonas.ws.axis2.util;

import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.StringTokenizer;

import javax.jws.WebService;
import javax.xml.namespace.QName;
import javax.xml.ws.WebServiceProvider;

import org.ow2.jonas.ws.axis2.JaxWsImplementorInfo;

public abstract class JAXWSUtils {


    public static boolean isEmpty(final String str) {
        if (str == null || "".equals(str)) {
            return true;
        } else {
            return false;
        }
    }
    private static String getNamespace(final Class clazz, final String namespace) {
        if (namespace == null || namespace.trim().length() == 0) {
            Package pkg = clazz.getPackage();
            if (pkg == null) {
                return null;
            } else {
                return getNamespace(pkg.getName());
            }
        } else {
            return namespace.trim();
        }
    }
    private static String getServiceName(final Class clazz, final String name) {
        if (name == null || name.trim().length() == 0) {
            return clazz.getSimpleName() + "Service";
        } else {
            return name.trim();
        }
    }
    private static QName getServiceQName(final Class clazz, final String namespace, final String name) {
        return new QName(getNamespace(clazz, namespace), getServiceName(clazz, name));
    }
    public static QName getServiceQName(final Class clazz) {
        WebService webService =
            (WebService)clazz.getAnnotation(WebService.class);
        if (webService == null) {
            WebServiceProvider webServiceProvider =
                (WebServiceProvider)clazz.getAnnotation(WebServiceProvider.class);
            if (webServiceProvider == null) {
                throw new IllegalArgumentException("The " + clazz.getName() + " is not annotated");
            }
            return getServiceQName(clazz, webServiceProvider.targetNamespace(), webServiceProvider.serviceName());
        } else {
            return getServiceQName(clazz, webService.targetNamespace(), webService.serviceName());
        }
    }

    public static String getNamespace(final String packageName) {
        if (packageName == null || packageName.length() == 0) {
            return null;
        }
        StringTokenizer tokenizer = new StringTokenizer(packageName, ".");
        String[] tokens;
        if (tokenizer.countTokens() == 0) {
            tokens = new String[0];
        } else {
            tokens = new String[tokenizer.countTokens()];
            for (int i = tokenizer.countTokens() - 1; i >= 0; i--) {
                tokens[i] = tokenizer.nextToken();
            }
        }
        StringBuffer namespace = new StringBuffer("http://");
        String dot = "";
        for (int i = 0; i < tokens.length; i++) {
            if (i == 1) {
                dot = ".";
            }
            namespace.append(dot + tokens[i]);
        }
        namespace.append('/');
        return namespace.toString();
    }

    public static String getPackageName(final Class<?> clazz) {
        String className = clazz.getName();
        if (className.startsWith("[L")) {
            className = className.substring(2);
        }
        int pos = className.lastIndexOf('.');
        if (pos != -1) {
            return className.substring(0, pos);
        } else {
            return "";
        }
    }

    public static Class<?> loadClass(final String className, final Class<?> callingClass) throws ClassNotFoundException {
        try {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();

            if (cl != null) {
                return cl.loadClass(className);
            }
        } catch (ClassNotFoundException e) {
            // ignore
        }
        return loadClass2(className, callingClass);
    }

    private static Class<?> loadClass2(final String className, final Class<?> callingClass) throws ClassNotFoundException {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException ex) {
            try {

                if (JaxWsImplementorInfo.class.getClassLoader() != null) {
                    return JaxWsImplementorInfo.class.getClassLoader().loadClass(className);
                }
            } catch (ClassNotFoundException exc) {
                if (callingClass != null && callingClass.getClassLoader() != null) {
                    return callingClass.getClassLoader().loadClass(className);
                }
            }
            throw ex;
        }
    }

    public static Class<?> getClassFromType(final Type t) {
        if (t instanceof Class) {
            return (Class) t;
        } else if (t instanceof GenericArrayType) {
            GenericArrayType g = (GenericArrayType) t;
            return Array.newInstance(getClassFromType(g.getGenericComponentType()), 0).getClass();
        } else if (t instanceof ParameterizedType) {
            ParameterizedType p = (ParameterizedType) t;
            return getClassFromType(p.getRawType());
        }
        // TypeVariable and WildCardType are not handled as it is unlikely such
        // Types will
        // JAXB Code Generated.
        assert false;
        throw new IllegalArgumentException("Cannot get Class object from unknown Type");
    }

    public static String getDefaultNamespace(final Class clazz) {
        String pkg = getNamespace(getPackageName(clazz));
        return isEmpty(pkg) ? "http://unknown.namespace/" : pkg;
    }


    private static QName getPortQName(final Class clazz, final String namespace, final String name, final String portName) {
        return new QName(getNamespace(clazz, namespace), getPortName(clazz, name, portName));
    }

    public static QName getPortQName(final Class clazz) {
        WebService webService =
            (WebService)clazz.getAnnotation(WebService.class);
        if (webService == null) {
            WebServiceProvider webServiceProvider =
                (WebServiceProvider)clazz.getAnnotation(WebServiceProvider.class);
            if (webServiceProvider == null) {
                throw new IllegalArgumentException("The " + clazz.getName() + " is not annotated");
            }
            return getPortQName(clazz, webServiceProvider.targetNamespace(), null, webServiceProvider.portName());
        } else {
            return getPortQName(clazz, webService.targetNamespace(), webService.name(), webService.portName());
        }
    }
    private static String getPortName(final Class clazz, final String name, final String portName) {
        if (portName == null || portName.trim().length() == 0) {
            if (name == null || name.trim().length() == 0) {
                return clazz.getSimpleName() + "Port";
            } else {
                return name + "Port";
            }
        } else {
            return portName.trim();
        }
    }
}
