/*
 * CropTableModel.java
 *
 * Created on July 20, 2004, 2:18 PM
 *
 * This is the model for delivering data to the crop table view. This handles loading the crop_defn.xml file and the
 * crop_lang.xml file. 
 *
 *
 * Jim Frankenberger
 * USDA-ARS, West Lafayette IN
 * jrf@purdue.edu
 *
 */
package ex1;

import de.schlichtherle.truezip.file.TFile;
import javax.swing.JOptionPane;

import java.util.*;

/**
 * Table model for crop viewer. This is the model for delivering data to the crop table view. This
 * handles loading the crop_defn.xml file and the crop_lang.xml file. The crop_defn.xml file
 * contains the following information that is stored:
 * <paramname> - name of the parameter
 * <paramtype> - type of the parameter, float, int, etc
 * <paramunit> - default units for the value
 *
 * The crop_lang.xml file contains the following information that is stored:
 * <paramprompt> - long description of parameter, what is displayed as a column heading
 * <paramaltunit> - an alternate unit (English) that the parameter can be displayed in
 * <factor> - what to multiple the value by to display the value in alternate units
 * <paramchoice> - list of values and text for the choice lists that a parameter may have
 *
 *
 * @author jrf
 *
 */
public class CropTableModel extends WepsTableModel {

    private static final long serialVersionUID = 1L;

    private final DispFileParser pDisp;   // crop display xml categories

    /**
     * Creates a new instance of CropTableModel
     *
     * @param cfgDir Directory where WEPS MCREW config files can be found
     * @param dbMainDir Directory where data files start for crops or operations
     */
    public CropTableModel(String cfgDir, String dbMainDir) {
        super(cfgDir, dbMainDir);
        // load the defn.xml file that has parameter info, only done once
        parms = new DefnFileParser(cfgDir + "/crop_defn.xml", true);
        // load the lang.xml file that has more parameter info, only done once
        new LangFileParser(parms, cfgDir + "/crop_lang.xml", true);

        pDisp = new DispFileParser(parms, cfgDir + "/crop_display.xml", true);
        // setup the data file parser, only done once
        pData = new DataFileParser(parms, cfgDir, true);
    }

    /**
     *
     * @return
     */
    public DispFileParser getDispFileParser() {
        return pDisp;
    }

    /**
     * Number of columns for table.
     *
     * @return The number of columns which is the number of crop parameters defined.
     */
    @Override
    public int getColumnCount() {
        // The two extra columns are the number, filename, dir columns at the beginning
        int c = parms.getParmCount() + 3;
        return c;
    }

    /**
     *
     * Number of rows in table, one per file.
     *
     * @return The number of rows in the crop table which is the number of crop files loaded.
     */
    @Override
    public int getRowCount() {
        return xmlFiles.size();
    }

    /**
     *
     * This is prompt field for the parameter with any units appended.
     *
     * @param col number number to get heading/name for
     * @return Name of the column with units
     */
    @Override
    public String getColumnName(int col) {
        return parms.getParmPrompt(col, altUnits);
    }

    @Override
    public int getLogicalRow(int tab, int row) {
        return row;
    }

    /**
     *
     * This is called by the JTable framework to get a value at a particular row and column.
     *
     * @param row The row in the table to get the value from
     * @param col The column in the table to get the value from
     * @return The String(object) of the cell contents
     */
    @Override
    public Object getValueAt(int row, int col) {
        if (col == 0) {
            return Integer.toString(row + 1);
        } else if (col == 1) {
            return getFileName(row);
        } else if (col == 2) {
            WepsDBFile w = xmlFiles.get(row);
            return w.getPathOnly();
        } else {
            if (row < xmlFiles.size()) {
                ParamDef p = parms.getColumn(col - 3);
                if (p != null) {
                    WepsDBFile wf = xmlFiles.get(row);
                    if (wf != null) {
                        return wf.getValue(p, altUnits);
                    } else {
                        return "???";
                    }
                } else {
                    return "???";
                }
            } else {
                return "???";
            }
        }
    }

