/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on ----
!  AUTHOR(S): KOGA, Junichiro
!  File : TableModelForNonTabularData.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */
package ciss.phase_viewer.primitiveguis.tableforinputinterface;

import java.util.EventListener;
import java.util.EventObject;
import java.util.Vector;

import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

import org.apache.log4j.Logger;

import ciss.phase_viewer.inputinterface.InputInterface;
import ciss.phase_viewer.inputinterface.InputInterfaceEntry;
import ciss.phase_viewer.inputinterface.InputInterfaceEntryChangeEvent;
import ciss.phase_viewer.inputinterface.InputInterfacePrimitiveEntry;

public class TableModelForNonTabularData extends TableModelForInputInterface {
    private static Logger logger = Logger
            .getLogger(TableModelForNonTabularData.class.getName());

    private Vector entryVector = new Vector();
    private int rowStart = 1;
    private boolean rowOriented = false;

    private int[] map;

    public TableModelForNonTabularData(String[] inputSpecifications,
            InputInterface inputInterface, int[] mapSpecCol, EventListener el) {
        super(inputSpecifications, inputInterface, mapSpecCol, el);
        super.init();
    }

    public TableModelForNonTabularData(String[] inputSpecifications,
            InputInterface inputInterface, int[] mapSpecCol, EventListener el,
            int columnIndex) {
        super(inputSpecifications, inputInterface, mapSpecCol, el, columnIndex);
        super.init();
    }

    public boolean isRowOriented() {
        return this.rowOriented;
    }

    public void inputInterfaceInitializing() {
        TableModelListener[] listeners = this.getTableModelListeners();
        for (int i = 0; i < listeners.length; i++) {
            this.removeTableModelListener(listeners[i]);
        }

        int row = getRowCount();
        int col = getColumnCount();
        int colStart = 1;

        for (int i = 0; i < row; i++) {
            for (int j = colStart; j < col; j++) {
                setValueAt("", i, j);
            }
        }
        restoreListeners(listeners);
    }

    protected void createTableColumns() {
        if (columns == null) {
            return;
        }

        logger.debug("creating table columns...");
        String[] colNames = null;
        if (spec.isRowOriented()) {
            rowOriented = true;
            colNames = spec.getColumnNamesForNonTabularData();
            setColumnIdentifiers(colNames);
            setRowCount(columns.length);
            for (int i = 0; i < columns.length; i++) {
                logger.debug("set name : " + columns[i].getName());
                setValueAt(columns[i].getName(), i, 0);
            }
        } else {
            rowOriented = false;
            for (int i = 0; i < columns.length; i++) {
                addColumn(columns[i].getName());
            }
            int nrw = spec.getNumRows();
            if (nrw > 0) {
                setRowCount(nrw);
            }
            String[] foo = inputSpecifications[0].split("\\.");
            String tag = foo[foo.length - 1];
            for (int i = 0; i < getRowCount(); i++) {
                setValueAt(tag, i, 0);
            }
        }

    }

    /**
     * InputInterfaceオブジェクトを展開する.
     */
    protected void extractInputFile() {
        entryVector = new Vector();
        map = new int[columns.length];
        int count = 0;
        logger.debug("extraction input. " + inputSpecifications[0]);
        for (int i = 0; i < columns.length; i++) {
            String fullName = inputSpecifications[0] + "."
                    + columns[i].getName().trim();
            logger.debug("fullname: " + fullName);
            if (columns[i].ignoreOnSave()) {
                continue;
            }
            InputInterfacePrimitiveEntry entry = input
                    .getInputInterfacePrimitiveEntry(fullName);
            map[i] = count;
            count++;
            entryVector.addElement(entry);
        }
        setInputToModel();
    }

    protected void setInputToModel() {
        input.setUpdateUndoStack(false);
        updateInputInterface = false;

        int icol = getColumnCount();
        int irow = getRowCount();

        int idata = icol + rowStart;
        int idata2 = irow;

        if (rowOriented) {
            idata = irow;
            idata2 = icol + rowStart;
        }

        for (int i = 0; i < entryVector.size(); i++) {
            if (i < idata) {
                InputInterfacePrimitiveEntry entry = (InputInterfacePrimitiveEntry) entryVector
                        .get(i);
                String value = entry.getValue();
                String[] values = value.trim().split("\\s+");
                for (int j = 0; j < values.length; j++) {
                    if (j < idata2) {
                        if (rowOriented) {
                            int tmp = j + rowStart;
                            logger.debug("rowOriented; set value " + values[j]
                                    + " at: " + i + " " + tmp);
                            setValueAt(values[j], i, tmp);
                        } else {
                            logger.debug("set value " + values[j] + " at: " + j
                                    + " " + i);
                            setValueAt(values[j], j, i + rowStart);
                        }
                    }
                }
            }
        }

        input.setUpdateUndoStack(true);
        updateInputInterface = true;
    }

