package org.apache.torque.templates.transformer.om;

/*
 * 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.
 */

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.TimeZone;

import org.apache.commons.lang.StringUtils;
import org.apache.torque.generator.control.ControllerState;
import org.apache.torque.generator.processor.string.Camelbacker;
import org.apache.torque.generator.processor.string.WrapReservedJavaWords;
import org.apache.torque.generator.source.SourceElement;
import org.apache.torque.generator.source.transform.SourceTransformerException;
import org.apache.torque.templates.TemplateOptionName;
import org.apache.torque.templates.TorqueSchemaAttributeName;
import org.apache.torque.templates.TorqueSchemaElementName;
import org.apache.torque.templates.TorqueSchemaInheritance;
import org.apache.torque.templates.TorqueSchemaJavaType;
import org.apache.torque.templates.transformer.SchemaTypeHelper;
import org.apache.torque.templates.typemapping.JavaType;
import org.apache.torque.templates.typemapping.ResultSetGetter;
import org.apache.torque.templates.typemapping.SchemaType;
import org.apache.torque.templates.typemapping.SqlType;
import org.apache.torque.templates.typemapping.TypeMap;

/**
 * Sets the class names and packages for the OM model.
 * The id method attribute must already be set on the parent table element
 * when this transformer is called.
 */
public class OMColumnTransformer
{
    /** The camelbacker to create the java name from the column name. */
    private static Camelbacker javaNameCamelbacker = new Camelbacker();

    /** The transformer for inheritance elements. */
    private static OMInheritanceTransformer inheritanceTransformer
            = new OMInheritanceTransformer();

    /** Names which cannot be used as constants for column names. */
    private static final Set<String> RESERVED_CONSTANT_NAMES;

    /** The Date format for Dates in Default values. */
    private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.S";

    /** Constant for the CURRENT_DATE default value for Dates. */
    static final String CURRENT_DATE = "CURRENT_DATE";

    /** Constant for the CURRENT_TIME default value for Dates. */
    static final String CURRENT_TIME = "CURRENT_TIME";

    /** Constant for the CURRENT_TIMESTAMP default value for Dates. */
    static final String CURRENT_TIMESTAMP = "CURRENT_TIMESTAMP";

    /** Constant for the getDefaultDate method name. */
    static final String GET_DEFAULT_DATE_METHOD_NAME = "getCurrentDate";

    /** Constant for the getDefaultTime method name. */
    static final String GET_DEFAULT_TIME_METHOD_NAME = "getCurrentTime";

    /** Constant for the getDefaultTimestamp method name. */
    static final String GET_DEFAULT_TIMESTAMP_METHOD_NAME
            = "getCurrentTimestamp";

    /** Prevents reserved java words. */
    private static WrapReservedJavaWords reservedJavaWordsWrapper
            = new WrapReservedJavaWords();

    static
    {
        Set<String> reservedConstantNames = new HashSet<String>();
        reservedConstantNames.add("DATABASE");
        reservedConstantNames.add("TABLE_NAME");
        reservedConstantNames.add("TABLE");
        RESERVED_CONSTANT_NAMES
            = Collections.unmodifiableSet(reservedConstantNames);
    }

    public void transform(
            SourceElement columnElement,
            ControllerState controllerState,
            int columnPosition)
        throws SourceTransformerException
    {
        checkElementName(columnElement);
        checkColumnNameExists(columnElement);
        setJavaTypeAttribute(columnElement);

        columnElement.setAttribute(
                ColumnAttributeName.POSITION,
                columnPosition);
        setAttributeDefaultValues(columnElement);

        SchemaType schemaType = SchemaTypeHelper.getSchemaType(
                columnElement,
                controllerState);
        columnElement.setAttribute("schemaType", schemaType);
        setDomainAttributes(columnElement, controllerState);

        JavaType fieldJavaType = getFieldJavaType(columnElement, schemaType);
        columnElement.setAttribute(
                JavaFieldAttributeName.FIELD_TYPE,
                fieldJavaType.getFullClassName());
        JavaType fieldJavaObjectType = TypeMap.getJavaObjectType(schemaType);
        columnElement.setAttribute(
                ColumnAttributeName.FIELD_OBJECT_TYPE,
                fieldJavaObjectType.getFullClassName());


        setPrimitiveTypeAttribute(columnElement, fieldJavaType);
        setNumberTypeAttribute(columnElement, fieldJavaType);
        setJavaNameAttribute(columnElement);
        setFieldNameAttribute(columnElement);
        setPeerColumnNameAttribute(columnElement);
        setQualifiedColumnNameAttribute(columnElement);
        setGetterNameAttribute(columnElement, fieldJavaType, controllerState);
        setSetterNameAttribute(columnElement);
        setAccessModifierAttributes(columnElement);
        setDefaultValueAttribute(columnElement, fieldJavaType, controllerState);
        setUseDatabaseDefaultValueAttribute(columnElement);
        setResultSetGetterAttribute(columnElement, schemaType);
        setSampleObjectAttribute(columnElement, schemaType);

        for (SourceElement inheritanceElement : columnElement.getChildren(
                TorqueSchemaElementName.INHERITANCE.getName()))
        {
            inheritanceTransformer.transform(
                    inheritanceElement,
                    controllerState);
        }
    }

