package org.jcon.df.request;

import org.jcon.util.GenLib;
import org.jcon.param.Param;
import org.jcon.param.ParamDriven;
import org.jcon.param.ParamDrivenInfo;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;

/**
 * Translates various data for a specific database type,
 * such as Sybase or Access.
 * <p>
 * NOTE - If "Zero length string not allowed" encountered
 * in MSAccess, manually change the table design to
 * Allow Zero Length = Yes for all Text fields.
 * THIS IS A BUG WORKAROUND - jh 6/9/98
 *
 * @author Jack Harich
 */
public class TranslatorType implements java.io.Serializable,
    ParamDriven {

//---------- Private Fields ------------------------------
// Key = columnDefType, Object = ColumnDefType
private Hashtable columnDefTypes = new Hashtable();

private Param   param;
private String  name;
private String  nullAllowed;
private String  nullDateValue; // "Format" or "NULL" so far
private boolean automaticTimeStamp;

//---------- ParamDriven Implementation ------------------
public void setParam(Param param) {
    this.param = param;

    name = param.getString("Name");
    automaticTimeStamp = param.isTrue("AutomaticTimeStamp");
    nullAllowed = param.getString("NullAllowed");
    nullDateValue = param.getString("NullDateValue");

    columnDefTypes.clear();
    Vector lines = param.getVector("ColumnDefTypes");
    for (int i = 0; i < lines.size(); i++) {
        String line = (String)lines.elementAt(i);
        StringTokenizer tokens = new StringTokenizer(line, ", ");

        ColumnDefType type = new ColumnDefType();
        type.setName(tokens.nextToken());
        type.setDatatype(tokens.nextToken());

        String prefix = tokens.nextToken();
        type.setPrefix(prefix.equals("None") ? "" : prefix);

        String suffix = tokens.nextToken();
        type.setSuffix(suffix.equals("None") ? "" : prefix);

        columnDefTypes.put(type.getName(), type);
        //print(".setParam() - Loaded columnDefType '" + type.getName() + "'");
    }
}
public Param getParam() {
    return param; // May need to build dynamically
}
public boolean applyNewParam(Param newParam) {
    setParam(param);
    return true; // Successful
}
public ParamDrivenInfo getParamDrivenInfo() {
    return null;
}
//---------- Properties ----------------------------------
/**
 * Returns the type name, such as Sybase or MSAccess.
 */
public String getName() {
    return name;
}
/**
 * Returns the sql CREATE TABLE String that indicates
 * whether nulls are allowed, typically "" or " null".
 */
public String getNullAllowed() {
    return nullAllowed;
}

public boolean isAutomaticTimeStamp() {
    return automaticTimeStamp;
}
//---------- Public Methods ------------------------------
/**
 * Returns the datatype for the logicalType. For example
 * a logicalType of "Integer" might return "int". This
 * allows mapping a logical type to a database datatype.
 * Returns null if not found.
 */
public String getDatatype(String logicalType) {
    ColumnDefType type = (ColumnDefType)columnDefTypes
        .get(logicalType);
    if (type == null) {
        GenLib.error("TranslatorType.getDatatype()",
            "Unknown columnDefType name '" + logicalType + "'");
    }
    return type.getDatatype();
}
/**
 * Returns the formatted value, ready for use in an SQL
 * statement. Output examples are 10, 'test' and $100.
 */
public String formatToSQL(String logicalType, String value) {
    //print(".formatToSQL() " + logicalType + " - types = " + columnDefTypes.size() + " in " + this);
    ColumnDefType type = (ColumnDefType)columnDefTypes
        .get(logicalType);
    if (type == null) {
        String problem = "Unknown columnDefType name '" +
            logicalType + "' for " + name + " with " + columnDefTypes.size() + " types.";

        IllegalArgumentException ex = new
            IllegalArgumentException(problem);

        GenLib.exception("TranslatorType.formatToSQL()",
            problem, ex);
        throw ex;
    }
    String formattedValue;
    boolean isEmpty = (value == null || value.trim().equals("")) ? true : false;
    
    if (logicalType.equals("Date") && isEmpty) {

        if (nullDateValue.equalsIgnoreCase("Format")) {
            formattedValue = type.formatToSQL(value); // Which is ''
        } else {
            formattedValue = nullDateValue; // "NULL" for MSAccess
        }
        //print(".formatToSQL() empty Date = '" + formattedValue + "'");
        
    // This avoids databases that are not configured to
    // accept zero length strings.
    // It also avoids trying to format a null value, such
    // as getting "$null" for an MID.
    } else if (logicalType.equals("MID") && isEmpty) {
    	  return "null";
    	  
    } else {
        return type.formatToSQL(value);
    }
    return formattedValue;
}
/**
 * Returns the aggregate clause using the standard imaginary
 * column name of "AggregateAnswer". The expression is
 * usually just a column name.
 */
public String getAggregateClause(String aggregateType,
        String expression) {
    if (name.equals("MSAccess")) {
        return aggregateType + "(" + expression +
            ") AS AggregateAnswer";

    } else if (name.equals("Sybase")) {
        return "AggregateAnswer = " + aggregateType +
            "(" + expression + ")";

    } else {
        GenLib.error("TranslatorType.getAggregateClause()",
            "Unknown type name '" + name + "'.");
        return "#Error#";
    }
}
//---------- Private Methods -----------------------------
//--- Std
private static void print(String text) {
    System.out.println("TranslatorType" + text);
}

} // End class