    /**
     *
     * This is called by the JTable framework to set a value at a particular position. This passes
     * along the altUnits flag so any translation can be done.
     *
     * @param o - Object that will be saved (string)
     * @param row - Row of table data is from
     * @param col - Column of table data is from
     */
    @Override
    public void setValueAt(Object o, int row, int col) {

        if (col <= 1) {
            return;
        }
        String pstr = (String) o;
        if (pstr != null) {
            if (row < xmlFiles.size()) {
                ParamDef p = parms.getColumn(col - 3);
                if (p != null) {
                    WepsDBFile wf = xmlFiles.get(row);
                    if (wf != null) {
                        wf.setValue(p, pstr, altUnits);
                    }
                }
            }
        }
    }

    /**
     *
     * The type of data in this column int, float, string, list
     *
     * @param col
     * @return Type of the column 0,1,2,3
     */
    @Override
    public ParamDef.ColumnType getColumnType(int col) {
        return parms.getType(col);
    }

    /**
     *
     * Called by JTable framework.
     *
     * @param c Column to get class for
     * @return 
     */
    @Override
    public Class<?> getColumnClass(int c) {
        Object p = getValueAt(0, c);
        if (p != null) {
            return p.getClass();
        } else {
            return "???".getClass();
        }
    }

    /**
     *
     * Called by JTable framework to see if this cell can switch to edit mode
     *
     * @param row Row to check if editable
     * @param col Column to check if editable
     * @return true if the cell can handle changes
     */
    @Override
    public boolean isCellEditable(int row, int col) {
        if (col <= 2) {
            return false;
        }
        if (row < xmlFiles.size()) {
            WepsDBFile wf = xmlFiles.get(row);
            if (wf.isReadOnly()) {
                return false;
            }
        }
        return allowEdits;

    }

    /**
     *
     * Get number of list elements for a dropdown list for this column.
     *
     * @param col Column to check for number of choices
     * @return number of choices this column dropdown list contains
     */
    public int getChoiceCount(int col) {
        return parms.getChoiceCount(col);
    }

    /**
     *
     * From a column dropdown list get a specific entry.
     *
     * @param col Column to check for dropdown list
     * @param ch Entry in dropdown list to return
     * @return String representing this specific entry
     */
    public String getChoice(int col, int ch) {
        return parms.getChoice(col, ch);
    }

    /**
     *
     * Parse a CROP data file and add it to the table model.
     *
     * @param file Crop XML File to load into the table model
     */
    @Override
    public void addXmlFile(String file) {
        TFile wf = new TFile(file);
        if (wf.exists() == true) {
            WepsDBFile w = new WepsDBFile(file, true, parms, dbDir);
            pData.addXmlFile(w);
            xmlFiles.add(w);
        } else {
            JOptionPane.showMessageDialog(null, "Can not find file: " + file);
        }
    }

    /**
     *
     * For any modified files try to save them.
     *
     */
    @Override
    public String saveAll() {
        
        for (WepsDBFile wf : xmlFiles) {
            if (wf != null) {
                if (wf.isModified()) {
                    wf.saveFile(mcrewCfgDir);
                }
            }
        }
        return "Files Saved.";
    }

    /**
     *
     * Return true if this file attached to the row has been changed
     *
     * @param row Row to check if associated file has been modified
     * @return true if this file in the specified row has changed and need to be saved.
     *
     */
    @Override
    public boolean isModified(int row) {
        WepsDBFile wf = xmlFiles.get(row);
        if (wf != null) {
            return wf.isModified();
        }
        return false;
    }

    /**
     *
     * @param row
     * @return
     */
    @Override
    public boolean nameMismatched(int row) {
        WepsDBFile wf = xmlFiles.get(row);
        if (wf != null) {
            return wf.isNameMismatched();
        }
        return false;
    }
    
    @Override
    public boolean outOfOrder(int row)
    {
        //at the monment, there is no way for crops to be out of order.
        return false;
    }