    /**
     * Sets the javaType attribute of the column element
     * if it is not already set and a default value is set.
     *
     * @param columnElement the column element, not null.
     */
    protected void setJavaTypeAttribute(SourceElement columnElement)
    {
        if (columnElement.getAttribute(TorqueSchemaAttributeName.JAVA_TYPE)
                != null)
        {
            return;
        }
        SourceElement databaseElement = columnElement.getParent().getParent();
        String defaultJavaType = (String) databaseElement.getAttribute(
                TorqueSchemaAttributeName.DEFAULT_JAVA_TYPE);
        if (defaultJavaType != null)
        {
            columnElement.setAttribute(
                    TorqueSchemaAttributeName.JAVA_TYPE,
                    defaultJavaType);
        }
    }

    /**
     * Sets default values for attributes of the column element
     * if the attribute is not set.
     * The following attributes are checked:
     * autoIncrement, protected, inheritance, required, primaryKey
     *
     * @param columnElement the column element, not null.
     */
    protected void setAttributeDefaultValues(SourceElement columnElement)
    {
        // set autoincrement attribute
        if (columnElement.getAttribute(TorqueSchemaAttributeName.AUTO_INCREMENT)
                == null)
        {
            String idMethod
                = (String) columnElement.getParent().getAttribute(
                        TorqueSchemaAttributeName.ID_METHOD);
            // idMethod can not be null because it is already set by the
            // table transformer
            if (!"none".equals(idMethod))
            {
                columnElement.setAttribute(
                        TorqueSchemaAttributeName.AUTO_INCREMENT,
                        Boolean.TRUE.toString());
            }
            else
            {
                columnElement.setAttribute(
                    TorqueSchemaAttributeName.AUTO_INCREMENT,
                    Boolean.FALSE.toString());
            }
        }

        // set protected attribute
        if (columnElement.getAttribute(
                    TorqueSchemaAttributeName.PROTECTED)
                == null)
        {
            columnElement.setAttribute(
                TorqueSchemaAttributeName.PROTECTED,
                Boolean.FALSE.toString());
        }

        // set inheritance attribute
        if (columnElement.getAttribute(
                    TorqueSchemaAttributeName.INHERITANCE)
                == null)
        {
            columnElement.setAttribute(
                TorqueSchemaAttributeName.INHERITANCE,
                Boolean.FALSE.toString());
        }

        // set required attribute
        Object required = columnElement.getAttribute(
                TorqueSchemaAttributeName.REQUIRED);
        if (required == null)
        {
            columnElement.setAttribute(
                    TorqueSchemaAttributeName.REQUIRED,
                    Boolean.FALSE.toString());
        }

        // set primaryKey attribute
        Object primaryKey = columnElement.getAttribute(
                TorqueSchemaAttributeName.PRIMARY_KEY);
        if (primaryKey == null)
        {
            columnElement.setAttribute(
                    TorqueSchemaAttributeName.PRIMARY_KEY,
                    Boolean.FALSE.toString());
        }
    }

