/*
 * Redistribution and use of this software and associated documentation ("Software"), with or
 * without modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
 * must also contain a copy of this document.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or other materials provided with
 * the distribution.
 *
 * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
 * without prior written permission of Intalio, Inc. For written permission, please contact
 * info@exolab.org.
 *
 * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
 * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
 * Intalio, Inc.
 *
 * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
 *
 * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Copyright 1999-2004 (C) Intalio Inc. All Rights Reserved.
 *
 * This file was originally developed by Keith Visco during the course of employment at Intalio Inc.
 * Portions of this file developed by Keith Visco after Jan 19 2005 are Copyright (C) 2005 Keith
 * Visco. All Rights Reserverd.
 *
 * $Id$
 */
package org.exolab.castor.builder.factory;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.exolab.castor.builder.BuilderConfiguration;
import org.exolab.castor.builder.ClassInfoResolver;
import org.exolab.castor.builder.GroupNaming;
import org.exolab.castor.builder.SGTypes;
import org.exolab.castor.builder.SourceGenerator;
import org.exolab.castor.builder.SourceGeneratorConstants;
import org.exolab.castor.builder.binding.XMLBindingComponent;
import org.exolab.castor.builder.info.ClassInfo;
import org.exolab.castor.builder.info.CollectionInfo;
import org.exolab.castor.builder.info.FieldInfo;
import org.exolab.castor.builder.info.XMLInfo;
import org.exolab.castor.builder.info.NodeType;
import org.exolab.castor.builder.info.nature.XMLInfoNature;
import org.exolab.castor.builder.types.XSList;
import org.exolab.castor.builder.types.XSListType;
import org.exolab.castor.builder.types.XSClass;
import org.exolab.castor.builder.types.XSString;
import org.exolab.castor.builder.types.XSType;
import org.exolab.castor.xml.schema.AttributeDecl;
import org.exolab.castor.xml.schema.ComplexType;
import org.exolab.castor.xml.schema.ElementDecl;
import org.exolab.castor.xml.schema.Facet;
import org.exolab.castor.xml.schema.Group;
import org.exolab.castor.xml.schema.Order;
import org.exolab.castor.xml.schema.Schema;
import org.exolab.castor.xml.schema.SchemaNames;
import org.exolab.castor.xml.schema.SimpleType;
import org.exolab.castor.xml.schema.Structure;
import org.exolab.castor.xml.schema.Wildcard;
import org.exolab.castor.xml.schema.XMLType;
import org.exolab.castor.xml.schema.simpletypes.ListType;
import org.exolab.javasource.JArrayType;
import org.exolab.javasource.JClass;
import org.exolab.javasource.JPrimitiveType;
import org.exolab.javasource.JType;

/**
 * The "Factory" responsible for creating fields for the given schema components.
 *
 * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
 * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
 */
public final class MemberFactory extends BaseFactory {

  /**
   * Creates a new MemberFactory using the given FieldInfo factory.
   *
   * @param config the BuilderConfiguration
   * @param infoFactory the FieldInfoFactory to use
   * @param groupNaming Grou pnaming scheme to be used.
   * @param sourceGenerator Calling source generator
   */
  public MemberFactory(final BuilderConfiguration config, final FieldInfoFactory infoFactory,
      final GroupNaming groupNaming, final SourceGenerator sourceGenerator) {
    super(config, infoFactory, groupNaming, sourceGenerator);

    if (getConfig().generateExtraCollectionMethods()) {
      this.getInfoFactory().setCreateExtraMethods(true);
    }
    String suffix = getConfig().getProperty(CollectionInfo.REFERENCE_SUFFIX_PROPERTY, null);
    this.getInfoFactory().setReferenceMethodSuffix(suffix);

    if (getConfig().boundPropertiesEnabled()) {
      this.getInfoFactory().setBoundProperties(true);
    }
  } // -- MemberFactory

