package org.jcon.df.admin;

import org.jcon.ba.system.BeanActionClose;
import org.jcon.ba.system.BeanActionStart;
import org.jcon.df.*;
import org.jcon.df.column.ColumnDef;
import org.jcon.df.work.DatabaseUtil;
import org.jcon.util.GenLib;
import org.jcon.util.msg.Message;
import org.jcon.util.msg.MessageListener;
import org.jcon.util.service.ContainerServices;
import org.jcon.util.service.ContainerServicesUser;
import org.jcon.ui.MessageBox;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;
import java.util.Vector;

/**
 * Provides a database administrator with the tools for
 * simple database management using the database definitions.
 *
 * @author Jack Harich
 */
public class EntityAdmin implements
    BeanActionStart, BeanActionClose, MessageListener,
    ContainerServicesUser {

//---------- Private Fields ------------------------------
// Key = dbName, Object = Database
private Hashtable databases = new Hashtable();

private EntityAdminView   view; // null if closed
private DatastoreServices datastoreServices;
private ContainerServices containerServices;
private int               entityRowCount;

// These are null if no current database
private Database          currentDatabase;
private DatabaseUtil      currentDatabaseUtil;
private Schema            currentSchema;

//---------- Initialization ------------------------------
public EntityAdmin() {
}
//---------- BeanActionStart Implementation --------------
public void start() {
    if (datastoreServices == null) {
        datastoreServices = (DatastoreServices)
            containerServices.getService("DatastoreServices");
    }
    if (view == null) initView();
    view.setVisible(true);
}
//---------- BeanActionClose Implementation --------------
public String canClose() {
    return null; // null means yes I can close
}
public void close() {
    if (view != null) view.close();
    view = null;
}
//---------- MessageListener Implementation --------------
public void processMessage(Message message) {
    String name = message.getName();
    //print(".processMessage() - name " + name);

    if (name == "StartEntityAdmin") {
        start();
    }
}
public String[] loadMessageInterests() {
    return new String[] {"StartEntityAdmin"};
}
//---------- ContainerServicesUser Implementation --------
public void setContainerServices(ContainerServices services) {
    containerServices = services;
}
public String[] getContainerServicesInterests() {
    return new String[] {"DatastoreServices"};    
}
//---------- Package Methods -----------------------------
// These are view callbacks
void databaseSelected(String dbName) {
    //print(".databaseSelected() " + dbName);
    // Refresh current fields
    currentDatabase = getDatabase(dbName);
    currentDatabaseUtil = new DatabaseUtil(currentDatabase);
    currentSchema = currentDatabase.getSchema();
    // Refresh view
    String[] names = currentSchema.loadEntityNames();
    view.loadEntitiesUnknownStatus(names);
    view.clearStructure();

    refreshCommandState();
}
void entitySelected(String entityName) {
    //print(".entitySelected() - entityName = " + entityName);
    // Refresh structure
    Entity entity = currentSchema.getEntity(entityName);
    Vector columnNames = entity.getColumnNamesInLogicalOrder();
    String[] [] structure = new String[columnNames.size()] [3];

    for (int i = 0; i < columnNames.size(); i++) {
        String columnName = (String)columnNames.elementAt(i);
        ColumnDef def = entity.getColumnDef(columnName);
        structure[i][0] = columnName;
        structure[i][1] = def.getType();
        structure[i][2] = def.getPropertySummary();
    }
    view.loadStructure(structure);
    // Intensive work
    refreshEntityStatus(entityName);
    refreshCommandState(); // Must be after refreshEntityStatus()
}
void createTable(String entityName) {
    if (entityName == null) {
        GenLib.beep();
    } else {
        int count = getEntityRowCount(entityName);
        if (count >= 0) {
            GenLib.beep();
        } else {
            currentDatabaseUtil.addTable(entityName);
            refreshEntityStatus(entityName);
            refreshCommandState();
        }
    }
}
void emptyTable(String entityName) {
    if (entityName == null) {
        GenLib.beep(); // Should not be possible
    } else {
        MessageBox box = new MessageBox();
        box.setTitle("Confirm Empty Table");
        String answer = box.askYesNoBlock(
            "Proceed to empty all records in '" + entityName + "' ?");
        if (answer.equals("Yes")) emptyTableConfirmed();
    }
}
void dropTable(String entityName) {
    if (entityName == null) {
        GenLib.beep(); // Should not be possible
    } else {
        MessageBox box = new MessageBox();
        box.setTitle("Confirm Drop Table");
        String answer = box.askYesNoBlock(
            "Proceed to remove table '" + entityName + "' from the database?");
        if (answer.equals("Yes")) dropTableConfirmed();
    }
}
void refreshAll() {
    if (noCurrentDatabase()) {
        GenLib.beep();
        return;
    }
    String[] names = currentSchema.loadEntityNames();
    for (int i = 0; i < names.length; i++) {
        refreshEntityStatus(names[i]);
    }
}
void closeViewRequested() {
    view.setVisible(false);
}
//---------- Private Methods -----------------------------
private void emptyTableConfirmed() {
    String entityName = view.getSelectedEntity();
    if (entityName == null) {
        GenLib.beep();
    } else {
        currentDatabaseUtil.removeRows(entityName, null);
        refreshEntityStatus(entityName);
        refreshCommandState();
    }
}
private void dropTableConfirmed() {
    String entityName = view.getSelectedEntity();
    if (entityName == null) {
        GenLib.beep();
    } else {
        currentDatabaseUtil.removeTable(entityName);
        refreshEntityStatus(entityName);
        refreshCommandState();
    }
}
private void refreshCommandState() {
    if (noCurrentDatabase()) {
        view.setCommandEnabled("CreateTable", false);
        view.setCommandEnabled("EmptyTable", false);
        view.setCommandEnabled("DropTable", false);
        view.setCommandEnabled("RefreshAll", false);
    } else {
        // Database selected
        view.setCommandEnabled("RefreshAll", true);
        String entityName = view.getSelectedEntity();
        if (entityName == null) {
            view.setCommandEnabled("CreateTable", false);
            view.setCommandEnabled("EmptyTable", false);
            view.setCommandEnabled("DropTable", false);
        } else {
            // Entity selected
            // *** int rowCount = getEntityRowCount(entityName);
            if (entityRowCount < 0) {
                // Not in database
                view.setCommandEnabled("CreateTable", true);
                view.setCommandEnabled("EmptyTable", false);
                view.setCommandEnabled("DropTable", false);
            } else if (entityRowCount == 0) {
                // In database, zero rows
                view.setCommandEnabled("CreateTable", false);
                view.setCommandEnabled("EmptyTable", false);
                view.setCommandEnabled("DropTable", true);
            } else {
                // In database, 1 or more rows
                view.setCommandEnabled("CreateTable", false);
                view.setCommandEnabled("EmptyTable", true);
                view.setCommandEnabled("DropTable", true);
            }
        }
    }
}
private boolean noCurrentDatabase() {
    return (currentDatabase == null ? true : false);
}
private void refreshEntityStatus(String entityName) {
    entityRowCount = getEntityRowCount(entityName);
    String status = entityRowCount + " rows";
    if (entityRowCount < 0) status = "Not in database";
    view.setEntityStatus(entityName, status);
}
// Returns -1 if not in database
private int getEntityRowCount(String entityName) {
    if (! currentDatabaseUtil.isEntityInDatabase(entityName)) {
        return -1;
    } else {
        int count = currentDatabaseUtil.countRows(entityName, null);
        //print(".getEntityRowCount() - count = " + count);
        return count;
    }
}
private Database getDatabase(String dbName) {
    Database database = (Database)databases.get(dbName);
    if (database == null) {
        database = datastoreServices.createDatabase(dbName);
        databases.put(dbName, database);
    }
    return database;
}
private void initView() {
    view = new EntityAdminView();
    view.setController(this);
    view.setTitle("Entity Administrator");
    // Load database names
    String[] names = datastoreServices.loadDatabaseNames();
    view.loadDatabaseNames(names);
    refreshCommandState();
}
//--- Std
private static void print(String text) {
    System.out.println("EntityAdmin" + text);
}

} // End class