    protected void setDomainAttributes(
                SourceElement columnElement,
                ControllerState controllerState)
            throws SourceTransformerException
    {
        SqlType domain = SchemaTypeHelper.getDomain(
                columnElement,
                controllerState);
        if (domain == null)
        {
            return;
        }
        if (columnElement.getAttribute(TorqueSchemaAttributeName.TYPE)
                    == null
                && domain.getSqlTypeName() != null)
        {
            columnElement.setAttribute(
                    TorqueSchemaAttributeName.TYPE,
                    domain.getSqlTypeName());
        }
        if (columnElement.getAttribute(TorqueSchemaAttributeName.DEFAULT)
                    == null
                && domain.getDefaultValue() != null)
        {
            columnElement.setAttribute(
                    TorqueSchemaAttributeName.DEFAULT,
                    domain.getDefaultValue());
        }
        if (columnElement.getAttribute(TorqueSchemaAttributeName.SIZE) == null
              && domain.getSize() != null)
        {
            columnElement.setAttribute(
                    TorqueSchemaAttributeName.SIZE,
                    domain.getSize());
        }
        if (columnElement.getAttribute(TorqueSchemaAttributeName.SCALE) == null
              && domain.getScale() != null)
        {
            columnElement.setAttribute(
                    TorqueSchemaAttributeName.SCALE,
                    domain.getScale());
        }
    }

    /**
     * Sets the attributes getterAccessModifer and setterAccessModifer
     * on the column element.
     *
     * @param columnElement the column element, not null.
     */
    protected void setAccessModifierAttributes(SourceElement columnElement)
    {
        boolean isProtected = "true".equals(
                 columnElement.getAttribute(
                         TorqueSchemaAttributeName.PROTECTED));

        String accessModifier;
        if (isProtected)
        {
            accessModifier = "protected";
        }
        else
        {
            accessModifier = "public";
        }
        columnElement.setAttribute(
                JavaFieldAttributeName.GETTER_ACCESS_MODIFIER,
                accessModifier);
        columnElement.setAttribute(
                JavaFieldAttributeName.SETTER_ACCESS_MODIFIER,
                accessModifier);
    }


    /**
     * Returns the java type of the field representing a database column.
     *
     * @param columnElement the column element, not null.
     * @param schemaType the schema type, not null.
     *
     * @return the java type of the column
     */
    protected JavaType getFieldJavaType(
                SourceElement columnElement,
                SchemaType schemaType)
            throws SourceTransformerException
    {
        JavaType result;
        String javaType = (String) columnElement.getAttribute(
                TorqueSchemaAttributeName.JAVA_TYPE);
        if (TorqueSchemaJavaType.OBJECT.getValue().equals(javaType))
        {
            result = TypeMap.getJavaObjectType(schemaType);
        }
        else if (TorqueSchemaJavaType.PRIMITIVE.getValue().equals(javaType)
                 || javaType == null)
        {
            result = TypeMap.getJavaPrimitiveType(schemaType);
        }
        else
        {
            String columnName = (String) columnElement.getAttribute(
                    TorqueSchemaAttributeName.NAME);
            throw new SourceTransformerException("Unknown javaType "
                    + javaType
                    + " in column "
                    + columnName);
        }
        return result;
    }

    /**
     * Checks that the name of the column element is correct.
     *
     * @param columnElement the column element, not null.
     *
     * @throws IllegalArgumentException if the element name is wrong.
     */
    protected void checkElementName(SourceElement columnElement)
    {
        if (!TorqueSchemaElementName.COLUMN.getName().equals(
                columnElement.getName()))
        {
            throw new IllegalArgumentException("Illegal element Name "
                    + columnElement.getName());
        }
    }

    /**
     * Checks that the name attribute exists on the column element.
     *
     * @param columnElement the column element, not null.
     *
     * @throws SourceTransformerException if the name attribute does not exist.
     */
    protected void checkColumnNameExists(SourceElement columnElement)
            throws SourceTransformerException
    {
        String columnName
                = (String) columnElement.getAttribute(
                        TorqueSchemaAttributeName.NAME);
        if (columnName == null)
        {
            throw new SourceTransformerException("The attribute "
                    + TorqueSchemaAttributeName.NAME.getName()
                    + " on element "
                    + columnElement.getName()
                    + " is null");
        }
    }

    /**
     * Sets the javaName attribute of the column element if it is not
     * already set.
     *
     * @param columnElement the column element, not null.
     */
    protected void setJavaNameAttribute(SourceElement columnElement)
    {
        if (columnElement.getAttribute(TorqueSchemaAttributeName.JAVA_NAME)
                != null)
        {
            return;
        }
        String columnName = (String) columnElement.getAttribute(
                TorqueSchemaAttributeName.NAME);
        String javaName = javaNameCamelbacker.process(columnName);
        columnElement.setAttribute(
                TorqueSchemaAttributeName.JAVA_NAME,
                javaName);
    }

