/*
 * 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.axis2.corba.receivers;

import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.corba.deployer.CorbaConstants;
import org.apache.axis2.corba.deployer.SchemaToIDLMapping;
import org.apache.axis2.corba.exceptions.CorbaException;
import org.apache.axis2.corba.exceptions.CorbaInvocationException;
import org.apache.axis2.corba.idl.IDLProcessor;
import org.apache.axis2.corba.idl.PreProcessorInputStream;
import org.apache.axis2.corba.idl.types.*;
import org.apache.axis2.corba.idl.values.*;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.description.java2wsdl.DefaultNamespaceGenerator;
import org.apache.axis2.description.java2wsdl.TypeTable;
import org.apache.axis2.namespace.Constants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.omg.CORBA.Any;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.omg.CORBA_2_3.ORB;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.CosNaming.NamingContextPackage.CannotProceed;
import org.omg.CosNaming.NamingContextPackage.InvalidName;
import org.omg.CosNaming.NamingContextPackage.NotFound;

import javax.xml.namespace.QName;
import java.io.*;
import java.math.BigDecimal;
import java.util.*;

//import java.io.FileInputStream;
//import java.util.zip.ZipEntry;
//import java.util.zip.ZipInputStream;

public class CorbaUtil implements CorbaConstants {
    private static Map IDL_CACHE = new HashMap();
    private static final Log log = LogFactory.getLog(CorbaUtil.class);

    public static org.omg.CORBA_2_3.ORB getORB(AxisService service) {
        Parameter orbClass = service.getParameter(ORB_CLASS);
        Parameter orbSingletonClass = service.getParameter(ORB_SINGLETON_CLASS);
        Properties props = System.getProperties();

        if (orbClass!=null)
            props.put(ORG_OMG_CORBA_ORBCLASS, ((String) orbClass.getValue()).trim());
        else
            props.put(ORG_OMG_CORBA_ORBCLASS, DEFAULR_ORB_CLASS);

        if (orbSingletonClass!=null)
            props.put(ORG_OMG_CORBA_ORBSINGLETON_CLASS, ((String) orbSingletonClass.getValue()).trim());
        else
            props.put(ORG_OMG_CORBA_ORBSINGLETON_CLASS, DEFAULT_ORBSINGLETON_CLASS);

        return (ORB) ORB.init(new String[]{}, props);
    }

    public static org.omg.CORBA.Object resolveObject(AxisService service, org.omg.CORBA_2_3.ORB orb) throws CorbaInvocationException {
        org.omg.CORBA.Object obj;
        try {
            Parameter namingServiceUrl = service.getParameter(NAMING_SERVICE_URL);
            Parameter objectName = service.getParameter(OBJECT_NAME);
            Parameter iorFilePath = service.getParameter(IOR_FILE_PATH);
            Parameter iorString = service.getParameter(IOR_STRING);

            if (namingServiceUrl!=null && objectName!=null) {
                obj = orb.string_to_object(((String) namingServiceUrl.getValue()).trim());
                NamingContextExt nc = NamingContextExtHelper.narrow(obj);
                obj = nc.resolve(nc.to_name(((String) objectName.getValue()).trim()));
            } else if (iorFilePath!=null) {
                FileReader fileReader = new FileReader(((String) iorFilePath.getValue()).trim());
                char[] buf = new char[1000];
                fileReader.read(buf);
                obj = orb.string_to_object((new String(buf)).trim());
                fileReader.close();
            } else if (iorString!=null) {
                obj = orb.string_to_object(((String) iorString.getValue()).trim());
            } else {
                throw new CorbaInvocationException("cannot resolve object");
            }

        } catch (NotFound notFound) {
            throw new CorbaInvocationException("cannot resolve object", notFound);
        } catch (CannotProceed cannotProceed) {
            throw new CorbaInvocationException("cannot resolve object", cannotProceed);
        } catch (InvalidName invalidName) {
            throw new CorbaInvocationException("cannot resolve object", invalidName);
        } catch (IOException e) {
            throw new CorbaInvocationException("cannot resolve object", e);
        }
        return obj;
    }

    public static IDL getIDL(AxisService service, ORB orb, String dirName) throws CorbaException {
        Parameter idlFile = service.getParameter(IDL_FILE);

        if (idlFile == null) {
            throw new CorbaInvocationException("Please specify the IDL file");    
        }

        String idlFileName = ((String) idlFile.getValue()).trim();
        String cacheKey = dirName + File.separator + idlFileName;
        IDL idl = (IDL) IDL_CACHE.get(cacheKey);
        if (idl==null) {
            try {
                /*File file = new File(dirName);
                InputStream stream;
                if (file.isDirectory()) {
                    stream = new FileInputStream(cacheKey);
                } else {
                    ZipInputStream zin = new ZipInputStream(new FileInputStream(file));

                    ZipEntry entry;
                    boolean found = false;
                    while ((entry = zin.getNextEntry()) != null) {
                        if (entry.getName().equalsIgnoreCase(idlFileName)) {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                        new CorbaInvocationException("cannot find " + idlFileName + " in " + file.getPath());

                    stream = zin;
                }*/
                InputStream stream = new PreProcessorInputStream(dirName, idlFileName);
                //TODO: Set pre-processor system and user input paths
                IDLProcessor idlProcessor = new IDLProcessor(stream);
                idl = idlProcessor.process();
                stream.close();
                IDL_CACHE.put(cacheKey, idl);
            } catch (IOException e) {
                throw new CorbaInvocationException("cannot process idl file", e);
            }
        }

        Map types = idl.getCompositeDataTypes();
        if (types!=null) {
            Iterator iter = types.values().iterator();
            while (iter.hasNext()) {
                DataType type =  (DataType) iter.next();
                if (type instanceof ValueType) {
                    StreamableValueFactory.register(orb, (ValueType) type);
                }
            }
        }
        return idl;
    }

    public static Invoker getInvoker(AxisService service, org.omg.CORBA.Object obj, IDL idl, String methodName) throws CorbaInvocationException {
        InvokerFactory invokerFactory = new CorbaInvokerFactory(idl);
        Parameter interfaceName = service.getParameter(INTERFACE_NAME);
        if (interfaceName==null)
            throw new CorbaInvocationException("interfaceName cannot be null");
        return invokerFactory.newInvoker(((String) interfaceName.getValue()).trim(), methodName, obj);
    }

    public static Object[] extractParameters(OMElement methodElement, Member[] parameterMembers, SchemaToIDLMapping mapping) throws CorbaInvocationException {
        if (parameterMembers==null)
            return new Object[0];

        Object[] retObjs = new Object[parameterMembers.length];

        if (methodElement==null)
            return retObjs;

        Iterator paramsIter = methodElement.getChildElements();
        Map paramsMap = new HashMap();
        String localName;
        while(paramsIter!=null && paramsIter.hasNext()) {
            OMElement param = (OMElement) paramsIter.next();
            localName = param.getLocalName();
            if (paramsMap.containsKey(localName)) {
                Object value = paramsMap.get(localName);
                if (value instanceof List) {
                    ((List) value).add(param);
                } else {
                    List valueList = new ArrayList();
                    valueList.add(value);
                    valueList.add(param);
                    paramsMap.put(localName, valueList);
                }
            } else {
                paramsMap.put(localName, param);
            }
        }

        String paramName;
        for (int i = 0; i < parameterMembers.length; i++) {
            paramName = parameterMembers[i].getName();
            retObjs[i] = extractValue(parameterMembers[i].getDataType(), paramsMap.get(paramName), mapping);
        }
        return retObjs;
    }

    private static Object extractValue(DataType dataType, Object param, SchemaToIDLMapping mapping) throws CorbaInvocationException {
        if (param == null) {
            return null;
        }

        if (dataType instanceof Typedef) {
            Typedef typedef = (Typedef) dataType;
            AliasValue aliasValue = new AliasValue(typedef);
            OMElement paramElement;
            if (param instanceof OMElement)
                paramElement = (OMElement) param;
            else
                return null;

            DataType aliasType = typedef.getDataType();
            if (!(aliasType instanceof AbstractCollectionType || aliasType instanceof FixedType)) {
                paramElement = paramElement.getFirstElement();
                if (paramElement == null || !ARRAY_ITEM.equals(paramElement.getLocalName()))
                    return null;
            }
            aliasValue.setValue(extractValue(aliasType, paramElement, mapping));
            return aliasValue;
        } else if (dataType instanceof PrimitiveDataType) {
            if (param!=null)
                return parseValue(dataType, ((OMElement) param).getText());
        } else if (dataType instanceof AbstractCollectionType) {
            AbstractCollectionType collectionType = (AbstractCollectionType) dataType;
            OMElement paramElement;
            if (param instanceof OMElement)
                paramElement = (OMElement) param;
            else
                return null;

            Iterator paramsIter = paramElement.getChildElements();
            List children = new ArrayList();
            while (paramsIter.hasNext()) {
                children.add(extractValue(collectionType.getDataType(), paramsIter.next(), mapping));
            }

            AbstractCollectionValue collectionValue;
            if (collectionType.isArray()) {
                collectionValue = new ArrayValue((ArrayType) collectionType);
            } else if (collectionType.isSequence()) {
                collectionValue = new SequenceValue((SequenceType) collectionType);
            } else {
                return null;
            }

            collectionValue.setValues(children.toArray());
            return collectionValue;
        } else if (dataType instanceof EnumType) {
            EnumType enumType = (EnumType) dataType;
            String enumText = ((OMElement) param).getText();
            int index = enumType.getEnumMembers().indexOf(enumText);
            if (index >= 0) {
                EnumValue enumValue = new EnumValue(enumType);
                enumValue.setValue(index);
                return enumValue;
            }
        } else if (dataType instanceof UnionType) {
            UnionType unionType = (UnionType) dataType;
            OMElement unElement = ((OMElement) param).getFirstElement();
            String unionMemberName = unElement.getLocalName();
            UnionValue unionValue = new UnionValue(unionType);
            unionValue.setMemberName(unionMemberName);
            Member[] members = unionType.getMembers();
            UnionMember member = null;
            for (int i = 0; i < members.length; i++) {
                member = (UnionMember) members[i];
                if (member.getName().equals(unionMemberName)) {
                    break;
                }
            }
            if (member != null) {
                unionValue.setMemberValue(extractValue(member.getDataType(), unElement, mapping));
            }
            return unionValue;
        } else if (dataType instanceof CompositeDataType) {
            CompositeDataType compositeType = (CompositeDataType) dataType;
            Member[] compositeMembers = compositeType.getMembers();
            Object[] compositeValues = extractParameters(((OMElement) param), compositeMembers, mapping);

            AbstractValue value;
            if (compositeType instanceof ValueType)
                value = new ObjectByValue((ValueType) compositeType);
            else if (compositeType instanceof Struct)
                value = new StructValue((Struct) compositeType);
            else
                throw new CorbaInvocationException("Parameter type not supported");

            value.setMemberValues(compositeValues);
            return value;
        } else if (dataType instanceof AnyType) {
            OMElement anyElement = (OMElement) param;
            DefaultNamespaceGenerator namespaceGenerator = new DefaultNamespaceGenerator();
            String defaultNamespace = namespaceGenerator.schemaNamespaceFromPackageName("").toString();

            OMElement typeElement = anyElement.getFirstChildWithName(new QName(defaultNamespace, "type"));

            if (typeElement != null) {

                OMElement definitionElement = typeElement.getFirstChildWithName(new QName(defaultNamespace, "definition"));
                OMElement typenameElement = typeElement.getFirstChildWithName(new QName(defaultNamespace, "typename"));
                OMElement anyValueElement = anyElement.getFirstChildWithName(new QName(defaultNamespace, "value"));

                if (typenameElement != null && anyValueElement != null) {

                    String typeName = typenameElement.getText();
                    String definition = definitionElement != null ? definitionElement.getText() : Constants.URI_DEFAULT_SCHEMA_XSD;
                    Object anyContent;
                    DataType anyValueType;
                    if (definition.equals(Constants.URI_DEFAULT_SCHEMA_XSD)) {
                        String anyValueString = anyValueElement.getText();
                        if (typeName.equals("boolean")) {
                            anyValueType = PrimitiveDataType.getPrimitiveDataType("boolean");
                            anyContent = Boolean.parseBoolean(anyValueString);
                        } else if (typeName.equals("double")) {
                            anyValueType = PrimitiveDataType.getPrimitiveDataType("double");
                            anyContent = Double.parseDouble(anyValueString);
                        } else if (typeName.equals("float")) {
                            anyValueType = PrimitiveDataType.getPrimitiveDataType("float");
                            anyContent = Float.parseFloat(anyValueString);
                        } else if (typeName.equals("unsignedByte")) {
                            anyValueType = PrimitiveDataType.getPrimitiveDataType("octet");
                            anyContent = Byte.parseByte(anyValueString);
                        } else if (typeName.equals("int")) {
                            anyValueType = PrimitiveDataType.getPrimitiveDataType("long");
                            anyContent = Integer.parseInt(anyValueString);
                        } else if (typeName.equals("long")) {
                            anyValueType = PrimitiveDataType.getPrimitiveDataType("longlong");
                            anyContent = Long.parseLong(anyValueString);
                        } else if (typeName.equals("short")) {
                            anyValueType = PrimitiveDataType.getPrimitiveDataType("short");
                            anyContent = Short.parseShort(anyValueString);
                        } else if (typeName.equals("string")) {
                            anyValueType = PrimitiveDataType.getPrimitiveDataType("string");
                            anyContent = anyValueString;
                        } else if (typeName.equals("unsignedShort")) {
                            anyValueType = PrimitiveDataType.getPrimitiveDataType("ushort");
                            anyContent = Short.parseShort(anyValueString);
                        } else if (typeName.equals("unsignedInt")) {
                            anyValueType = PrimitiveDataType.getPrimitiveDataType("ulong");
                            anyContent = Integer.parseInt(anyValueString);
                        } else if (typeName.equals("unsignedLong")) {
                            anyValueType = PrimitiveDataType.getPrimitiveDataType("ulonglong");
                            anyContent = Long.parseLong(anyValueString);
                        } else {
                            throw new CorbaInvocationException("Unsupported data type: " + typeName);
                        }
                    } else {
                        anyValueType = mapping.getDataType(new QName(definition, typeName));
                        if (anyValueType != null) {
                            anyContent = CorbaUtil.extractValue(anyValueType, anyValueElement.getFirstElement(), mapping);
                        } else {
                            throw new CorbaInvocationException("Unsupported data schema: " + definition + " type:" + typeName);
                        }
                    }
                    AnyValue anyValue = new AnyValue();
                    anyValue.setContent(anyContent);
                    anyValue.setContentType(anyValueType);
                    return anyValue;
                }
            }
        } else if (dataType instanceof FixedType) {
            return new BigDecimal(((OMElement) param).getText());
        }
        return null;
    }

    public static void processResponse(Object resObject,
                                       Member[] params,
                                       Object[] outParamValues,
                                       DataType dataType,
                                       AxisService service,
                                       String methodName,
                                       SOAPFactory fac,
                                       String messageNameSpace,
                                       MessageContext outMessage) throws AxisFault {
        boolean qualified = service.isElementFormDefault();
        OMNamespace ns = fac.createOMNamespace(messageNameSpace, service.getSchemaTargetNamespacePrefix());
        OMElement bodyContent = fac.createOMElement(methodName + RESPONSE, ns);
        OMElement child;

        if (qualified) {
            child = fac.createOMElement(RETURN_WRAPPER, ns);
        } else {
            child = fac.createOMElement(RETURN_WRAPPER, null);
        }
        bodyContent.addChild(child);

        if (dataType!=null
                && !getQualifiedName(dataType).equals(VOID)
                && resObject!=null) {
            processResponse(child, bodyContent, resObject, dataType, fac, ns, qualified, service);
        } else {
            child.addAttribute("nil", "true", fac.createOMNamespace(Constants.URI_2001_SCHEMA_XSI,
                    Constants.NS_PREFIX_SCHEMA_XSI));
        }

        Member param;
        List outParamList = Arrays.asList(outParamValues);
        Iterator paramsIter = outParamList.iterator();
        for (int i = 0; i < params.length; i++) {
            param = params[i];
            if (Member.MODE_INOUT.equals(param.getMode())
                    || Member.MODE_OUT.equals(param.getMode())) {
                if (qualified) {
                    child = fac.createOMElement(param.getName(), ns);
                } else {
                    child = fac.createOMElement(param.getName(), null);
                }
                bodyContent.addChild(child);
                processResponse(child, bodyContent, paramsIter.next(), param.getDataType(), fac, ns, qualified, service);
            }
        }

        SOAPEnvelope envelope = fac.getDefaultEnvelope();
        envelope.getBody().addChild(bodyContent);
        outMessage.setEnvelope(envelope);
    }

    private static void processResponse(OMElement child, OMElement bodyContent, Object resObject, DataType dataType,
                                        SOAPFactory fac, OMNamespace defaultNS, boolean qualified, AxisService service) throws AxisFault {
        if (dataType instanceof PrimitiveDataType) {
            child.addChild(fac.createOMText(child, resObject.toString()));
        } else if (dataType instanceof Typedef) {
            Typedef typedef = (Typedef) dataType;
            AliasValue aliasValue = (AliasValue) resObject;
            OMNamespace ns = getNameSpaceForType(fac, service, typedef);
            OMElement item = fac.createOMElement(ARRAY_ITEM, ns, child);
            processResponse(item, child, aliasValue.getValue(), typedef.getDataType(), fac, ns, qualified, service);
        } else if (dataType instanceof FixedType) {
            child.addChild(fac.createOMText(child, resObject.toString()));
        } else if (dataType instanceof AbstractCollectionType) {
            AbstractCollectionType collectionType = (AbstractCollectionType) dataType;
            AbstractCollectionValue collectionValue = (AbstractCollectionValue) resObject;
            Object[] values = collectionValue.getValues();
            int length = values.length;
            for (int i=0; i<length; i++) {
                OMElement outer = bodyContent;
                if (collectionType.getDataType() instanceof AbstractCollectionType) {
                    outer = child;
                    if (qualified) {
                        child = fac.createOMElement(ARRAY_ITEM, defaultNS);
                    } else {
                        child = fac.createOMElement(ARRAY_ITEM, null);
                    }
                    outer.addChild(child);
                }
                processResponse(child, outer, values[i], collectionType.getDataType(), fac, defaultNS, qualified, service);
                if (i < (length -1)) {
                    if (qualified) {
                        child = fac.createOMElement(ARRAY_ITEM, defaultNS);
                    } else {
                        child = fac.createOMElement(ARRAY_ITEM, null);
                    }
                    bodyContent.addChild(child);
                }
            }
        } else if (dataType instanceof ValueType || dataType instanceof Struct) {
            AbstractValue resValue = (AbstractValue) resObject;
            Member[] members = resValue.getMembers();
            Object[] memberValues = resValue.getMemberValues();
            OMNamespace ns = getNameSpaceForType(fac, service, (CompositeDataType) dataType);
            for (int i = 0; i < memberValues.length; i++) {
                OMElement memberElement = fac.createOMElement(members[i].getName(), ns);
                processResponse(memberElement, bodyContent, memberValues[i], members[i].getDataType(), fac, ns, qualified, service);
                child.addChild(memberElement);
            }
        } else if (dataType instanceof UnionType) {
            UnionValue unionValue = (UnionValue) resObject;
            OMElement unMember;
            OMNamespace ns = getNameSpaceForType(fac, service, (CompositeDataType) dataType);
            if (qualified) {
                unMember = fac.createOMElement(unionValue.getMemberName(), ns);
            } else {
                unMember = fac.createOMElement(unionValue.getMemberName(), null);
            }
            processResponse(unMember, child, unionValue.getMemberValue(), unionValue.getMemberType(), fac, ns, qualified, service);
            child.addChild(unMember);
        } else if (dataType instanceof EnumType) {
            EnumValue enumValue = (EnumValue) resObject;
            child.addChild(fac.createOMText(child, enumValue.getValueAsString()));
        } else if (dataType instanceof AnyType) {
            Any any = (Any) resObject;
            TypeCode typeCode = any.type();
            DataType contentDataType;
            String dataTypeNameSpaceURI;
            if (PrimitiveDataType.isPrimitive(typeCode)) {
                contentDataType = new PrimitiveDataType(typeCode);
                dataTypeNameSpaceURI = Constants.URI_DEFAULT_SCHEMA_XSD;
            } else if (TCKind._tk_any == typeCode.kind().value()) {
                dataTypeNameSpaceURI = Constants.URI_DEFAULT_SCHEMA_XSD;
                contentDataType = new AnyType();
            } else {
                try {
                    String id = typeCode.id();
                    IDL idl = (IDL) service.getParameterValue(IDL_LITERAL);
                    Map complexTypes = idl.getCompositeDataTypes();
                    String typeKey = id.substring(id.indexOf(":") + 1, id.lastIndexOf(":")).replaceAll("/", "::");
                    contentDataType = (DataType) complexTypes.get(typeKey);
                    OMNamespace namespace = getNameSpaceForType(fac, service, (CompositeDataType) contentDataType);
                    dataTypeNameSpaceURI = namespace.getNamespaceURI();
                } catch (BadKind badKind) {
                    throw AxisFault.makeFault(badKind);
                }
            }

            if (contentDataType == null) {
                throw new AxisFault("can't find the data type of the returned value.");
            }

            Object value = CorbaUtil.extractValue(contentDataType, any);

            TypeTable typeTable = service.getTypeTable();
            QName anySchema = typeTable.getComplexSchemaType(CorbaConstants.ANY_TYPE_NAME);
            if (anySchema == null) {
                throw new AxisFault("CORBA.Any schema type is not defined.");
            }
            String defaultNSURI = anySchema.getNamespaceURI();
            String defaultNSPrefix = anySchema.getPrefix();

            OMElement valueElement = fac.createOMElement(new QName(defaultNSURI, "value", defaultNSPrefix));
            processResponse(valueElement, child, value, contentDataType, fac, defaultNS, qualified, service);
            child.addChild(valueElement);

            OMElement definitionElement =  fac.createOMElement(new QName(defaultNSURI, "definition", defaultNSPrefix));
            definitionElement.addChild(fac.createOMText(dataTypeNameSpaceURI));

            OMElement typeNameElement =  fac.createOMElement(new QName(defaultNSURI, "typename", defaultNSPrefix));
            String typeName;
            if (contentDataType instanceof PrimitiveDataType) {
               typeName = ((PrimitiveDataType) contentDataType).getTypeName();
               if (String.class.getName().equals(typeName)) {
                   typeName = "string";
               }
            } else if (contentDataType instanceof CompositeDataType) {
               typeName = ((CompositeDataType) contentDataType).getName();
            } else if (contentDataType instanceof AnyType) {
               typeName = CorbaConstants.ANY_TYPE_NAME;
            } else {
                throw new AxisFault("Invalid return type");
            }

            typeNameElement.addChild(fac.createOMText(typeName));

            OMElement typeElement =  fac.createOMElement(new QName(defaultNSURI, "type", defaultNSPrefix));
            typeElement.addChild(definitionElement);
            typeElement.addChild(typeNameElement);
            child.addChild(typeElement);
        }
    }

    private static OMNamespace getNameSpaceForType(SOAPFactory fac, AxisService service, CompositeDataType dataType) {
        TypeTable typeTable = service.getTypeTable();
        String fullname = (dataType.getModule()!=null) ? dataType.getModule() + dataType.getName() : dataType.getName();
        fullname = fullname.replaceAll(CompositeDataType.MODULE_SEPERATOR, ".");
        QName qname = typeTable.getQNamefortheType(fullname);
        if (qname==null)
            return null;
        return fac.createOMNamespace(qname.getNamespaceURI(), qname.getPrefix());
    }

    public static String getQualifiedName(DataType type){
        if (type instanceof CompositeDataType) {
            CompositeDataType compositeType = (CompositeDataType) type;
            String module = compositeType.getModule();
            module = (module == null) ? "" : module.replaceAll("::", ".");
            return  module + compositeType.getName();
        } else if (type instanceof PrimitiveDataType) {
            PrimitiveDataType primitiveDataType = (PrimitiveDataType) type;
            return primitiveDataType.getTypeName();
        } else if (type instanceof AnyType) {
            return CorbaConstants.ANY_TYPE_NAME;
        }
        return null;
    }

    public static void insertValue(Any arg, DataType type, Object value) {
        switch(type.getTypeCode().kind().value()) {
            case TCKind._tk_long: arg.insert_long(((Integer) value).intValue()); break;
            case TCKind._tk_ulong: arg.insert_ulong(((Integer) value).intValue()); break;
            case TCKind._tk_longlong: arg.insert_longlong(((Long) value).longValue()); break;
            case TCKind._tk_ulonglong: arg.insert_ulonglong(((Long) value).longValue()); break;
            case TCKind._tk_short: arg.insert_short(((Short) value).shortValue()); break;
            case TCKind._tk_ushort: arg.insert_ushort(((Short) value).shortValue()); break;
            case TCKind._tk_float: arg.insert_float(((Float) value).floatValue()); break;
            case TCKind._tk_double: arg.insert_double(((Double) value).floatValue()); break;
            case TCKind._tk_char: arg.insert_char(((Character) value).charValue()); break;
            case TCKind._tk_wchar: arg.insert_wchar(((Character) value).charValue()); break;
            case TCKind._tk_boolean: arg.insert_boolean(((Boolean) value).booleanValue()); break;
            case TCKind._tk_octet: arg.insert_octet(((Byte) value).byteValue()); break;
            case TCKind._tk_string: arg.insert_string((String) value); break;
            case TCKind._tk_wstring: arg.insert_wstring((String) value); break;
            case TCKind._tk_value: arg.insert_Value((Serializable) value); break;
            case TCKind._tk_objref: arg.insert_Object((org.omg.CORBA.Object) value); break;
            case TCKind._tk_any:
                AnyValue anyValue = (AnyValue) value;
                Any any = ORB.init().create_any();
                CorbaUtil.insertValue(any, anyValue.getContentType(), anyValue.getContent());
                arg.insert_any(any);
                break;
            case TCKind._tk_struct:
                StructValue structValue = (StructValue) value;
                org.omg.CORBA_2_3.portable.OutputStream outputStream = (org.omg.CORBA_2_3.portable.OutputStream) arg.create_output_stream();
                arg.type(structValue.getTypeCode());
                structValue.write(outputStream);
                arg.read_value(outputStream.create_input_stream (), structValue.getTypeCode());
                break;
            case TCKind._tk_enum:
                EnumValue enumValue = (EnumValue) value;
                outputStream = (org.omg.CORBA_2_3.portable.OutputStream) arg.create_output_stream();
                arg.type(enumValue.getTypeCode());
                enumValue.write(outputStream);
                arg.read_value(outputStream.create_input_stream (), enumValue.getTypeCode());
                break;
            case TCKind._tk_union:
                UnionValue unionValue = (UnionValue) value;
                outputStream = (org.omg.CORBA_2_3.portable.OutputStream) arg.create_output_stream();
                arg.type(unionValue.getTypeCode());
                unionValue.write(outputStream);
                arg.read_value(outputStream.create_input_stream (), unionValue.getTypeCode());
                break;
            case TCKind._tk_alias:
                AliasValue aliasValue = (AliasValue) value;
                outputStream = (org.omg.CORBA_2_3.portable.OutputStream) arg.create_output_stream();
                arg.type(aliasValue.getTypeCode());
                aliasValue.write(outputStream);//TODO: returning fixed variables, inside structs, etc.
                arg.read_value(outputStream.create_input_stream (), aliasValue.getTypeCode());
                break;
            case TCKind._tk_sequence:
                SequenceValue sequenceValue = (SequenceValue) value;
                outputStream = (org.omg.CORBA_2_3.portable.OutputStream) arg.create_output_stream();
                arg.type(sequenceValue.getTypeCode());
                sequenceValue.write(outputStream);
                arg.read_value(outputStream.create_input_stream (), sequenceValue.getTypeCode());
                break;
            case TCKind._tk_array:
                ArrayValue arrayValue = (ArrayValue) value;
                outputStream = (org.omg.CORBA_2_3.portable.OutputStream) arg.create_output_stream();
                arg.type(arrayValue.getTypeCode());
                arrayValue.write(outputStream);
                arg.read_value(outputStream.create_input_stream (), arrayValue.getTypeCode());
                break;
            default:
                log.error("ERROR! Invalid dataType");
                break;
        }
    }

    public static Object extractValue(DataType returnType, Any returned) {
        Object returnValue = null;
        TypeCode typeCode = returnType.getTypeCode();
        switch(typeCode.kind().value()) {
            case TCKind._tk_void: returnValue = null; break;
            case TCKind._tk_long: returnValue = new Integer(returned.extract_long()); break;
            case TCKind._tk_ulong: returnValue = new Integer(returned.extract_ulong()); break;
            case TCKind._tk_longlong: returnValue = new Long(returned.extract_longlong()); break;
            case TCKind._tk_ulonglong: returnValue = new Long(returned.extract_ulonglong()); break;
            case TCKind._tk_short: returnValue = new Short(returned.extract_short()); break;
            case TCKind._tk_ushort: returnValue = new Short(returned.extract_ushort()); break;
            case TCKind._tk_float: returnValue = new Float(returned.extract_float()); break;
            case TCKind._tk_double: returnValue = new Double(returned.extract_double()); break;
            case TCKind._tk_char: returnValue = new Character(returned.extract_char()); break;
            case TCKind._tk_wchar: returnValue = new Character(returned.extract_wchar()); break;
            case TCKind._tk_boolean: returnValue = Boolean.valueOf(returned.extract_boolean()); break;
            case TCKind._tk_octet: returnValue = new Byte(returned.extract_octet()); break;
            case TCKind._tk_string: returnValue = returned.extract_string(); break;
            case TCKind._tk_wstring: returnValue = returned.extract_wstring(); break;
            case TCKind._tk_any: returnValue = returned.extract_any(); break;
            case TCKind._tk_value: returnValue = returned.extract_Value(); break;
            case TCKind._tk_objref: returnValue = returned.extract_Object(); break;
            //case TCKind._tk_longdouble :
            case TCKind._tk_struct:
                Struct struct = (Struct) returnType;
                StructValue structValue = new StructValue(struct);
                org.omg.CORBA_2_3.portable.InputStream inputStream = (org.omg.CORBA_2_3.portable.InputStream) returned.create_input_stream();
                structValue.read(inputStream);
                returnValue = structValue;
                break;
            case TCKind._tk_except:
                ExceptionType exceptionType = (ExceptionType) returnType;
                ExceptionValue exceptionValue = new ExceptionValue(exceptionType);
                inputStream = (org.omg.CORBA_2_3.portable.InputStream) returned.create_input_stream();
                exceptionValue.read(inputStream);
                returnValue = exceptionValue;
                break;
            case TCKind._tk_enum:
                EnumType enumType = (EnumType) returnType;
                EnumValue enumValue = new EnumValue(enumType);
                inputStream = (org.omg.CORBA_2_3.portable.InputStream) returned.create_input_stream();
                enumValue.read(inputStream);
                returnValue = enumValue;
                break;
            case TCKind._tk_union:
                UnionType unionType = (UnionType) returnType;
                inputStream = (org.omg.CORBA_2_3.portable.InputStream) returned.create_input_stream();
                UnionValue unionValue = new UnionValue(unionType);
                unionValue.read(inputStream);
                returnValue = unionValue;
                break;
            case TCKind._tk_alias:
                Typedef typedef = (Typedef) returnType;
                inputStream = (org.omg.CORBA_2_3.portable.InputStream) returned.create_input_stream();
                AliasValue aliasValue = new AliasValue(typedef);
                aliasValue.read(inputStream);
                returnValue = aliasValue;
                break;
            case TCKind._tk_sequence:
                SequenceType sequenceType = (SequenceType) returnType;
                inputStream = (org.omg.CORBA_2_3.portable.InputStream) returned.create_input_stream();
                SequenceValue sequenceValue = new SequenceValue(sequenceType);
                sequenceValue.read(inputStream);
                returnValue = sequenceValue;
                break;
            case TCKind._tk_array:
                ArrayType arrayType = (ArrayType) returnType;
                inputStream = (org.omg.CORBA_2_3.portable.InputStream) returned.create_input_stream();
                ArrayValue arrayValue = new ArrayValue(arrayType);
                arrayValue.read(inputStream);
                returnValue = arrayValue;
                break;
            default:
                log.error("ERROR! Invalid dataType");
                break;
        }
        return returnValue;
    }

    public static Object parseValue(DataType type, String value) {
        if (value == null)
            return null;
        value = value.trim();
        Object ret = null;
        int kind = type.getTypeCode().kind().value();
        switch(kind) {
            case TCKind._tk_long : ret = Integer.valueOf(value); break;
            case TCKind._tk_ulong : ret = Integer.valueOf(value); break;
            case TCKind._tk_longlong : ret = Long.valueOf(value); break;
            case TCKind._tk_ulonglong : ret = Long.valueOf(value); break;
            case TCKind._tk_short : ret = Short.valueOf(value); break;
            case TCKind._tk_ushort : ret = Short.valueOf(value); break;
            case TCKind._tk_float : ret = Float.valueOf(value); break;
            case TCKind._tk_double : ret = Double.valueOf(value); break;
            case TCKind._tk_char : ret = Character.valueOf(value.charAt(0)); break;
            case TCKind._tk_wchar : ret = Character.valueOf(value.charAt(0)); break;
            case TCKind._tk_boolean : ret = Boolean.valueOf(value); break;
            case TCKind._tk_octet : ret = Byte.valueOf(value); break;
            case TCKind._tk_string : ret = value; break;
            case TCKind._tk_wstring : ret = value; break;
            case TCKind._tk_enum :
                EnumType enumType = (EnumType) type;
                EnumValue enumValue = new EnumValue(enumType);
                int i = enumType.getEnumMembers().indexOf(value);
                enumValue.setValue(i);
                ret = enumValue;
                break;
            case TCKind._tk_alias:
                Typedef typedef = (Typedef) type;
                AliasValue aliasValue = new AliasValue(typedef);
                aliasValue.setValue(parseValue(typedef.getDataType(), value));
                ret = aliasValue;
                break;
            default:
                log.error("ERROR! Invalid dataType (" + kind + ")");
                break;
        }
        return ret;
    }

    public static Object getEmptyValue(DataType type) {
        switch(type.getTypeCode().kind().value()) {
            case TCKind._tk_long: return new Integer(0);
            case TCKind._tk_ulong: return new Integer(0);
            case TCKind._tk_longlong: return new Long(0);
            case TCKind._tk_ulonglong: return new Long(0);
            case TCKind._tk_short: return new Short("0");
            case TCKind._tk_ushort: return new Short("0");
            case TCKind._tk_float: return new Float(0f);
            case TCKind._tk_double: return new Double(0d);
            case TCKind._tk_char: return new Character('0');
            case TCKind._tk_wchar: return new Character('0');
            case TCKind._tk_boolean: return Boolean.FALSE;
            case TCKind._tk_octet: return new Byte("0");
            case TCKind._tk_string: return "";
            case TCKind._tk_wstring: return "";
            case TCKind._tk_value: return "";
            //case TCKind._tk_objref: return new org.omg.CORBA.Object();
            case TCKind._tk_any:
                AnyValue anyValue = new AnyValue();
                anyValue.setContentType(PrimitiveDataType.getPrimitiveDataType("string"));
                anyValue.setContent("");
                return anyValue;
            case TCKind._tk_struct:
                Struct struct = (Struct) type;
                StructValue value = new StructValue(struct);
                Member[] members = struct.getMembers();
                Object[] memberValues = new Object[members.length];
                for (int i = 0; i < members.length; i++) {
                    memberValues[i] = getEmptyValue(members[i].getDataType());
                }
                value.setMemberValues(memberValues);
                return value;
            case TCKind._tk_enum: return new EnumValue((EnumType) type);
            case TCKind._tk_union:
                UnionType unionType = (UnionType) type;
                UnionValue unionValue = new UnionValue(unionType);
                members = unionType.getMembers();
                unionValue.setMemberName(members[0].getName());
                unionValue.setMemberType(members[0].getDataType());
                unionValue.setMemberValue(getEmptyValue(members[0].getDataType()));
                return unionValue;
            case TCKind._tk_alias:
                Typedef typedef = (Typedef) type;
                AliasValue aliasValue = new AliasValue(typedef);
                aliasValue.setValue(getEmptyValue(typedef.getDataType()));
                return aliasValue;
            case TCKind._tk_sequence:
                SequenceType sequenceType = (SequenceType) type;
                SequenceValue sequenceValue = new SequenceValue(sequenceType);
                sequenceValue.setValues(new Object[0]);
                return sequenceValue;
            case TCKind._tk_array:
                ArrayType arrayType = (ArrayType) type;
                ArrayValue arrayValue = new ArrayValue(arrayType);
                Object[] objects = new Object[arrayType.getElementCount()];
                DataType arrayDataType = arrayType.getDataType();
                for (int i = 0; i < objects.length; i++) {
                    objects[i] = getEmptyValue(arrayDataType);
                }
                arrayValue.setValues(objects);
                return arrayValue;
            default:
                log.error("ERROR! Invalid dataType");
        }
        return null;
    }
}
