package org.jcon.df.edit.task;

import org.jcon.df.Schema;
import org.jcon.param.Param;
import org.jcon.param.StringVector;
import org.jcon.util.DataLib;
import org.jcon.util.GenLib;
import java.util.StringTokenizer;
import java.util.Vector;

/**
 * Carries the properties making up a DataRequest Param.
 * Initialized from a Param with defaults.
 * *** See DataRequest for DUPECODE. ***
 *
 * @author Jack Harich
 */
public class DataRequestProp {

//---------- Private Fields ------------------------------
private Schema schema;

// Edit properties
private boolean editable;
private Vector  columnIDs           = new Vector();
private Vector  unexpandedColumnIDs = new Vector();
private Vector  entityNames         = new Vector();
private Vector  sortBys             = new Vector();
private Vector  joins               = new Vector(); // String
private String  filterLine; // Single line for raw parsing
private String  dbName;
private String  entitiesLine;

//---------- Initialization ------------------------------
public DataRequestProp() {
    clear();
}
private void clear() {
    editable = true;
    columnIDs.removeAllElements();
    unexpandedColumnIDs.removeAllElements();
    entityNames.removeAllElements();
    sortBys.removeAllElements();
    joins.removeAllElements();
    filterLine = null;
    dbName = null;
    entitiesLine = null;
}
//---------- Properties ----------------------------------
//----- Minor Getters
public boolean isEditable() {
    return editable;
}
public Vector getColumnIDs() {
    return columnIDs;
}
public String getPrimeEntityName() {
    return (String)entityNames.firstElement();
}
//----- Minor Setters
public void setSchema(Schema schema) {
    this.schema = schema;
}
//----- Major
// From a DataRequest Param
public void setMetaParam(Param metaParam) {
    //---------- Prepare properties
    clear();
    //----- Required properties
    dbName = metaParam.getString("Database");
    entitiesLine = metaParam.getString("Entities");
    Vector entities = DataLib.convertDelimStringToVector(
        entitiesLine, ", ");
    for (int i = 0; i < entities.size(); i++) {
        entityNames.addElement(entities.elementAt(i));
    }
    //----- Optional properties
    if (metaParam.hasProperty("ColumnIDs")) {
        Vector lines = metaParam.getVector("ColumnIDs");
        for (int i = 0; i < lines.size(); i++) {
            String columnID = (String)lines.elementAt(i);
            // ***columnIDs.addElement(columnID);
            addColumnID(columnID);
        }
    }
    // Format: SortBy is: columnID1, columnID2 Desc
    if (metaParam.hasProperty("SortBy")) {
        StringTokenizer tokens = new StringTokenizer(
            metaParam.getString("SortBy"), ",");
        while (tokens.hasMoreTokens()) {
            String phrase = tokens.nextToken().trim();
            //print(" - adding phrase to sortBys: " + phrase);
            sortBys.addElement(phrase);
        }
    }
    // (See DUPECODE in df.request.ReadRowSet) ***
    // Format: Joins hasLines:
    //             AwardType.AwardClassMID = AwardClass.MID
    //             End: Joins
    if (metaParam.hasProperty("Joins")) {
        Vector joinLines = metaParam.getVector("Joins");
        for (int i = 0; i < joinLines.size(); i++) {
            joins.addElement((String)joinLines.elementAt(i));
        }
    }
    // Format: FilterLine is: raw WHERE clause
    filterLine = metaParam.getString("FilterLine"); // null if none

    //---------- Enhance properties
    // Precondition assertions
    if (dbName == null) {
        throw new IllegalStateException("Database name is required.");
    }
    if (entityNames.isEmpty()) {
        throw new IllegalStateException("At least one entity name is required.");
    }
    String primeEntityName = getPrimeEntityName();
    // Set defaults
    if (columnIDs.isEmpty() && unexpandedColumnIDs.isEmpty()) {
        addColumnID(primeEntityName + ".*"); // Expanded below
    }
    // Prepend missing primeEntityName to columnIDs
    for (int i = 0; i < columnIDs.size(); i ++) {
        String columnID = (String)columnIDs.elementAt(i);
        if (columnID.indexOf(".") < 0) {
            columnID = primeEntityName + "." + columnID;
            columnIDs.setElementAt(columnID, i);
        }
    }
    // Prepend missing primeEntityName to sortBys
    for (int i = 0; i < sortBys.size(); i ++) {
        String phrase = (String)sortBys.elementAt(i);
        if (phrase.indexOf(".") < 0) {
            phrase = primeEntityName + "." + phrase;
            sortBys.setElementAt(phrase, i);
        }
    }
    // Expand unexpandedColumnIDs
    for (int i = 0; i < unexpandedColumnIDs.size(); i ++) {
        String columnID = (String)unexpandedColumnIDs.elementAt(i);
        String entityName = DataLib.getFirstDelimited(columnID, '.');
        // Use schema to add columnIDs
        Vector names = schema.getEntity(entityName)
            .getColumnNamesInLogicalOrder();
        for (int j = 0; j < names.size(); j++) {
            String name = (String)names.elementAt(j);
            addColumnID(entityName + "." + name);
            //print(" - Expanded " + i + " " + j + " " + entityName + "." + name);
        }
    }
}
/**
 * Returns the columnIDs for the prime entity.
 */
public Vector getPrimeColumnIDs() {
    Vector primeIDs = new Vector();
    String primeEntity = (String)entityNames.firstElement();
    for (int i = 0; i < columnIDs.size(); i++) {
        String columnID = (String)columnIDs.elementAt(i);
        if (columnID.startsWith(primeEntity)) {
            primeIDs.addElement(columnID);
        }
    }
    return primeIDs;
}
public Param getFullParam() {
    Param param = new Param();

    // Note how adding columnIDs cause a "hasLines:"
    param.put("Database", dbName);
    param.put("Entities", entitiesLine);

    StringVector vector = new StringVector();
    vector.copy(columnIDs);
    param.put("ColumnIDs", vector);

    if (! sortBys.isEmpty()) {
        String sortBy = DataLib.convertVectorToDelimString(
            sortBys, ", ");
        //print(" - sortBy: " + sortBy);
        param.put("SortBy", sortBy);
    }
    if (! joins.isEmpty()) {
        StringVector lines = new StringVector();
        /** for (int i = 0; i < joins.size(); i++) {
            String line = (String)joins.elementAt(i);
            lines.addElement(line);
        } */
        lines.copy(joins);
        param.put("Joins", lines);
    }
    if (filterLine != null) {
        param.put("FilterLine", filterLine);
    }
    return param;
}
//---------- Public Methods ------------------------------

//---------- Private Methods -----------------------------
/**
 * Adds a columnID of the format "EntityName.ColumnName".
 * ColumnName may be "*" for all. If none are added then
 * FirstEntityName.* is automatically added. If the
 * entityName is missing then the first entityName is prepended.
 */
private void addColumnID(String columnID) {
    if (columnID.endsWith(".*")) {
        unexpandedColumnIDs.addElement(columnID);
    } else {
        columnIDs.addElement(columnID);
    }
}
//--- Std
private static void print(String text) {
    System.out.println("DataRequestProp" + text);
}

} // End class