    /**
     * Sets the fieldName attribute of the column element if it is not
     * already set.
     * The javaName attribute of the column must be set.
     *
     * @param columnElement the column element, not null.
     */
    protected void setFieldNameAttribute(SourceElement columnElement)
    {
        if (columnElement.getAttribute(JavaFieldAttributeName.FIELD_NAME)
                != null)
        {
            return;
        }
        String javaName = (String) columnElement.getAttribute(
                TorqueSchemaAttributeName.JAVA_NAME);
        String fieldName = StringUtils.uncapitalize(javaName);
        fieldName = reservedJavaWordsWrapper.process(fieldName);
        columnElement.setAttribute(
                JavaFieldAttributeName.FIELD_NAME,
                fieldName);
    }

    /**
     * Sets the peerColumnName attribute of the column element if it is not
     * already set.
     *
     * @param columnElement the column element, not null.
     */
    protected void setPeerColumnNameAttribute(SourceElement columnElement)
    {
        if (columnElement.getAttribute(ColumnAttributeName.PEER_COLUMN_NAME)
                != null)
        {
            return;
        }
        String columnName = (String) columnElement.getAttribute(
                TorqueSchemaAttributeName.NAME);
        String peerColumnName = columnName.toUpperCase();
        if (RESERVED_CONSTANT_NAMES.contains(peerColumnName))
        {
            peerColumnName = "_" +  peerColumnName;
        }
        columnElement.setAttribute(
                ColumnAttributeName.PEER_COLUMN_NAME,
                peerColumnName);
    }

    /**
     * Sets the qualifiedColumnName attribute of the column element
     * if it is not already set.
     *
     * @param columnElement the column element, not null.
     */
    protected void setQualifiedColumnNameAttribute(SourceElement columnElement)
    {
        if (columnElement.getAttribute(ColumnAttributeName.QUALIFIED_COLUMN_NAME)
                != null)
        {
            return;
        }
        String tableName = (String) columnElement.getParent().getAttribute(
                TorqueSchemaAttributeName.NAME);
        String columnName = (String) columnElement.getAttribute(
                TorqueSchemaAttributeName.NAME);
        String qualifiedColumnName
                = tableName + "." + columnName;
        columnElement.setAttribute(
                ColumnAttributeName.QUALIFIED_COLUMN_NAME,
                qualifiedColumnName);
    }

    /**
     * Sets the getterName attribute of the column element
     * if it is not already set.
     * The fieldName attribute of the column element must already be set.
     *
     * @param columnElement the column element, not null.
     * @param javaType the java type of the column, not null.
     * @param controllerState the controller state, not null.
     */
    protected void setGetterNameAttribute(
            SourceElement columnElement,
            JavaType javaType,
            ControllerState controllerState)
    {
        if (columnElement.getAttribute(JavaFieldAttributeName.GETTER_NAME)
                != null)
        {
            return;
        }
        String fieldName = (String) columnElement.getAttribute(
                JavaFieldAttributeName.FIELD_NAME);
        String getterName = FieldHelper.getGetterName(
                fieldName,
                javaType.getFullClassName(),
                controllerState);
        columnElement.setAttribute(
                JavaFieldAttributeName.GETTER_NAME,
                getterName);
    }

    /**
     * Sets the setterName attribute of the column element
     * if it is not already set.
     * The fieldName attribute of the column element must already be set.
     *
     * @param columnElement the column element, not null.
     */
    protected void setSetterNameAttribute(SourceElement columnElement)
    {
        if (columnElement.getAttribute(JavaFieldAttributeName.SETTER_NAME)
                != null)
        {
            return;
        }
        String fieldName = (String) columnElement.getAttribute(
                JavaFieldAttributeName.FIELD_NAME);
        String setterName = FieldHelper.getSetterName(fieldName);
        columnElement.setAttribute(
                JavaFieldAttributeName.SETTER_NAME,
                setterName);
    }

    /**
     * Sets the primitiveType attribute of the column element
     * if it is not already set.
     *
     * @param columnElement the column element, not null.
     * @param javaType the type of the java field corresponding to the
     *        column, not null.
     */
    protected void setPrimitiveTypeAttribute(
            SourceElement columnElement,
            JavaType javaType)
    {
        if (columnElement.getAttribute(ColumnAttributeName.PRIMITIVE_TYPE)
                != null)
        {
            return;
        }
        boolean primitiveFieldType = javaType.isPrimitive();
        columnElement.setAttribute(
                ColumnAttributeName.PRIMITIVE_TYPE,
                Boolean.toString(primitiveFieldType));
    }