    /**
     *
     * Create a copy of the crop data on a certain row and give it a new name.
     *
     * @param name new filename for crop
     * @param row Base row to copy parameters from
     *
     */
    @Override
    public void copy(String name, int row) {
        WepsDBFile wf = new WepsDBFile(name, true, parms, dbDir);

        wf.createClone(mcrewCfgDir, xmlFiles.get(row), false);
        pData.addXmlFile(wf);
        xmlFiles.add(wf);
    }

    /**
     * Get a list of the visible and hidden parameters based on what tabs are selected in the main
     * table.
     * @param visible
     * @param tab
     * @param hidden
     */
    public void getVisibleList(ArrayList<Integer> visible, ArrayList<Integer> hidden, int tab) {
        int count = parms.getParmCount();

        for (int i = 0; i < count; i++) {
            ParamDef p = parms.getColumn(i);
            if (pDisp.isInCategory(p, tab)) {
                visible.add(i);
            } else {
                hidden.add(i);
            }
        }
    }

    @Override
    public WepsTableModel.TableEnum getType() {
        return WepsTableModel.TableEnum.Crop;
    }

    @Override
    public String getTypeString() {
        return "crop";
    }

    @Override
    public String getTypeFileExtension() {
        return ".crop";
    }
    
    /**
     * CropTableModel's getTableStatus needs to override WepsTableModel's because
     * the CropTableModel needs to check all of the xml files, and return the
     * highest value amoung them.
     * @return 
     */
    @Override
    public InputLimits.TableStatus getTableStatus()
    {
        InputLimits.TableStatus accumulate = InputLimits.TableStatus.OKAY;
        for(WepsDBFile file : xmlFiles)
        {
            InputLimits.TableStatus current = file.getTotalStatus();
            if(accumulate.lessThan(current)) accumulate = current;
        }
        return accumulate;
    }
    
    /**
     * If the out of bounds cell is on this tab, we can use the super method call.
     * Otherwise, we return 0
     * @return 
     */
    @Override
    public int getFirstRedRow() {
        if(super.getTableStatus().lessThan(InputLimits.TableStatus.NOSAVE)) return 0;
        return super.getFirstRedRow();
    }

    /**
     * If the out of bounds cell is on this tab, we can use the super method call.
     * Otherwise, we return 0
     * @return 
     */
    @Override
    public int getFirstRedColumn() {
        if(super.getTableStatus().lessThan(InputLimits.TableStatus.NOSAVE)) return 0;
        return super.getFirstRedColumn();
    }
    
    /**
     * If the out of bounds cell is on this tab, we can use the super method call.
     * Otherwise, we return 0
     * @return 
     */
    @Override
    public int getFirstRedColumn(int row)
    {
        if(super.getTableStatus().lessThan(InputLimits.TableStatus.NOSAVE)) return 0;
        return super.getFirstRedColumn(row);
    }
    
    /**
     * If the out of bounds cell is on this tab, we can use the super method call.
     * Otherwise, we return 0
     * @return 
     */
    @Override
    public int getFirstYellowRow() {
        if(super.getTableStatus().lessThan(InputLimits.TableStatus.WARNSAVE)) return 0;
        return super.getFirstYellowRow();
    }
    
    /**
     * If the out of bounds cell is on this tab, we can use the super method call.
     * Otherwise, we return 0
     * @return 
     */
    @Override
    public int getFirstYellowColumn() {
        if(super.getTableStatus().lessThan(InputLimits.TableStatus.WARNSAVE)) return 0;
        return super.getFirstYellowColumn();
    }
    
    /**
     * If the out of bounds cell is on this tab, we can use the super method call.
     * Otherwise, we return 0
     * @return 
     */
    @Override
    public int getFirstYellowColumn(int row)
    {
        if(super.getTableStatus().lessThan(InputLimits.TableStatus.WARNSAVE)) return 0;
        return super.getFirstYellowColumn(row);
    }

}