  /**
   * Creates a FieldInfo for content models that support "any" element.
   *
   * @param any the wildcard we will operate on
   * @param useJava50 if true then we will generate code for Java 5
   *
   * @return the new FieldInfo
   */
  public FieldInfo createFieldInfoForAny(final Wildcard any, final boolean useJava50) {
    if (any == null) {
      return null;
    }

    // --currently anyAttribute is not supported
    if (any.isAttributeWildcard()) {
      return null;
    }

    XSType xsType = new XSClass(SGTypes.OBJECT, "any");
    String vName = "_anyObject";
    // if (getConfig().useOldFieldNaming()) {
    // StringUtils.leftPad(vName, 1, '_');
    // }
    String xmlName = null;
    FieldInfo result = null;

    if (any.getMaxOccurs() > 1 || any.getMaxOccurs() < 0) {
      result = this.getInfoFactory().createCollection(xsType, vName, "anyObject", getJavaNaming(),
          useJava50);
      XSListType xsList = ((CollectionInfo) result).getXSList();
      xsList.setMinimumSize(any.getMinOccurs());
      xsList.setMaximumSize(any.getMaxOccurs());
    } else {
      result = this.getInfoFactory().createFieldInfo(xsType, vName);
    }

    if (result.hasNature(XMLInfoNature.class.getName())) {
      XMLInfoNature xmlNature = new XMLInfoNature(result);

      if (any.getMinOccurs() > 0) {
        xmlNature.setRequired(true);
      } else {
        xmlNature.setRequired(false);
      }

      xmlNature.setNodeName(xmlName);

      // --LIMITATION:
      // -- 1- we currently support only the FIRST namespace
      // -- 2- ##other, ##any are not supported
      if (any.getNamespaces().hasMoreElements()) {
        String nsURI = (String) any.getNamespaces().nextElement();
        if (nsURI.length() > 0) {
          if (nsURI.equals("##targetNamespace")) {
            Schema schema = any.getSchema();
            if (schema != null) {
              xmlNature.setNamespaceURI(schema.getTargetNamespace());
            }
          } else if (!nsURI.startsWith("##")) {
            xmlNature.setNamespaceURI(nsURI);
          }
        }
      } // --first namespace
    }

    return result;
  }

  /**
   * Creates a FieldInfo to hold the value of a choice.
   *
   * @return the new FieldInfo
   */
  public FieldInfo createFieldInfoForChoiceValue() {
    String fieldName = "_choiceValue";
    // if (getConfig().useOldFieldNaming()) {
    // StringUtils.leftPad(fieldName, 1, '_');
    // }
    XSType xsType = new XSClass(SGTypes.OBJECT, "any");
    FieldInfo fInfo = null;
    fInfo = this.getInfoFactory().createFieldInfo(xsType, fieldName);
    fInfo.setComment("Internal choice value storage");
    fInfo.setTransient(true);
    fInfo.setMethods(FieldInfo.READ_METHOD);

    if (fInfo.hasNature(XMLInfoNature.class.getName())) {
      XMLInfoNature xmlNature = new XMLInfoNature(fInfo);

      xmlNature.setNodeType(NodeType.ELEMENT);
      xmlNature.setRequired(false);
      xmlNature.setNodeName("##any");
    }

    return fInfo;
  }

  /**
   * Creates a FieldInfo for content.
   * 
   * @param component {@link XMLBindingComponent} instance for accessing binding information.
   * @param xsType the type of content
   * @param useJava50 if true, code will be generated for Java 5
   *
   * @return the new FieldInfo
   */
  public FieldInfo createFieldInfoForContent(final XMLBindingComponent component,
      final XSType xsType, final boolean useJava50) {
    String fieldName = "content";// new xsType()???
    if (getConfig().useOldFieldNaming()) {
      StringUtils.leftPad(fieldName, 1, '_');
    }
    if (component.getContentMemberName() != null) {
      fieldName = component.getContentMemberName();
    }
    FieldInfo fInfo = null;
    if (xsType.isCollection()) {
      fInfo = this.getInfoFactory().createCollection(((XSListType) xsType).getContentType(),
          fieldName, null, getJavaNaming(), useJava50);
    } else {
      fInfo = this.getInfoFactory().createFieldInfo(xsType, fieldName);
    }
    fInfo.setComment("internal content storage");
    if (xsType instanceof XSString) {
      fInfo.setDefaultValue("\"\"");
    }
    if (fInfo.hasNature(XMLInfoNature.class.getName())) {
      XMLInfoNature xmlNature = new XMLInfoNature(fInfo);
      xmlNature.setNodeType(NodeType.TEXT);
      xmlNature.setRequired(false);
      xmlNature.setNodeName("#text");
    }
    return fInfo;
  }