    /**
     * Sets the numberType attribute of the column element
     * if it is not already set.
     *
     * @param columnElement the column element, not null.
     * @param javaType the type of the java field corresponding to the
     *        column, not null.
     */
    protected void setNumberTypeAttribute(
            SourceElement columnElement,
            JavaType javaType)
    {
        if (columnElement.getAttribute(ColumnAttributeName.NUMBER_TYPE)
                != null)
        {
            return;
        }
        boolean numberFieldType = javaType.isNumber();
        columnElement.setAttribute(
                ColumnAttributeName.NUMBER_TYPE,
                Boolean.toString(numberFieldType));
    }


    /**
     * Sets the defaultValue attribute of the column element
     * if it is not already set.
     *
     * @param columnElement the column element, not null.
     * @param javaType the type of the java field corresponding to the
     *        column, not null.
     * @param controllerState the ControllerState, not null.
     *
     * @throws SourceTransformerException if an unknown primitive type
     *         is encountered
     */
    protected void setDefaultValueAttribute(
                SourceElement columnElement,
                JavaType javaType,
                ControllerState controllerState)
            throws SourceTransformerException
    {
        // special case inheritance by class name
        // In this case, the class name of the object must be written into the
        // column as default, overriding any SQL default values.
        if (TorqueSchemaInheritance.SINGLE.getValue().equals(
                    columnElement.getAttribute(
                        TorqueSchemaAttributeName.INHERITANCE))
            && columnElement.getChildren(TorqueSchemaElementName.INHERITANCE)
                    .isEmpty())
        {
            columnElement.setAttribute(
                    JavaFieldAttributeName.DEFAULT_VALUE,
                    "getClass().getName()");
            return;
        }

        if (columnElement.getAttribute(JavaFieldAttributeName.DEFAULT_VALUE)
                != null)
        {
            return;
        }
        String defaultAttributeValue = (String) columnElement.getAttribute(
                TorqueSchemaAttributeName.DEFAULT);

        String fieldDefaultValue;
        if (defaultAttributeValue != null)
        {
            boolean useDatabaseDefaultValue = "true".equals(
                    columnElement.getAttribute(
                        TorqueSchemaAttributeName.USE_DATABASE_DEFAULT_VALUE));
            fieldDefaultValue = getDefaultValueWithDefaultSet(
                    javaType,
                    defaultAttributeValue,
                    useDatabaseDefaultValue,
                    columnElement);
        }
        else if ("true".equals(
                columnElement.getAttribute(TorqueSchemaAttributeName.VERSION)))
        {
            fieldDefaultValue = controllerState.getStringOption(
                    TemplateOptionName.OM_OPTIMISTIC_LOCKING_DEFAULT_VALUE);
        }
        else
        {
            fieldDefaultValue = getDefaultValueWithoutDefaultSet(javaType);
        }
        columnElement.setAttribute(
                JavaFieldAttributeName.DEFAULT_VALUE,
                fieldDefaultValue);
    }