    /**
     * テーブルモデルリスナーが呼ぶメソッド. InputInterfaceオブジェクトを更新する.
     */
    public void execute(EventObject e) {
        if (!updateInputInterface) {
            return;
        }

        // temporarily remove the table model listeners during update.
        TableModelListener[] listeners = this.getTableModelListeners();

        for (int i = 0; i < listeners.length; i++) {
            this.removeTableModelListener(listeners[i]);
        }

        TableModelEvent tmde = (TableModelEvent) e;
        int first = 0;
        int last = 0;
        int chcol = 0;

        if (tmde != null) {
            first = tmde.getFirstRow();
            last = tmde.getLastRow();
            chcol = tmde.getColumn();
            logger.debug("first row that changed: " + tmde.getFirstRow());
            logger.debug("last row that changed: " + tmde.getLastRow());
            logger.debug("type: " + tmde.getType());
        } else {
            restoreListeners(listeners);
            return;
        }

        if (first < 0 || last < 0 || first >= getRowCount()
                || last >= getRowCount()) {
            restoreListeners(listeners);
            return;
        }

        logger.debug("updating table data ...");
        int icol = this.getColumnCount();
        int irow = this.getRowCount();
        int rowStart = 1;

        String[] columnName = new String[icol];
        for (int i = 0; i < icol; i++) {
            columnName[i] = getColumnName(i);
        }

        int change = -1;
        int targ = -1;
        if (rowOriented) {
            change = first;
            targ = first;
        } else {
            change = chcol;
            targ = chcol;
        }

        if (change < 0 || targ < 0) {
            restoreListeners(listeners);
            return;
        }

        Vector entries = new Vector();
        InputInterfacePrimitiveEntry pentry = input
                .getInputInterfacePrimitiveEntry(inputSpecifications[0] + "."
                        + columns[targ].getName());
        logger.debug("targ: " + targ + "changing entry: "
                + inputSpecifications[0] + "." + columns[targ].getName());
        pentry.saveState(); // for undo/redo operations...

        String accumData = "";
        String name = "";
        if (rowOriented) {
            for (int j = rowStart; j < icol; j++) {
                accumData += (String) getValueAt(change, j) + " ";
            }
            name = ((String) getValueAt(change, 0)).trim();
        } else {
            for (int j = 0; j < irow; j++) {
                accumData += (String) getValueAt(j, change);
            }
            name = columnName[change].trim();
        }

        pentry.setName(name);
        pentry.setValue(accumData);
        pentry.setUnit("");
        input.replaceEntry(pentry, this, callListener);
        entries.addElement(pentry);

        restoreListeners(listeners);
    }

    public void inputInterfaceEntryChanged(InputInterfaceEntryChangeEvent e) {
        logger.debug("at inputInterfaceEntryChaged: tag: " + e.getTag());
        if (e == null || e.getTag() == null) {
            logger.debug("something is wrong... InputInterfaceEntryChangeEvent not properly initialized.");
            return;
        }

        if (e.getSource() == this) {
            logger.debug("source == this");
            return;
        }

        InputInterfaceEntry entry = e.getEntry();
        if (entry.getEntryType() != InputInterfaceEntry.PRIMITIVE) {
            logger.debug("not primitive entry");
            return;
        }

        int target = -1;
        String tag = e.getTag().trim() + "." + e.getEntry().getName();
        String targetTag = "";
        for (int i = 0; i < super.columns.length; i++) {
            if (tag.equalsIgnoreCase(inputSpecifications[0] + "."
                    + super.columns[i].getName())) {
                target = i;
            }
        }

        if (target < 0) {
            logger.debug("not target");
            return;
        }

        logger.debug("tag: " + tag);

        logger.debug("e.getSource(): " + e.getSource());
        logger.debug("this: " + this);

        InputInterfacePrimitiveEntry pentry = input
                .getInputInterfacePrimitiveEntry(tag);
        entryVector.set(map[target], pentry);

        setInputToModel();
    }

}