  /**
   * Creates a FieldInfo object for the given XMLBindingComponent.
   *
   * @param component the XMLBindingComponent to create the FieldInfo for
   * @param resolver resolver to use to find ClassInfo
   * @param useJava50 if true, code will be generated for Java 5
   * @return the FieldInfo for the given attribute declaration
   */
  public FieldInfo createFieldInfo(final XMLBindingComponent component,
      final ClassInfoResolver resolver, final boolean useJava50) {
    String xmlName = component.getXMLName();
    String memberName = component.getJavaMemberName();
    if (getConfig().useOldFieldNaming()) {
      if (!memberName.startsWith("_")) {
        memberName = "_" + memberName;
      }
    }

    XMLType xmlType = component.getXMLType();

    ClassInfo classInfo = resolver.resolve(component);

    XSType xsType = null;
    FieldInfo fieldInfo = null;
    boolean enumeration = false;
    boolean simpleTypeCollection = false;

    if (xmlType != null) {
      if (xmlType.isSimpleType()) {
        SimpleType simpleType = (SimpleType) xmlType;

        SimpleType baseType = null;
        String derivationMethod = simpleType.getDerivationMethod();
        if (derivationMethod != null) {
          if (SchemaNames.RESTRICTION.equals(derivationMethod)) {
            baseType = (SimpleType) simpleType.getBaseType();
          }
        }

        // -- handle special case for enumerated types
        if (simpleType.hasFacet(Facet.ENUMERATION)) {
          // -- LOok FoR CLasSiNfO iF ReSoLvR is NoT NuLL
          enumeration = true;
          if (resolver != null) {
            classInfo = resolver.resolve(xmlType);
          }
          if (classInfo != null) {
            XMLInfoNature xmlNature = new XMLInfoNature(classInfo);
            xsType = xmlNature.getSchemaType();
          }
        } else if ((simpleType instanceof ListType) || (baseType instanceof ListType)) {
          if (baseType != null) {
            if (!baseType.isBuiltInType()) {
              simpleTypeCollection = true;
            }
          } else {
            if (!simpleType.isBuiltInType()) {
              simpleTypeCollection = true;
            }
          }

          // handle special case where the list type uses an item type
          // that has enumeration facets defined.
          ListType listType = (ListType) simpleType;
          if (listType == null) {
            listType = (ListType) baseType;
          }
          SimpleType itemType = listType.getItemType();
          if (itemType.hasFacet(Facet.ENUMERATION)) {
            ClassInfo itemClassInfo = resolver.resolve(itemType);
            if (itemClassInfo != null) {
              xsType = new XMLInfoNature(itemClassInfo).getSchemaType();
            } else {
              XMLBindingComponent temp = new XMLBindingComponent(getConfig(), getGroupNaming());
              temp.setBinding(component.getBinding());
              temp.setView(itemType);
              String packageName = temp.getJavaPackage();
              if (packageName != null && packageName.length() > 0) {
                packageName = packageName + "." + SourceGeneratorConstants.TYPES_PACKAGE;
              } else {
                packageName = SourceGeneratorConstants.TYPES_PACKAGE;
              }
              JClass tempClass = new JClass(packageName + "." + temp.getJavaClassName(),
                  getConfig().useOldFieldNaming());
              xsType = new XSClass(tempClass);
              xsType.setAsEnumerated(true);
            }
          }


        }

        if (xsType == null) {
          xsType = component.getJavaType();
        }
      } else if (xmlType.isAnyType()) {
        // -- Just treat as java.lang.Object.
        if (classInfo != null) {
          XMLInfoNature xmlNature = new XMLInfoNature(classInfo);
          xsType = xmlNature.getSchemaType();
        }
        if (xsType == null) {
          xsType = new XSClass(SGTypes.OBJECT);
        }
      } else if (xmlType.isComplexType() && (xmlType.getName() != null)) {
        // --if we use the type method then no class is output for
        // --the element we are processing
        if (getConfig().mappingSchemaType2Java()) {
          XMLBindingComponent temp = new XMLBindingComponent(getConfig(), getGroupNaming());
          temp.setBinding(component.getBinding());
          temp.setView(xmlType);
          ClassInfo typeInfo = resolver.resolve(xmlType);
          if (typeInfo != null) {
            // if we have not processed the <complexType> referenced
            // by the ClassInfo yet, this will return null
            // TODO find a way to resolve an unprocessed <complexType>
            XMLInfoNature xmlNature = new XMLInfoNature(typeInfo);
            xsType = xmlNature.getSchemaType();
          } else {
            String className = temp.getQualifiedName();
            if (className != null) {
              JClass jClass = new JClass(className, getConfig().useOldFieldNaming());
              if (((ComplexType) xmlType).isAbstract()) {
                jClass.getModifiers().setAbstract(true);
              }
              xsType = new XSClass(jClass);
              className = null;
            }
          }
        }
      } // complexType
    } else {
      if (xsType == null) {
        xsType = component.getJavaType();
      }

      if (xsType == null) {
        // -- patch for bug 1471 (No XMLType specified)
        // -- treat unspecified type as anyType
        switch (component.getAnnotated().getStructureType()) {
          case Structure.ATTRIBUTE:
            AttributeDecl attribute = (AttributeDecl) component.getAnnotated();
            if (!attribute.hasXMLType()) {
              xsType = new XSClass(SGTypes.OBJECT);
            }
            break;
          case Structure.ELEMENT:
            ElementDecl element = (ElementDecl) component.getAnnotated();
            if (!element.hasXMLType()) {
              xsType = new XSClass(SGTypes.OBJECT);
            }
            break;
          default:
            // probably a model-group
            break;
        }
      }
    }

    // is the XSType found?
    if (xsType == null) {
      String className = component.getQualifiedName();
      JClass jClass = new JClass(className, getConfig().useOldFieldNaming());
      if (component.isAbstract()) {
        jClass.getModifiers().setAbstract(true);
      }
      if (getConfig().isAutomaticConflictResolution()) {
        getSourceGenerator().getXMLInfoRegistry().bind(jClass, component, "field");
      }
      xsType = new XSClass(jClass);
      if (xmlType != null && xmlType.isComplexType()) {
        ComplexType complexType = (ComplexType) xmlType;
        if (complexType.isAbstract() || getConfig().mappingSchemaElement2Java()) {
          jClass.getModifiers().setAbstract(true);
        }
      }
      className = null;
    }

    // create the fieldInfo
    // check whether this should be a collection or not
    int maxOccurs = component.getUpperBound();
    int minOccurs = component.getLowerBound();
    if (simpleTypeCollection || ((maxOccurs < 0 || maxOccurs > 1) && !this.isChoice(component))) {
      String vName = memberName + "List";

      // if xmlName is null it means that
      // we are processing a container object (group)
      // so we need to adjust the name of the members of the collection
      CollectionInfo cInfo;
      cInfo = this.getInfoFactory().createCollection(xsType, vName, memberName,
          component.getCollectionType(), getJavaNaming(), useJava50);

      XSListType xsList = cInfo.getXSList();
      if (!simpleTypeCollection) {
        xsList.setMaximumSize(maxOccurs);
        xsList.setMinimumSize(minOccurs);
      } else {
        if (xsList instanceof XSList) {
          ((XSList) xsList).setDerivedFromXSList(true);
        }
      }
      fieldInfo = cInfo;
    } else {
      switch (xsType.getType()) {
        case XSType.ID_TYPE:
          fieldInfo = this.getInfoFactory().createIdentity(memberName);
          break;
        case XSType.COLLECTION:
        case XSType.IDREFS_TYPE:
        case XSType.NMTOKENS_TYPE:
          String collectionName = component.getCollectionType();
          XSType contentType = ((XSListType) xsType).getContentType();
          fieldInfo = this.getInfoFactory().createCollection(contentType, memberName, memberName,
              collectionName, getJavaNaming(), useJava50);
          break;
        default:
          fieldInfo = this.getInfoFactory().createFieldInfo(xsType, memberName);
          break;
      }
    }

    // initialize the field
    XMLInfoNature xmlNature = new XMLInfoNature(fieldInfo);
    xmlNature.setNodeName(xmlName);
    xmlNature.setRequired(minOccurs > 0);
    switch (component.getAnnotated().getStructureType()) {
      case Structure.ELEMENT:
        xmlNature.setNodeType(NodeType.ELEMENT);
        break;
      case Structure.ATTRIBUTE:
        xmlNature.setNodeType(NodeType.ATTRIBUTE);
        break;
      case Structure.MODELGROUP:
      case Structure.GROUP:
        xmlNature.setNodeName(XMLInfo.CHOICE_NODE_NAME_ERROR_INDICATION);
        fieldInfo.setContainer(true);
        break;
      default:
        break;
    }

    // -- handle namespace URI / prefix
    String nsURI = component.getTargetNamespace();
    if ((nsURI != null) && (nsURI.length() > 0)) {
      xmlNature.setNamespaceURI(nsURI);
      // TODO set the prefix used in the XML Schema
      // in order to use it inside the Marshaling Framework
    }

    // handle default value (if any is set)
    handleDefaultValue(component, classInfo, xsType, fieldInfo, enumeration);

    // -- handle nillable values
    if (component.isNillable()) {
      fieldInfo.setNillable(true);
    }

    // -- add annotated comments
    String comment = createComment(component.getAnnotated());
    if (comment != null) {
      fieldInfo.setComment(comment);
    }

    // --specific field handler or validator?
    if (component.getXMLFieldHandler() != null) {
      fieldInfo.setXMLFieldHandler(component.getXMLFieldHandler());
    }

    if (component.getValidator() != null) {
      fieldInfo.setValidator(component.getValidator());
    }

    if (component.getVisiblity() != null) {
      String visibility = component.getVisiblity();
      fieldInfo.setVisibility(visibility);
    }

    // deal with substitution groups
    switch (component.getAnnotated().getStructureType()) {
      case Structure.ELEMENT:
        ElementDecl elementDeclaration = (ElementDecl) component.getAnnotated();
        if (elementDeclaration.isReference()) {
          elementDeclaration = elementDeclaration.getReference();
        }
        Enumeration<ElementDecl> possibleSubstitutes =
            elementDeclaration.getSubstitutionGroupMembers();
        if (possibleSubstitutes.hasMoreElements()) {
          List<String> substitutionGroupMembers = new ArrayList<String>();
          while (possibleSubstitutes.hasMoreElements()) {
            ElementDecl substitute = possibleSubstitutes.nextElement();
            substitutionGroupMembers.add(substitute.getName());
          }
          fieldInfo.setSubstitutionGroupMembers(substitutionGroupMembers);
        }
      default:
    }

    return fieldInfo;
  }