    /**
     * Calculates the java default value of a column in case a default value
     * is set.
     *
     * @param javaType The java type of the column.
     * @param defaultValue The default value from the schema.
     * @param useDatabaseDefaultValue whether the database default value should
     *        be used.
     * @param columnElement the current column element for which
     *        the default value should be calculated.
     *
     * @return The java default value.
     *
     * @throws SourceTransformerException if an illegal default value is used.
     */
    protected String getDefaultValueWithDefaultSet(
                JavaType javaType,
                String defaultValue,
                boolean useDatabaseDefaultValue,
                SourceElement columnElement)
            throws SourceTransformerException
    {
        boolean primitiveFieldType = javaType.isPrimitive();
        String fieldDefaultValue;
        if (JavaType.BOOLEAN_PRIMITIVE == javaType)
        {
            if ("Y".equals(defaultValue)
                || "1".equals(defaultValue)
                || "true".equalsIgnoreCase(defaultValue))
            {
                fieldDefaultValue = "true";
            }
            else
            {
                fieldDefaultValue = "false";
            }
        }
        else if (JavaType.BOOLEAN_OBJECT == javaType)
        {
            if ("Y".equals(defaultValue)
                || "1".equals(defaultValue)
                || "true".equalsIgnoreCase(defaultValue))
            {
                fieldDefaultValue = "Boolean.TRUE";
            }
            else
            {
                fieldDefaultValue = "Boolean.FALSE";
            }
        }
        else if (JavaType.STRING == javaType)
        {
            fieldDefaultValue = "\"" + defaultValue + "\"";
        }
        else if (JavaType.SHORT_OBJECT == javaType)
        {
            // The following is better than casting with (short)
            // because a range check is performed,
            fieldDefaultValue = "Short.valueOf(\"" + defaultValue + "\")";
        }
        else if (JavaType.BYTE_OBJECT == javaType)
        {
            // The following is better than casting with (byte)
            // because a range check is performed,
            fieldDefaultValue = "Byte.valueOf(\"" + defaultValue + "\")";
        }
        else if (JavaType.INTEGER_OBJECT == javaType)
        {
            fieldDefaultValue = "Integer.valueOf(" + defaultValue + ")";
        }
        else if (JavaType.LONG_OBJECT == javaType)
        {
            fieldDefaultValue = "Long.valueOf(" + defaultValue + "L)";
        }
        else if (JavaType.DATE == javaType)
        {
            if (CURRENT_DATE.equalsIgnoreCase(defaultValue)
                    || CURRENT_TIME.equalsIgnoreCase(defaultValue)
                    || CURRENT_TIMESTAMP.equalsIgnoreCase(defaultValue))
            {
                if (useDatabaseDefaultValue)
                {
                    // if the database default value is used do not use
                    // current time in java as it might be different
                    fieldDefaultValue = "null";
                }
                else
                {
                    // the database does not provide a default so use
                    // java current time.
                    if (CURRENT_DATE.equalsIgnoreCase(defaultValue))
                    {
                        String methodName;
                        if (columnElement.getParent().getAttribute(
                                TableAttributeName.GET_CURRENT_DATE_METHOD_NAME)
                            != null)
                        {
                            methodName = columnElement.getParent().getAttribute(
                                    TableAttributeName.GET_CURRENT_DATE_METHOD_NAME)
                                .toString();
                        }
                        else
                        {
                            methodName = GET_DEFAULT_DATE_METHOD_NAME;
                        }
                        fieldDefaultValue = methodName + "()";
                    }
                    else if (CURRENT_TIME.equalsIgnoreCase(defaultValue))
                    {
                        String methodName;
                        if (columnElement.getParent().getAttribute(
                                TableAttributeName.GET_CURRENT_TIME_METHOD_NAME)
                            != null)
                        {
                            methodName = columnElement.getParent().getAttribute(
                                    TableAttributeName.GET_CURRENT_TIME_METHOD_NAME)
                                .toString();
                        }
                        else
                        {
                            methodName = GET_DEFAULT_TIME_METHOD_NAME;
                        }
                        fieldDefaultValue = methodName + "()";
                    }
                    else
                    {
                        String methodName;
                        if (columnElement.getParent().getAttribute(
                                TableAttributeName.GET_CURRENT_TIMESTAMP_METHOD_NAME)
                            != null)
                        {
                            methodName = columnElement.getParent().getAttribute(
                                    TableAttributeName.GET_CURRENT_TIMESTAMP_METHOD_NAME)
                                .toString();
                        }
                        else
                        {
                            methodName = GET_DEFAULT_TIMESTAMP_METHOD_NAME;
                        }
                        fieldDefaultValue = methodName + "()";
                    }
                }
            }
            else
            {
                if (useDatabaseDefaultValue)
                {
                    // if the database default value is used, do not use
                    // current time in java as it might be different
                    // and have a custom format.
                    fieldDefaultValue = "null";
                }
                else
                {
                    fieldDefaultValue = "new Date("
                            + getDefaultValueAsDate(defaultValue).getTime()
                            + "L)";
                }
            }
        }
        else if (primitiveFieldType)
        {
            fieldDefaultValue = defaultValue;
        }
        else
        {
            fieldDefaultValue
                    = "new " + javaType.getFullClassName()
                        + "(" + defaultValue + ")";
        }
        return fieldDefaultValue;
    }

