package org.jcon.df.admin;

import org.jcon.ui.table.BTable;
import org.jcon.ui.table.BTableEvent;
import org.jcon.ui.table.BTableListener;
import org.jcon.ui.table.BTableModel;
import org.jcon.ui.VisualLib;
import org.jcon.ui.WindowLib;
import org.jcon.ui.WindowMgr;
import org.jcon.util.GenLib;
import java.awt.*;
import java.awt.event.*;
import java.util.Hashtable;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JSplitPane;

/**
 * The VIEW for the EntityAdmin. Presents the available
 * databases, a Database Entities list, EntityStructure
 * list, and buttons.
 *
 * Note - Padding cell values with " " to get good look.
 * This should change with newer Swing. Other problems too.
 *
 * @author Jack Harich
 */
public class EntityAdminView implements
    ActionListener, BTableListener, WindowListener, ItemListener {

//---------- Private Fields ------------------------------
private EntityAdmin controller;
private JFrame   frame = WindowMgr.createRegisteredFrame();
private Choice   databaseChoice = new Choice();
private Vector   entityNames = new Vector();

private EntityModel entityModel = new EntityModel();
private BTable      entityTable = new BTable();

private StructureModel structureModel = new StructureModel();
private BTable         structureTable = new BTable();

// Key = command, Object = Button
private Hashtable buttons = new Hashtable();

private String[][] entities  = new String[0][0];
private String[][] structure = new String[0][0];

//---------- Initialization ------------------------------
public EntityAdminView() {
    entityTable.setModel(entityModel);
    structureTable.setModel(structureModel);
    VisualLib.installLookAndFeel();

    //----- Frame
    frame.setBackground(Color.lightGray);
    frame.addWindowListener(this);
    databaseChoice.addItemListener(this);
    entityTable.addBTableListener(this);

    //----- North
    Panel northPanel = new Panel();
    frame.getContentPane().add("North", northPanel);

    // Button bar - Need to move over from Databases Choice ***
    Panel buttonBar = new Panel();
    northPanel.add(buttonBar);
    buttonBar.add(new Label("Entities"));
    buttonBar.add(createButton("Create", "CreateTable"));
    buttonBar.add(createButton("Empty", "EmptyTable"));
    buttonBar.add(createButton("Drop", "DropTable"));
    buttonBar.add(createButton("Refresh All", "RefreshAll"));

    // DatabasesChoice
    northPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
    northPanel.add(new Label("DBs"));
    northPanel.add(databaseChoice);

    //----- Center
    // Configure tables

    // entityTable
    entityTable.addColumn(0, 25, "Entity Name");
    entityTable.addColumn(1, 18, "Status");
    entityTable.setPreferredHeight(400);
    entityTable.init();
    // structureTable
    structureTable.addColumn(0, 20, "Column");
    structureTable.addColumn(1, 10, "Type");
    structureTable.addColumn(2, 30, "Properties");
    structureTable.setPreferredHeight(400);
    structureTable.init();

    // Put tables in splitter. Must be after init()
    JSplitPane splitPane = new JSplitPane(JSplitPane.
        HORIZONTAL_SPLIT, entityTable.getComponent(),
        structureTable.getComponent());
    splitPane.setContinuousLayout(false); // Until buffer
    splitPane.setDoubleBuffered(true);
    frame.getContentPane().add("Center", splitPane);

    // Correct Swing bug
    // This fails to have any effect, revealing yet another Swing bug
    //int prefWidth = structureTable.getPreferredWidth();
    //structureTable.setPreferredWidth(prefWidth + 4);

    //----- Other
    frame.pack(); // Works since preferredSize set

    // Correct Swing bug
    frame.setSize(frame.getSize().width + 2, frame.getSize().height);

    WindowLib.center(frame);
}
public static void main(String args[]) { // Unit test
    EntityAdminView view = new EntityAdminView();
    view.entities = new String[1][2];
    String[] row = {" Testing", " Unknown"};
    view.entities[0] = row;
    view.setVisible(true);
}
//---------- ActionListener Implementation ---------------
public void actionPerformed(ActionEvent evt) {
    String command = evt.getActionCommand().intern();
    //print(" - command = " + command);

    // Assert entity selected if Table command
    String entityName = getSelectedEntity();
    if (command.endsWith("Table") && entityName == null) {
        GenLib.beep();
        return;
    }
    // Pass command to controller
    if (command == "CreateTable") {
        controller.createTable(entityName);

    } else if (command == "EmptyTable") {
        controller.emptyTable(entityName);

    } else if (command == "DropTable") {
            controller.dropTable(entityName);

    } else if (command == "RefreshAll") {
        controller.refreshAll();

    } else {
        print(".actionPerformed() - Unknown command " + command);
    }
}
//---------- BTableListener Implementation ---------------
public void processBTableEvent(BTableEvent evt) {
    if (evt.getSource() == entityTable) {
        int type = evt.getEventType();
        switch(type) {
            case BTableEvent.ROW_SELECTED:
                String entityName = getSelectedEntity();
                //print(".processBTableEvent() - entityName = " + entityName);
                if (entityName != null) controller.entitySelected(entityName);
                break;
            case BTableEvent.ROW_ACTIVATED:
                // Not used
                break;
            default:
                // Ignore
                break;
        }
    }
}
//---------- WindowListener Implementatons ---------------
public void windowClosing(WindowEvent evt) {
    // User clicked on X or chose window Close
    controller.closeViewRequested();
}
public void windowClosed(WindowEvent evt) { }
public void windowDeiconified(WindowEvent evt) { }
public void windowIconified(WindowEvent evt) { }
public void windowOpened(WindowEvent evt) { }
public void windowActivated(WindowEvent evt) {  }
public void windowDeactivated(WindowEvent evt) { }

//---------- ItemListener Implementation -----------------
public void itemStateChanged(ItemEvent evt) {
    if (evt.getSource() == databaseChoice) {
        controller.databaseSelected(databaseChoice.getSelectedItem());
    }
}
//---------- Properties ----------------------------------
public void setController(EntityAdmin controller) {
    this.controller = controller;
}
public void setTitle(String title) {
    frame.setTitle(title);
}
public void setVisible(boolean visible) {
    frame.setVisible(visible);
}
//---------- Public Methods ------------------------------
public void loadDatabaseNames(String[] dbNames) {
    databaseChoice.removeAll();
    for (int i = 0; i < dbNames.length; i++) {
        databaseChoice.add(dbNames[i]);
    }
    databaseChoice.invalidate();
}
public void setEntityStatus(String entityName, String status) {
    int rowIndex = getEntityIndex(entityName);
    if (rowIndex < 0) {
        print(".setEntityStatus() - entityName " + entityName + " not in entityTable");
        GenLib.beep();
    } else {
        entities[rowIndex][1] = " " + status;
        entityModel.fireTableRowsUpdated(rowIndex, rowIndex);
    }
}
public void loadEntitiesUnknownStatus(String[] names) {
    // Clear previous
    entityNames.removeAllElements();
    entities = new String[names.length][2];
    // Load new
    for (int i = 0; i < names.length; i++) {
        String entityName = names[i];
        String[] row = {" " + entityName, " Unknown"};
        entities[i] = row;
        entityNames.addElement(entityName);
    }
    entityModel.fireTableDataChanged();
}
public void loadStructure(String[][] structure) {
    this.structure = structure;
    structureModel.fireTableDataChanged();
}
public void clearStructure() {
    structure = new String[0][0];
    structureModel.fireTableDataChanged();
}
public void setCommandEnabled(String command, boolean enabled) {
    Button button = (Button)buttons.get(command);
    if (button == null) {
        print(".setCommandEnabled() - Cannot find command " + command);
    } else {
        button.setEnabled(enabled);
    }
}
// Returns null if none
public String getSelectedEntity() {
    int index = entityTable.getSelectedRow();
    // Swing bug, index can be > entityNames.size() - 1
    if (index < 0 || index > entityNames.size() - 1) {
        return null; // Clicked on whitespace
    } else {
        return (String)entityNames.elementAt(index);
    }
}
public void close() {
    frame.dispose();
}
//---------- Private Methods -----------------------------
// Returns -1 if not found
private int getEntityIndex(String entityName) {
    for (int i = 0; i < entityNames.size(); i++) {
        String name = (String)entityNames.elementAt(i);
        if (name.equals(entityName)) return i;
    }
    return -1;
}
private Button createButton(String name, String command) {
    Button button = new Button(name);
    button.setActionCommand(command);
    button.addActionListener(this);
    buttons.put(command, button);
    return button;
}
//--- Std
private static void print(String text) {
    System.out.println("EntityAdminView" + text);
}
//========== Inner Classes ===============================
class EntityModel extends BTableModel {
    //----- Abstract implementation  -----
    public int getRowCount() {
        return entities.length;
    }
    public Object getValueAt(int row, int col) {
        return entities[row][col];
    }
} // End inner class
class StructureModel extends BTableModel {
    //----- Abstract implementation  -----
    public int getRowCount() {
        return structure.length;
    }
    public Object getValueAt(int row, int col) {
        return structure[row][col];
    }
} // End inner class

} // End class