  /**
   * Determines if the given <code>component</code> represents a choice.
   * 
   * @param component The XMLBindingComponent to check.
   * @return <code>true</code> if and only if the given XMLBindingComponent represents a choice.
   *         Otherwise returns <code>false</code>
   */
  private boolean isChoice(final XMLBindingComponent component) {
    Group group = this.getGroup(component.getAnnotated());
    if (group == null || group.getOrder() == null) {
      return false;
    }

    return group.getOrder() == Order.choice;
  }

  /**
   * Returns the given <code>structure</code> as Group if it represents one.<br>
   * <br>
   * If the given <code>structure</code> has the structure type <code>GROUP</code> this method
   * returns the given <code>structure</code> itself (casted to Group). If the structure is of any
   * other type or is <code>null</code> this method will return <code>null</code>
   * 
   * @param structure The Structure to be returned as Group.
   * @return The given <code>structure</code> if and only if it is a group; otherwise returns
   *         <code>null</code>.
   */
  private Group getGroup(final Structure structure) {
    if (structure == null) {
      return null;
    }

    if (structure.getStructureType() == Structure.GROUP) {
      return (Group) structure;
    }

    return null;
  }

  /**
   * Handle default or fixed value, if any is set.
   * 
   * @param component The component on which a default value is set
   * @param classInfo The corresponding ClassInfo instance.
   * @param xsType The schema type of the component.
   * @param fieldInfo The FieldInfo into which to inject a default value
   * @param enumeration If we are looking at an enumeration.
   */
  private void handleDefaultValue(final XMLBindingComponent component, final ClassInfo classInfo,
      final XSType xsType, final FieldInfo fieldInfo, final boolean enumeration) {

    String value = component.getValue();
    if (value == null) {
      return;
    }

    value = adjustDefaultValue(xsType, value);

    if (value.length() == 0) {
      value = "\"\"";
    }

    // TODO Need to change this...and to validate the value...to be done at reading time.

    // -- clean up value
    // -- if the xsd field is mapped into a java.lang.String
    if (xsType.getJType().toString().equals("java.lang.String")) {
      char ch = value.charAt(0);
      if (ch != '\'' && ch != '\"') {
        value = '\"' + value + '\"';
      }
      // deals with special characters, e.g. line feed
      StringBuffer buffer = new StringBuffer(value.length());
      for (char character : value.toCharArray()) {
        switch (character) {
          case '\n':
            buffer.append("\\n");
            break;
          default:
            buffer.append(character);
        }
      }
      value = buffer.toString();
    } else if (enumeration) {
      JType jType = (classInfo != null) ? classInfo.getJClass() : xsType.getJType();
      if (getSourceGenerator().useJava5Enums()) {
        value = jType.getName() + ".fromValue(\"" + value + "\")";
      } else {
        value = jType.getName() + ".valueOf(\"" + value + "\")";
      }
    } else if (xsType.getJType().isArray()) {
      JType componentType = ((JArrayType) xsType.getJType()).getComponentType();
      if (componentType.isPrimitive()) {
        JPrimitiveType primitive = (JPrimitiveType) componentType;
        value = "new " + primitive.getName() + "[] { " + primitive.getWrapperName() + ".valueOf(\""
            + value + "\")." + primitive.getName() + "Value() }";
      } else {
        value = "new " + componentType.getName() + "[] { " + componentType.getName() + ".valueOf(\""
            + value + "\") }";

      }
    } else if (!(xsType.getJType().isPrimitive())) {
      if (xsType.isDateTime()) {
        // Castor marshals DATETIME_TYPE into java.util.Date(), so we need to convert it
        if (xsType.getType() == XSType.DATETIME_TYPE) {
          // FIXME This fails if the DateTIme has a time zone
          // because we throw away the time zone in toDate()
          value = "new org.exolab.castor.types.DateTime(\"" + value + "\").toDate()";
        } else {
          value = "new " + xsType.getJType().getName() + "(\"" + value + "\")";
        }
      } else {
        // FIXME This works only if a constructor with String as parameter exists
        value = "new " + xsType.getJType().getName() + "(\"" + value + "\")";
      }
    }

    if (component.isFixed()) {
      fieldInfo.setFixedValue(value);
    } else {
      fieldInfo.setDefaultValue(value);
    }
  }

  /**
   * Adjusts the default value string represenation to reflect the semantics of various 'special'
   * data types.
   *
   * @param xsType The XMl schems type of the value to adjust
   * @param value The actual value to adjust
   * @return an adjusted default value.
   */
  private String adjustDefaultValue(final XSType xsType, final String value) {
    switch (xsType.getType()) {
      case XSType.FLOAT_TYPE:
        return value + 'f';
      case XSType.BOOLEAN_TYPE:
        return Boolean.toString(Boolean.parseBoolean(value));
      default:
        break;
    }
    return value;
  }

} // -- MemberFactory
