package org.jcon.df;

import org.jcon.util.GenLib;
import org.jcon.df.request.PerformerRemote;
import org.jcon.df.request.Request;
import org.jcon.df.request.RequestServices;
import org.jcon.df.request.Translator;
import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Vector;

/**
 * A Database provides logical access to a single physical
 * database. All data access is done via Request subclasses.
 * Additional features are transaction support and access
 * to metadata via the schema. A database has a single schema.
 *
 * Since a Database is sent "over the wire" using Serialization
 * it and all contents MUST be Serializable.
 *
 * @author Jack Harich
 */
public class Database implements
    EntitySupplier, java.io.Serializable {

//---------- Private Fields ------------------------------
private String      dbName;

private DatabaseServerRemote server; // Currently not used ***
private PerformerRemote      performer;
private transient DatastoreServices    datastoreServices;
/**@supplierCardinality 1*/
private Schema               schema;
private Translator           translator;
private Connector            connector;

private static final boolean DEBUG = false;

private transient RequestServices requestServices;
//---------- Superclass Overrides ------------------------
public Object clone() {
    Database db = new Database();

    // Copies
    db.dbName = dbName;

    db.server = server;
    db.performer = performer;
    db.datastoreServices = datastoreServices;
    db.schema = schema; // Since read only
    db.translator = translator; // Since no state

    // Clones
    db.connector = (Connector)connector.clone();

    return db;
}
//---------- EntitySupplier Implementation ---------------
public Entity getEntity(String schemaName, String entityName) {
    return datastoreServices.getEntity(schemaName, entityName);
}
//---------- Properties ----------------------------------
//----- Read only
public String getName() {
    return dbName;
}
public Schema getSchema() {
    return schema;
}
//---------- Public Methods ------------------------------
/**
 * Performs the request. Results are in the request,
 * such as a sum or RowSet. This is a very flexible
 * mechanism and keeps the data framework interface stable.
 */
public Object performRequest(Request request) {
checkRequestServices();
try {
    if (request.isMutator()) {
        // Perform on SERVER using Performer
        // This optimization prepares the SQL on the client
        requestServices.setConnector(null); // <-----<<<
        request.setRequestServices(requestServices);
        request.clearFailureData();

        request.prepare();

        if (DEBUG) print(".performRequest() - mutator, before performer.performRequest()");
            Object result = performer.performRequest(request);
        if (DEBUG) print(".performRequest() - mutator, after performer.performRequest()");
        return result;

    } else {
        // Non-mutator request preformed LOCALLY on read only connector
        requestServices.setConnector(connector); // <-----<<<
        request.setRequestServices(requestServices);
        request.clearFailureData();

        // Perform request. See Performer for duplicate behavior.
        requestServices.prepareResources(null);
            request.prepare();
            request.perform();
        requestServices.releaseResources();
        return request;
    }
} catch(Exception ex) {
    GenLib.exception("Database.performRequest()",
        "Cannot perform request.", ex);
    if (request.getFailureText() == null) {
        request.setFailureText("Database request failure due to exception.");
    }
    if (request.getFailureException() == null) {
        request.setFailureException(ex);
    }
    return request;
} finally {
    if (! request.isMutator()) connector.releaseConnection();
}
} // End method

//----- TEST - Returns test result
public String testConnection() {
    try {
        connector.retrieveConnection();
        connector.releaseConnection();
        return "Okay - retrieved and released connection.";
    } catch(Exception ex) {
        return ex.getMessage();
    }
}
//---------- Package Methods -----------------------------
//----- Property initialization
void setName(String dbName) {
    this.dbName = dbName;
}
void setDatastoreServices(DatastoreServices datastoreServices) {
    this.datastoreServices = datastoreServices;
}
void setPerformer(PerformerRemote performer) {
    this.performer = performer;
}
PerformerRemote getPerformer() {
    return performer;
}
//----- Workers
void setServer(DatabaseServerRemote server) {
    this.server = server; // Currently not used ***
}
void setConnector(Connector connector) {
    this.connector = connector;
}
Connector getConnector() {
    return connector;
}
void setSchema(Schema schema) {
    this.schema = schema;
    schema.setEntitySupplier(this);
}
void setTranslator(Translator translator) {
    this.translator = translator;
}
Translator getTranslator() {
    return translator;
}
//---------- Private Methods -----------------------------
private void checkRequestServices() {
    if (requestServices == null) {
        requestServices = new RequestServices();
        requestServices.setTranslator(translator);
        requestServices.setSchema(schema);
    }
}
//--- Std
private static void print(String text) {
    System.out.println("Database" + text);
}

} // End class