    /**
     * Parses the default value String as Date.
     *
     * @param defaultValue the String to parse.
     * @return the parsed date.
     *
     * @throws SourceTransformerException if the date cannot be parsed.
     */
    public static Date getDefaultValueAsDate(String defaultValue)
            throws SourceTransformerException
    {
        try
        {
            SimpleDateFormat dateFormat
                    = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
            dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
            return dateFormat.parse(defaultValue);
        }
        catch (ParseException e)
        {
            throw new SourceTransformerException(
                "The default value "
                    + defaultValue
                    + " does not match the format String "
                    + DEFAULT_DATE_FORMAT
                    + " for date values");
        }
    }

    /**
     * Calculates the java default value of a column in case a default value
     * is not set.
     *
     * @param javaType The java type of the column.
     *
     * @return The java default value.
     */
    protected String getDefaultValueWithoutDefaultSet(JavaType javaType)
            throws SourceTransformerException
    {
        String fieldDefaultValue;
        boolean primitiveFieldType = javaType.isPrimitive();
        if (primitiveFieldType)
        {
            if (JavaType.BOOLEAN_PRIMITIVE == javaType)
            {
                fieldDefaultValue = "false";
            }
            else if (JavaType.BYTE_PRIMITIVE == javaType)
            {
                fieldDefaultValue = "(byte) 0";
            }
            else if (JavaType.SHORT_PRIMITIVE == javaType)
            {
                fieldDefaultValue = "(short) 0";
            }
            else if (JavaType.INTEGER_PRIMITIVE == javaType)
            {
                fieldDefaultValue = "0";
            }
            else if (JavaType.LONG_PRIMITIVE == javaType)
            {
                fieldDefaultValue = "0L";
            }
            else if (JavaType.FLOAT_PRIMITIVE == javaType)
            {
                fieldDefaultValue = "0";
            }
            else if (JavaType.DOUBLE_PRIMITIVE == javaType)
            {
                fieldDefaultValue = "0";
            }
            else if (JavaType.CHAR_PRIMITIVE == javaType)
            {
                fieldDefaultValue = "'\0'";
            }
            else
            {
                throw new SourceTransformerException(
                        "unknown primitive type" + javaType);
            }
        }
        else
        {
            fieldDefaultValue = "null";
        }
        return fieldDefaultValue;
    }

    /**
     * Sets the useDatabaseDefaultValue attribute of the column element to its
     * default "false" if it is not already set.
     *
     * @param columnElement the column element, not null.
     */
    protected void setUseDatabaseDefaultValueAttribute(
            SourceElement columnElement)
    {
        if (columnElement.getAttribute(
                    TorqueSchemaAttributeName.USE_DATABASE_DEFAULT_VALUE)
                != null)
        {
            return;
        }
        columnElement.setAttribute(
                TorqueSchemaAttributeName.USE_DATABASE_DEFAULT_VALUE,
                Boolean.toString(false));
    }

    /**
     * Sets the resultSetGetter attribute of the column element
     * if it is not already set.
     * If the resultSetGetter is a string value, it is converted to
     * a ResultSetGetter value.
     *
     * @param columnElement the column element, not null.
     * @param schemaType the schema type of the column, not null.
     */
    protected void setResultSetGetterAttribute(
            SourceElement columnElement,
            SchemaType schemaType)
    {
        ResultSetGetter resultSetGetter = null;
        Object originalValue = columnElement.getAttribute(
                ColumnAttributeName.RESULT_SET_GETTER);

        if (originalValue != null)
        {
            if (originalValue instanceof String)
            {
                resultSetGetter = ResultSetGetter.getByMethodName(
                        (String) originalValue);
            }
        }
        else
        {
            resultSetGetter = TypeMap.getResultSetGetter(schemaType);
        }

        if (resultSetGetter != null)
        {
            columnElement.setAttribute(
                    ColumnAttributeName.RESULT_SET_GETTER,
                    resultSetGetter);
        }
    }

    /**
     * Sets the sampleObject attribute of the column element
     * if it is not already set.
     *
     * @param columnElement the column element, not null.
     * @param schemaType the schema type of the column, not null.
     */
    protected void setSampleObjectAttribute(
            SourceElement columnElement,
            SchemaType schemaType)
    {
        if (columnElement.getAttribute(ColumnAttributeName.SAMPLE_OBJECT)
                != null)
        {
            return;
        }

        String sampleObject = TypeMap.getJavaObject(schemaType);
        columnElement.setAttribute(
                ColumnAttributeName.SAMPLE_OBJECT,
                sampleObject);
    }

}
