/** Table
 *
 * @version 1.1
 *
 * @author Sada
 *
 * date Mar 2003
 * This class constitutes the main table which is displayed when MCREW comes up.
 */
package usda.weru.mcrew;

import java.awt.event.*;
import de.schlichtherle.truezip.file.TFile;
import javax.swing.*;
import java.util.*;
import java.text.*;
import com.klg.jclass.table.*;
import com.klg.jclass.cell.editors.*;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.print.PageFormat;
import org.apache.log4j.Logger;
import usda.weru.mcrew.ManageData.CropIntervalInfo;
import usda.weru.mcrew.MyArrayEditor.ArrayEditorPopup;
import usda.weru.util.*;

/** The main table for Mcrew
 * This hold the vectors for dates and operations
 * It is a jctable
 * author :  Manmohan Uttarwar, Sada, Sudhir Kaul,
 * date   : Dec 200
 */
public class Table extends JPanel implements JCEditCellListener, JCSelectListener, JCPrintListener, JCTraverseCellListener {

    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = Logger.getLogger(Table.class);
    //public static boolean cropObjectDataChanged = false;
    /**
     * The vector that holds all the string values for column headings of the main MCREW
     * table.
     */
    /**
     * Tells us the height of the row with column headings.
     */
    public int headerRowHeight = 30;
    /**
     * The color object to be used for header row colors.
     */
    public static Color orangeColor = Color.ORANGE;
    /**
     * Color for entries out of hard limits
     */
    public static Color hard = Color.MAGENTA;
    /**
     * Color for entries out of soft limits
     */
    public static Color soft = Color.YELLOW;
    /**
     * The background color of the column header row.
     */
    public String headerRowColor = "Orange";
    /**
     * The font size of the text that goes in the column header row of the MCREW table.
     */
    public int headerRowFontSize = 14;
    /**
     * The font name of the text that goes in the column header row of the MCREW table.
     */
    public String headerRowFontName = "Times New Roman";
    private ManageData mManageData;
    private JCTable jctable;
    private MyMouseAdapter mouseAdapter;
    private ArrayEditorPopup arrayEditor;
    private BaseCellEditor bce;

    JCStringCellEditor se;
    private boolean mouseFlg = false;
    //private Vector calibColIdx;
    //private Vector mActions;
    //mActions = mOprnObj.getAllActions(); // correct this .. it doesn't belong here
    private final int mNumDataRows = 0;
    private final int mCurrentRow = -1;
    private final int editRow = -1;
    private final int editColumn = -1; // Not sure of using these row variables. Just retained from previous code.
    private final boolean debugFlg = true;
    private boolean killFlag = false;
    /**
     * Flag that tells whether data was modified on the crop or operation dialog screens or the main
     * MCREW table so that we can save the new data if needed.
     */
    private boolean dataChanged = false;

    /**
     *
     * @param kill
     */
    public void setKillFlag(boolean kill) {
        killFlag = kill;
    }
    /**
     * Store the elements that go in the choice list seen in some cells of the MCREW table
     * or even in various tables in oprn_dlg, crop_dlg, etc.
     */
    //public Hashtable paramChoices = null;
    /**
     * The parameter objects associated with a crop meta data can be accessed through this
     * hashtable.
     */
    //public Hashtable cropParams = null;
    private TablePanel mcrew;

    /**
     *
     * @param m
     */
    public Table(TablePanel m, ManageData inputData) {
        mcrew = m;
        init(inputData);
    }

    /**
     *
     * @param pManageData
     */
    public Table(ManageData pManageData) {
        init(pManageData);
    }

    /**
     *
     * @throws Throwable
     */
    @Override
    protected void finalize() throws Throwable {
        cleanup();
        super.finalize();
    }

    /**
     *
     */
    public void cleanup() {
        mcrew = null;
        mManageData = null;
    }

    /**
     * Single argument constructor that takes in the data object that stores all the
     * operation and crop information. This constructor also sets the look and feel of
     * table by some method calls.
     * @param pManageData The object holds the data for each row (through RowInfo object). It also
     * has various functions to deal with the operations like cut, copy, paste, read and
     * write data files
     */
    public void init(ManageData pManageData) {
        //data model
        mManageData = pManageData;

        mouseAdapter = new MyMouseAdapter(this);

        //make the table
        makeTable();

        //Assign the datasource
        jctable.setDataSource(mManageData);

        //setup the popup listener
        addMouseListener(mouseAdapter);
        addMouseWheelListener(mouseAdapter);
        // If there's is no data in the cell, then mouse event should be caught by jctable
        jctable.addMouseListener(mouseAdapter);
        jctable.addMouseWheelListener(mouseAdapter);

        LayoutManager layout = new GridLayout(0, 1);
        setLayout(layout);

        add(jctable);
        setVisible(true);

    }
    
    /**
     * Sets the look and feel of the table like the height and width of each cell in a row,
     * its text font, background & foreground color, type of cell bordering, etc.
     */
    public void makeTable() {
        jctable = new JCTable();

        jctable.addKeyListener(new KeyListener() {

            @Override
            public void keyPressed(KeyEvent e) {
            }

            @Override
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_DELETE) {
                    deleteRows();
                    if (mcrew != null) {
                        mcrew.setDeleted();
                    }
                }
            }

            @Override
            public void keyTyped(KeyEvent e) {
            }
        });

        jctable.addEditCellListener(this);
        jctable.addTraverseCellListener(this);

        jctable.addSelectListener(this);
        jctable.setSelectionPolicy(JCTableEnum.SELECT_MULTIRANGE);
        jctable.setSelectIncludeLabels(false);
        jctable.setFocusIndicator(JCTableEnum.FOCUS_NONE);

        jctable.setColumnLabelDisplay(true);
        jctable.setRowLabelDisplay(true);
        jctable.setMinWidth(JCTableEnum.LABEL, 25);
        jctable.setMaxWidth(JCTableEnum.LABEL, 25);

        jctable.setDoubleBuffered(true);
        jctable.setAutoScroll(JCTableEnum.AUTO_SCROLL_BOTH);

        //Set the frozen column
        jctable.setFrozenColumns(MCREWConfig.getFrozenColumn());

        //Freeze the header line
        jctable.setFrozenRows(0); // header line
        //Set the data row heights from the default data style

        jctable.setMinHeight(JCTableEnum.ALLCELLS, MCREWConfig.getDefaultDataCellStyle().getRowMinHeight());
        jctable.setPixelHeight(JCTableEnum.ALLCELLS, MCREWConfig.getDefaultDataCellStyle().getRowHeight());
        jctable.setMaxHeight(JCTableEnum.ALLCELLS, MCREWConfig.getDefaultDataCellStyle().getRowMaxHeight());

        //Set the header row heights from the default header style
        jctable.setMinHeight(-1, MCREWConfig.getDefaultHeaderCellStyle().getRowMinHeight());
        jctable.setPixelHeight(-1, MCREWConfig.getDefaultHeaderCellStyle().getRowHeight());
        jctable.setMaxHeight(-1, MCREWConfig.getDefaultHeaderCellStyle().getRowMaxHeight());

        //I'm not sure what the focus color is doing
        jctable.setFocusColor(Color.red);

        //Apply Default Header Cells Style
        jctable.setCellStyle(-1, JCTableEnum.ALLCELLS, MCREWConfig.getDefaultHeaderCellStyle().getJCCellStyle());
        //Apply Default Data Cells Style
        jctable.setCellStyle(JCTableEnum.ALLCELLS, JCTableEnum.ALLCELLS,
                MCREWConfig.getDefaultDataCellStyle().getJCCellStyle());

        //special renderer for crop interval colors
        //JCCellStyle style = (JCCellStyle)ConfigData.getDefaultHeaderCellStyle().getJCCellStyle().clone();
        JCCellStyle style = new JCCellStyle();
        style.setCellRenderer(new CropIntervalColorCellRenderer());
        style.setCellBorder(null);
        jctable.setCellStyle(JCTableEnum.ALL, JCTableEnum.LABEL, style);

        //Loop over the column defns and apply any header and data styles
        MCREWConfig.ColumnDefn tempColumnDef;
        for (int columnIndex = 0; columnIndex < MCREWConfig.getColumns().size(); columnIndex++) {
            tempColumnDef = MCREWConfig.getColumns().get(columnIndex);

            //Cell Styles
            MCREWConfig.CellStyle dataStyle = tempColumnDef.getDataCellStyle();
            if (dataStyle != null) {
                jctable.setCellStyle(JCTableEnum.ALLCELLS, columnIndex, dataStyle.getJCCellStyle());
            }

            //Header cell styles
            if (tempColumnDef.getHeaderCellStyle() != null) {
                jctable.setCellStyle(-1, columnIndex, tempColumnDef.getHeaderCellStyle().getJCCellStyle());
            }

            //Set Column Widths
            jctable.setMinWidth(columnIndex, tempColumnDef.getMinWidth()); // make date smaller

            jctable.setPixelWidth(columnIndex, tempColumnDef.getWidth());
            jctable.setMaxWidth(columnIndex, tempColumnDef.getMaxWidth());
        }

    }

    /**
     *
     * @param cursor
     */
    @Override
    public void setCursor(Cursor cursor) {
        super.setCursor(cursor);
        jctable.setTrackCursor(cursor.getType() == Cursor.DEFAULT_CURSOR);
        jctable.setCursor(cursor);
    }

    /**
     * This method is not implemented
     * @param ev Cell edit event
     */
    // Start implementing JCEditCellListener
    @Override
    public void beforeEditCell(JCEditCellEvent ev) {
    }

    /**
     * This method is not implemented
     * @param ev Cell edit event
     */
    @Override
    public void editCell(JCEditCellEvent ev) {
    }

    /**
     * This method captures the new value assigned to the cell which is then used for storing
     * in the datastore or other datastructure to be retrieved in future.
     * @param ev Cell edit event
     */
    @Override
    public void afterEditCell(JCEditCellEvent ev) {
        checkData();
    }
    // Finish implementing JCEditCellListener
    /************************************************************* neha */
// Start implementing JCTraverseCellListener
    /**
     * This method is not implemented
     * @param e Cell traverse event
     */
    @Override
    public void traverseCell(JCTraverseCellEvent e) {
//		//System.out.println("T_tC: " + e.getColumn() + " " + e.getRow());
    }

    /**
     *
     */
    public void commitEdit() {
        jctable.commitEdit(true);
    }

    /**
     * This method is not implemented
     * @param e Cell Traverse event
     */
    @Override
    public void afterTraverseCell(JCTraverseCellEvent e) {
//		setSelectedCells(JCCellRange r)
//		//System.out.println("T_aTC: " + e.getNextColumn() + " " + e.getNextRow() + " " + e);
//		JCCellRange jcr = new JCCellRange(e.getNextRow(), e.getNextColumn(), e.getNextRow(), e.getNextColumn());
//		jctable.setSelectedCells(jcr);
    }
// End implementing JCTraverseCellListener

    /**
     * Selections should only be full rows. This method adds a range of cells to
     * the selection. So basically this happens after the selection is done.
     * @param e The selection event for the cells in each table rows.
     */
    @Override
    public void afterSelect(JCSelectEvent e) {
        usda.weru.util.Util.debugPrint(debugFlg, e.toString());
        int startColumn = e.getStartColumn();
        int endColumn = e.getEndColumn();

        //      //System.out.println("Table: start row:"+startRow+"  start column:"+startColumn);
        //      //System.out.println("Table: end row:"+endRow+"  end column:"+endColumn);
        if (startColumn == 0 && endColumn == (jctable.getNumColumns() - 1)) {
            return; // all Columns selected

        }
//      boolean rtnFlg = jctable.addRowSelection(e.getStartRow(), e.getEndRow());
        boolean rtnFlg = jctable.addSelection(e.getStartRow(), 0, e.getEndRow(), jctable.getNumColumns() - 1);
        usda.weru.util.Util.debugPrint(debugFlg, "add succeeded " + rtnFlg + " " + jctable.getSelectedCells());
    }

    /**
     * This method is not needed.
     * @param e The selection event for the cells in each table rows.
     */
    @Override
    public void beforeSelect(JCSelectEvent e) {
//		
//		e.setCancelled(mouseFlg);
        usda.weru.util.Util.debugPrint(debugFlg, mouseFlg + " " + e.toString());
    }

    private static class CompareRange extends JCCellRange implements java.util.Comparator<JCCellRange> {

        private static final long serialVersionUID = 1L;

        @Override
        public int compare(JCCellRange o1, JCCellRange o2) {
            return (o2).start_row - (o1).start_row;
        }

    }

    /**
     * Ticket: 1149
     * Joseph Levin
     * This method consolidates the selection ranges of the table into the minmal amount.
     * Example : if R0 and R1 have been individually selected by holding ctrl, getSelectedRows
     * will consolidate the two ranges into one range covering R(0-1).
     */
    private Vector<JCCellRange> getSelectedRows() {
        // Quest doesn't really like to specify return types, so we have to do an unchecked cast here
        Collection<JCCellRange> col_selectedCells = Caster.<Collection<JCCellRange>>cast(jctable.getSelectedCells());
        Vector<JCCellRange> vec_selectedCells = new Vector<>();
        JCCellRange tempCellRange1;
        JCCellRange tempCellRange2;

        // We will select a full row
        int startColumn = 0;
        int endColumn = jctable.getNumColumns() - 1;
        int startRow1;
        int startRow2;
        int endRow1;
        int endRow2;
        try {
            for (Iterator<JCCellRange> selectedCellsIterator1 = col_selectedCells.iterator();
                    selectedCellsIterator1.hasNext();) {
                tempCellRange1 = selectedCellsIterator1.next();
                startRow1 = tempCellRange1.start_row;
                endRow1 = tempCellRange1.end_row;
                //Rows cannot be in the header
                if (startRow1 < jctable.getFrozenRows()) {
                    startRow1 = jctable.getFrozenRows();
                    tempCellRange1.start_row = startRow1;
                }
                if (endRow1 < jctable.getFrozenRows()) {
                    endRow1 = jctable.getFrozenRows();
                    tempCellRange1.end_row = endRow1;
                }
                //Rows cannot be greater than the number of rows
                int max = jctable.getNumRows() - 1;
                
                if (startRow1 > max) {
                    startRow1 = max;
                    tempCellRange1.start_row = startRow1;
                    return null;
                }
                if (endRow1 > max) {
                    endRow1 = max;
                    tempCellRange1.end_row = endRow1;
                    return null;
                }

                tempCellRange1.start_column = startColumn;
                tempCellRange1.end_column = endColumn;
                if (startRow1 > endRow1) {
                    tempCellRange1.start_row = endRow1;
                    tempCellRange1.end_row = startRow1;
                }
                else
                {
                    tempCellRange1.start_row = startRow1;
                    tempCellRange1.end_row = endRow1;
                }
                vec_selectedCells.add(tempCellRange1);
            }
        } catch (NullPointerException e) {
            //System.out.println("Unable to determine selected rows.");
            return vec_selectedCells;
        }

        
        
        //Ranges need to be sorted by start_row before iterating to minimize the number of ranges returned.
        Collections.sort(vec_selectedCells, new CompareRange());

        //This vector will only have the ranges we need.  Some ranges will be expanded.
        Vector<JCCellRange> vec_requiredRanges = new Vector<>();
        boolean shouldAddRange1;
        //Loop over all the ranges sorted by start_row
        int i1;
        int i2;
        for (i1 = 0; i1 < vec_selectedCells.size(); i1++) {
            tempCellRange1 = vec_selectedCells.get(i1);
            shouldAddRange1 = true;
            for (i2 = 0; i2 < vec_requiredRanges.size(); i2++) {
                tempCellRange2 = vec_requiredRanges.get(i2);
                //Does range1 fit inside range2?
                if (tempCellRange1.start_row >= tempCellRange2.start_row
                        && tempCellRange1.end_row <= tempCellRange2.end_row) {
                    shouldAddRange1 = false;
                    break;
                }
                //Does range1 expand the lower limit of range2?
                if (tempCellRange1.start_row < tempCellRange2.start_row
                        && tempCellRange1.end_row >= tempCellRange2.start_row - 1) {
                    //Yes, extend range2 to the lower bound.
                    tempCellRange2.start_row = tempCellRange1.start_row;
                    shouldAddRange1 = false;
                }
                //Does range1 expand the upper limit of range2?
                if (tempCellRange1.end_row > tempCellRange2.end_row
                        && tempCellRange1.start_row <= tempCellRange2.end_row + 1) {
                    //Yes, extend range2 to the upper bound.
                    tempCellRange2.end_row = tempCellRange1.end_row;
                    shouldAddRange1 = false;
                }
            }
            //Did we do anything with the exsisting ranges?
            if (shouldAddRange1) {
                //No, add range1 to the required vector.
                vec_requiredRanges.add(tempCellRange1);
            }
        }

        //Sort from smallest to largest start row
        Collections.sort(vec_requiredRanges, new CompareRange());

        //Retuns the minimal number of selection ranges
        return vec_requiredRanges;
    }
    
    

    /*
     *Ticket: 1149
     *Joseph Levin
     * Rewrote the getSelectedRows method.  It is located above
     */
    @Deprecated
    @SuppressWarnings({"unchecked", "rawtypes"})
    private Vector getSelectedRowsOld() {

        Collection sc = jctable.getSelectedCells();
        if (sc == null) {
            return null;
        }
        boolean dontAdd = false;

        Vector scv = new Vector();
        for (Iterator sci = sc.iterator(); sci.hasNext();) {
            //Initialize to false before every iteration
            dontAdd = false;
            JCCellRange jccr = (JCCellRange) sci.next();

            /* Added by Sada, Jun 30, 2003 */
            /* Note: Due to some reasons, there are invalid entries sometimes in the collection such as
             * Row 1, Col -1, R1, C 214748367
             */
            if ((jccr.start_column < 0) || (jccr.end_column < 0) || (jccr.start_row < 0) || (jccr.end_row < 0)) {
                continue;
            }
            /*	End, additions by Sada, Jun 30, 2003 */
            for (Object scv1 : scv) {
                JCCellRange addedCell = (JCCellRange) scv1;
                if (jccr.start_row == addedCell.start_row && jccr.end_row == addedCell.end_row) {
                    dontAdd = true;
                    break;
                }
            } //end of for loop
            //Set the cell range to cover an entire row - neha

            jccr.end_column = jctable.getNumColumns() - 1;
            jccr.start_column = 0;
            if (dontAdd == false) {
                scv.add(jccr);
            }
        }

        Collections.sort(scv, new CompareRange());

        return scv;
    }

    /**
     * This method is not implemented.
     * @param e Cell Selection event.
     */
    @Override
    public void select(JCSelectEvent e) 
    {
        
    }

    /**
     * This method cuts the selected rows fronm the MCREW table when a right click
     * operation is done on the selected rows in the table.
     */
    public void cutRows() {
        Vector<JCCellRange> scv = getSelectedRows();
        if (scv == null) {
            JOptionPane.showMessageDialog(Util.getParentJFrame(this), "Cut position not specified",
                    "Error cutting rows", JOptionPane.ERROR_MESSAGE);
            return;
        }

        mManageData.cutRows(scv);
        jctable.clearSelection();

        int r = Integer.MAX_VALUE;
        for (JCCellRange jccr : scv) {
            r = Math.min(r, jccr.start_row);
            r = Math.min(r, jccr.end_row);
        }
        //r = r - scv.size() + 1;
        JCCellRange range = new JCCellRange(r, 0, r, jctable.getNumColumns());
        jctable.setSelectedCells(range);
    }

    /**
     * Makes the copy of selected rows on the right click mouse/keyboard copy row event of
     * the main MCREW table. If some rows are copied then then they could be reproduced and
     * inserted as it is in the table as additional rows.
     */
    public void copyRows() {
//		dumpDates("before");
        Vector<JCCellRange> scv = getSelectedRows();
        if (scv == null) {
            JOptionPane.showMessageDialog(Util.getParentJFrame(this), "Copy position not specified",
                    "Error copying rows", JOptionPane.ERROR_MESSAGE);
            return;
        }

        mManageData.copyRows(scv);

//		mVDataSource.deleteRows(startSelRow, endSelRow - startSelRow + 1);
        jctable.clearSelection();

//		dumpDates("after");
    }

    /**
     * Pastes or inserts new rows on the right click mouse/keyboard paste event in the
     * main MCREW table. If some rows are copied then those rows are replicated on paste event.
     */
    public void pasteRows() {
        if (mManageData.clipBoardRows.size() == 0) {
            JOptionPane.showMessageDialog(Util.getParentJFrame(this), "No rows on clip board",
                    "Error pasting rows", JOptionPane.ERROR_MESSAGE);
            return;
        }

        Vector<JCCellRange> scv = getSelectedRows();

        if (isOneRowSelected("paste rows")) {
            return;
        }
        JCCellRange jccr = scv.get(0);
        int rowCnt = mManageData.pasteRows(jccr.start_row);

        //Highlight the pasted rows
        JCCellRange pastedRange = new JCCellRange(jccr.start_row, 0, jccr.start_row
                + mManageData.clipBoardRows.size() - 1, jctable.getNumColumns());
        jctable.setSelectedCells(pastedRange);

//		jctable.setRowSelection(crow, crow + rowCnt - 1);
    }

    /**
     * Deletes the selected rows on the right click mouse/keyboard event from the
     * main MCREW table.
     */
    public void deleteRows() {
        Vector<JCCellRange> scv = getSelectedRows();
        if (scv == null) {
            JOptionPane.showMessageDialog(Util.getParentJFrame(this), "Delete position not specified",
                    "Error deleting rows", JOptionPane.ERROR_MESSAGE);
            return;
        }

        mManageData.deleteSelectedRows(scv);
        mcrew.setDataChanged(true);

        jctable.clearSelection();
        int r = Integer.MAX_VALUE;
        for (JCCellRange jccr : scv) {
            r = Math.min(r, jccr.start_row);
            r = Math.min(r, jccr.end_row);
        }
        //r = r - scv.size() + 1;
        JCCellRange range = new JCCellRange(r, 0, r, jctable.getNumColumns());
        jctable.setSelectedCells(range);
        checkData();
    }

    /**
     *
     */
    public void undoDeleteRows() {
        int[] rtn = mManageData.undoDeleteRows();
        Arrays.sort(rtn);
        JCCellRange range = new JCCellRange(rtn[0], 0, rtn[0] + rtn.length - 1, jctable.getNumColumns());
        jctable.setSelectedCells(range);
        mcrew.setDataChanged(true);

    }

    /**
     * This method displays the calendar and sets the appropriate calendar dates to
     * the date cells of the MCREW table.
     */
    public void calendarDates() {
        Vector<JCCellRange> scv = getSelectedRows();
        usda.weru.util.Util.debugPrint(scv.toString());

        if (scv == null || scv.size() == 0) {
            int row = jctable.getCurrentRow();
            int col = jctable.getCurrentColumn();
            JCCellRange singleCell = new JCCellRange(row, col, row, col);
            scv = new Vector<>();
            scv.add(singleCell);
        }

        int rdx = getSelectedRow();
        if (rdx == -1) {
            return;
        }
        JulianCalendar jd = null;

        if (mManageData.size() == 0 && rdx == 0) {
            jd = new JulianCalendar();
        } else if (rdx == mManageData.size()) {
            jd = new JulianCalendar();
            JulianCalendar jdsrc = mManageData.getRow(rdx - 1).getDisplayDate();
            jd.setDate(jdsrc.getDate());
        } else {
            jd = mManageData.getRow(rdx).getDisplayDate();
        }

        DisplayCalendar dc = new DisplayCalendar(Util.getParentJFrame(this), jd, "table");
        dc.setVisible(true);
        if (dc.getResult() == DisplayCalendar.OK_OPTION && dc.curDate != null) {
            if (rdx >= mManageData.size()) {
                // eg: add 0th row and theres are 0 elements
                mManageData.insertRow(rdx, new RowInfo(jd));
            }
            mManageData.changeDates(scv, dc.curDate);
            mcrew.setDataChanged(true);
        }
        checkEndCell(scv);
    }

    /**********************************************************neha***********/
    //Sets the tillage direction
    public void setDirection() {
        mcrew.setWaiting(true);
        try {
            Float tillDir = null;
            boolean correctTillFlg = false;
            boolean errorFlg = false;
            boolean cancelFlg = false;
            int row = -1;
            int col = -1;
            String newValue = null;
            Object oldValue = null;

            Vector<JCCellRange> scv = getSelectedRows();
            if (scv == null || scv.size() == 0) {
                row = jctable.getCurrentRow();
                col = jctable.getCurrentColumn();
                JCCellRange singleCell = new JCCellRange(row, col, row, col);
                scv = new Vector<>();
                scv.add(singleCell);
            }

            int rdx = getSelectedRow();
            if (rdx == -1) {
                return;
            }
            oldValue = mManageData.getTableDataItem(rdx, 3);
            newValue = JOptionPane.showInputDialog(Util.getParentJFrame(this), "Enter tillage direction", oldValue);

            if (newValue != null) {
                try {
                    tillDir = new Float(newValue);
                } catch (NumberFormatException ex) {
                    usda.weru.util.Util.debugPrint(debugFlg, " Non number entered for tillage Direction " + ex);
                }
                if ((newValue.equals("") == true) || tillDir == null) {
                    errorFlg = true;
                }
                if (tillDir != null) {
                    if (tillDir.isNaN() == true || tillDir.doubleValue() > 180.0 || tillDir.doubleValue() < -180.0) {
                        errorFlg = true;
                    }
                }
                if (errorFlg == true) {
                    String[] errorMsg = {"", "Please enter a valid Tillage direction value.",
                        "The value should be a number between -180.0 and 180.0"};
                    do {
                        Object ipValue = JOptionPane.showInputDialog(null, errorMsg, "Tillage Direction",
                                JOptionPane.QUESTION_MESSAGE, null, null, null);
                        if (ipValue == null) {
                            //user pressed Cancel option
                            cancelFlg = true;
                            //System.out.println("user pressed cancel-cancelFlg:"+cancelFlg);
                        } else {
                            try {
                                tillDir = new Float(ipValue.toString());
                            } catch (NumberFormatException ex) {
                                usda.weru.util.Util.debugPrint(debugFlg, " Non number entered for tillage Direction " + ex);
                            }
                            if ((tillDir != null && (tillDir.isNaN() == true || tillDir.doubleValue() > 180.0
                                    || tillDir.doubleValue() < -180.0)) || tillDir == null) {
                                errorMsg[0] = "The value entered in incorrect";
                                correctTillFlg = false;
                            } else {
                                correctTillFlg = true;
                            }
                        } //end of else
                        //System.out.println("cancelFlg:"+cancelFlg+"  correctTillFlg:"+correctTillFlg);

                    } while (correctTillFlg == false && cancelFlg == false);
                } //end of inner if errorFlg is true

                if (correctTillFlg == true && cancelFlg == false) {
                    newValue = tillDir.toString();
                }

                if (rdx >= mManageData.size()) {
                    // eg: add 0th row and theres are 0 elements
                    mManageData.insertRow(rdx);
                }

                if (cancelFlg == false) {
                    usda.weru.util.Util.debugPrint(debugFlg, "The new changed VALUE is -:-:-" + newValue);
                    for (JCCellRange jccr : scv) {
                        int sRow = jccr.start_row;
                        int eRow = jccr.end_row;

                        if (sRow > eRow) {
                            int pivot = sRow;
                            sRow = eRow;
                            eRow = pivot;
                        }

                        for (rdx = sRow; rdx <= eRow; rdx++) {
                            mManageData.setColumnValue(rdx, MCREWConfig.getObjectName(3),
                                    MCREWConfig.getTagName(3), newValue);
                        }
                        //   usda.weru.util.Util.debugPrint(debugFlg, "ROW is :  " + rdx + " "
                        //   + "Object Name : " + ConfigData.getObjectName(3) + " Tag Name : " + ConfigData.getTagName(3));
                    }

                    mcrew.setDataChanged(true);

                } //end of if(cancelFlg is false)

            } //end of if (newValue != null)
        } finally {
            mcrew.setWaiting(false);
        }

    } //end of setDirection()

    /**********************************************************neha***********/
    public void adjustDirection() {
        mcrew.setWaiting(true);
        try {
            String oldValue = null;
            String newValue = null;
            float tillDir = 0;
            int rdx = -1;

            Vector<JCCellRange> scv = getSelectedRows();
            if (scv == null) {
                JOptionPane.showMessageDialog(Util.getParentJFrame(this), "No row(s) selected to change",
                        "Error changing Tillage direction", JOptionPane.ERROR_MESSAGE);
                return;
            }

            TillageChange tc = new TillageChange(Util.getParentJFrame(this), true);
            tc.setVisible(true);

            if (tc.delta != 0) {
                for (JCCellRange jccr : scv) {
                    int sRow = jccr.start_row;
                    int eRow = jccr.end_row;

                    if (sRow > eRow) {
                        int pivot = sRow;
                        sRow = eRow;
                        eRow = pivot;
                    }

                    //   //System.out.println("sRow:"+sRow+" eRow:"+eRow);
                    for (rdx = sRow; rdx <= eRow; rdx++) {
                        oldValue = mManageData.getColumnValueAsString(rdx,
                                MCREWConfig.getObjectName(3), MCREWConfig.getTagName(3));
                        if (oldValue != null && !"".equals(oldValue)) {
                            try {
                                tillDir = new Float(oldValue).floatValue();
                            } catch (NumberFormatException ex) {
                                JOptionPane.showMessageDialog(this, "Number format Exception" + oldValue,
                                        "Error converting number", JOptionPane.ERROR_MESSAGE);
                                usda.weru.util.Util.debugPrint(debugFlg, " Non number entered for tillage Direction " + ex);
                                return;
                            }
                            //add the new value of increment or decrement to the old value
                            tillDir = tillDir + (float) tc.delta;
                            newValue = Float.toString(tillDir);
                            //System.out.println("newValue:"+newValue);
                            mManageData.setColumnValue(rdx, MCREWConfig.getObjectName(3), MCREWConfig.getTagName(3), newValue);
                            usda.weru.util.Util.debugPrint(debugFlg, "ROW is :  " + rdx + " "
                                    + "Object Name : " + MCREWConfig.getObjectName(3)
                                    + " Tag Name : " + MCREWConfig.getTagName(3));
                        } //end of if oldValue != null and empty string

                    } //end of for loop
                }

                mcrew.setDataChanged(true);

            } //end of if(tc.delta != 0)
        } finally {
            mcrew.setWaiting(false);
        }

    }

    /**
     * It is used to set the tillage direction to 0, 45 or 90 degrees.
     * @param tillValue The direction in degrees like 0, 45, 90, etc.
     */
    public void setAbsoluteDirection(int tillValue) {
        mcrew.setWaiting(true);
        try {
            Integer intTillValue = tillValue;
            int row = -1;
            int col = -1;
            String newValue = null;

            Vector<JCCellRange> scv = getSelectedRows();
            if (scv == null || scv.isEmpty()) {
                row = jctable.getCurrentRow();
                col = jctable.getCurrentColumn();
                JCCellRange singleCell = new JCCellRange(row, col, row, col);
                scv = new Vector<>();
                scv.add(singleCell);
            }

            int rdx = getSelectedRow();
            if (rdx == -1) {
                return;
            }
            //Convert the integer value to string
            newValue = intTillValue.toString();

            if (rdx >= mManageData.size()) {
                // eg: add 0th row and theres are 0 elements
                mManageData.insertRow(rdx);
            }

            usda.weru.util.Util.debugPrint(debugFlg, "The new changed VALUE is -:-:-" + newValue);
            for (JCCellRange jccr : scv) {
                int sRow = jccr.start_row;
                int eRow = jccr.end_row;
                if (sRow > eRow) {
                    int pivot = sRow;
                    sRow = eRow;
                    eRow = pivot;
                }
                //	//System.out.println("sRow:"+sRow+"  eRow:"+eRow);
                for (rdx = sRow; rdx <= eRow; rdx++) {
                    usda.weru.util.Util.debugPrint(debugFlg, "ROW is :  " + rdx + " " + "Object Name : "
                            + MCREWConfig.getObjectName(3) + " Tag Name : " + MCREWConfig.getTagName(3));
                    mManageData.setColumnValue(rdx, MCREWConfig.getObjectName(3), MCREWConfig.getTagName(3), newValue);
                }
                //     usda.weru.util.Util.debugPrint(debugFlg, "ROW is :  " + rdx + " " + "Object Name : "
                //     + ConfigData.getObjectName(3) + " Tag Name : " + ConfigData.getTagName(3));
            }

            mcrew.setDataChanged(true);
        } finally {
            mcrew.setWaiting(false);
        }

    } //end of setAbsoluteDirection() method

    /**
     * This method is used to increment or decrement the tillage directions.
     * @param incrDecrValue The value by which this tillage direction should be incremented or
     * decremented.
     */
    public void incrDecrDir(int incrDecrValue) {
        mcrew.setWaiting(true);
        try {
            String oldValue = null;
            String newValue = null;
            float tillDir = 0;
            int rdx = -1;

            Vector<JCCellRange> scv = getSelectedRows();
            if (scv == null) {
                JOptionPane.showMessageDialog(Util.getParentJFrame(this), "No row(s) selected to change",
                        "Error changing Tillage direction", JOptionPane.ERROR_MESSAGE);
                return;
            }

            for (JCCellRange jccr : scv) {
                int sRow = jccr.start_row;
                int eRow = jccr.end_row;
                if (sRow > eRow) {
                    int pivot = sRow;
                    sRow = eRow;
                    eRow = pivot;
                }
                for (rdx = sRow; rdx <= eRow; rdx++) {
                    oldValue = mManageData.getColumnValueAsString(rdx, MCREWConfig.getObjectName(3), MCREWConfig.getTagName(3));
                    if (oldValue != null && !"".equals(oldValue)) {
                        try {
                            tillDir = new Float(oldValue).floatValue();
                        } catch (NumberFormatException ex) {
                            JOptionPane.showMessageDialog(this, "Number format Exception" + oldValue,
                                    "Error converting number", JOptionPane.ERROR_MESSAGE);
                            usda.weru.util.Util.debugPrint(debugFlg, " Non number entered for tillage Direction " + ex);
                            return;
                        }
                        //add the new value of increment or decrement to the old value
                        tillDir = tillDir + (float) incrDecrValue;
                        newValue = Float.toString(tillDir);
                        //System.out.println("newValue:"+newValue);
                        mManageData.setColumnValue(rdx, MCREWConfig.getObjectName(3), MCREWConfig.getTagName(3), newValue);
                        usda.weru.util.Util.debugPrint(debugFlg, "ROW is :  " + rdx + " "
                                + "Object Name : " + MCREWConfig.getObjectName(3) + " Tag Name : " + MCREWConfig.getTagName(3));
                    } //end of if oldValue != null and empty string

                } //end if for loop on selections
            }

            mcrew.setDataChanged(true);
        } finally {
            mcrew.setWaiting(false);
        }
    } //end of incrDecrDir() method

    /**********************************************************neha***********/
    public void changeBy90() {
        mcrew.setWaiting(true);
        try {
            String oldValue = null;
            String newValue = null;
            float tillDir = 0;
            int rdx = -1;

            Vector<JCCellRange> scv = getSelectedRows();
            if (scv == null) {
                JOptionPane.showMessageDialog(Util.getParentJFrame(this), "No row(s) selected to change",
                        "Error changing Tillage direction", JOptionPane.ERROR_MESSAGE);
                return;
            }

            for (JCCellRange jccr : scv) {
                int sRow = jccr.start_row;
                int eRow = jccr.end_row;
                if (sRow > eRow) {
                    int pivot = sRow;
                    sRow = eRow;
                    eRow = pivot;
                }
                for (rdx = sRow; rdx <= eRow; rdx++) {
                    oldValue = mManageData.getColumnValueAsString(rdx, MCREWConfig.getObjectName(3), MCREWConfig.getTagName(3));
                    if (oldValue != null && !"".equals(oldValue)) {
                        try {
                            tillDir = new Float(oldValue).floatValue();
                        } catch (NumberFormatException ex) {
                            JOptionPane.showMessageDialog(this, "Number format Exception"
                                    + oldValue, "Error converting number", JOptionPane.ERROR_MESSAGE);
                            usda.weru.util.Util.debugPrint(debugFlg, " Non number entered for tillage Direction " + ex);
                            return;
                        }
                        //add 90 to oldValue; If its greater than 90, then decrement 90 from it
                        //and if its less than 0, then add 90 to it
                        if (tillDir > 0) {
                            tillDir = tillDir - 90;
                        } else {
                            tillDir = tillDir + 90;
                        }
                        newValue = new Float(tillDir).toString();
                        //System.out.println("newValue:"+newValue);
                        mManageData.setColumnValue(rdx, MCREWConfig.getObjectName(3), MCREWConfig.getTagName(3), newValue);
                        usda.weru.util.Util.debugPrint(debugFlg, "ROW is :  " + rdx + " "
                                + "Object Name : " + MCREWConfig.getObjectName(3)
                                + " Tag Name : " + MCREWConfig.getTagName(3));
                    } //end of if oldValue != null and empty string

                }
            }

            mcrew.setDataChanged(true);
        } finally {
            mcrew.setWaiting(false);
        }

    }

    /**********************************************************neha***********/
    public void setDates() {
        Vector<JCCellRange> scv = getSelectedRows();
        if (scv == null || scv.size() == 0) {
            int row = jctable.getCurrentRow();
            int col = jctable.getCurrentColumn();
            JCCellRange singleCell = new JCCellRange(row, col, row, col);
            scv = new Vector<>();
            scv.add(singleCell);
        }

        int rdx = getSelectedRow();
        JulianCalendar jd = null;

        if (mManageData.size() == 0 && rdx == 0) {
            jd = new JulianCalendar();
        } else if (rdx == mManageData.size()) {
            jd = new JulianCalendar();
            JulianCalendar jdsrc = mManageData.getRow(rdx - 1).getDisplayDate();
            jd.setDate(jdsrc.getDate());
        } else {
            jd = mManageData.getRow(rdx).getDisplayDate();
        }

        JulianCalendar old = (JulianCalendar) jd.clone();
        String formatString = MCREWConfig.getOperationDateFormat();
        int monthIndex = formatString.indexOf("M");
        int dayIndex = formatString.indexOf("d");
        int yearIndex = formatString.indexOf("y");
        if (dayIndex == 0) {
            formatString = "dd/MM/yy";
        } else if (monthIndex == 0) {
            formatString = "MM/dd/yy";
        } else if (yearIndex == 0) {
            formatString = "yy/MM/dd";
        }

        SimpleDateFormat format = new SimpleDateFormat(formatString);
        Calendar cal = Calendar.getInstance();
        cal.clear();
        cal.set(0, 0, 1);
        format.set2DigitYearStart(cal.getTime());
        String current = format.format(jd.getTime());

        String julDat = JOptionPane.showInputDialog(Util.getParentJFrame(this),
                "Enter new date - format: " + formatString, current);

        if (julDat != null) {
            try {
                Date date = format.parse(julDat);
                jd.setTime(date);
                jd.set(Calendar.ERA, GregorianCalendar.AD);
                if (jd.get(Calendar.YEAR) < 1 || jd.get(Calendar.YEAR) > 99) {
                    throw new IllegalStateException();
                }
                if (rdx >= mManageData.size()) {
                    // eg: add 0th row and theres are 0 elements
                    mManageData.insertRow(rdx, new RowInfo(jd));
                }
                mManageData.changeDates(scv, jd);
            } catch (ParseException f) {
                LOGGER.debug("Unable to parse date: " + julDat);
                JOptionPane.showMessageDialog(Util.getParentJFrame(this),
                        f, "Invalid date format", JOptionPane.ERROR_MESSAGE);
                jd.setDate(old.getDate());
            } catch (IllegalArgumentException f) {
                LOGGER.debug("Unable to parse date: " + julDat);
                JOptionPane.showMessageDialog(Util.getParentJFrame(this),
                        f, "Invalid date format", JOptionPane.ERROR_MESSAGE);
                jd.setDate(old.getDate());
            } catch (IllegalStateException e) {
                JOptionPane.showMessageDialog(Util.getParentJFrame(this),
                        "Invalid rotation year: " + jd.get(Calendar.YEAR) + "\nMinimum: 1\nMaximum: 99",
                        "Invalid date", JOptionPane.ERROR_MESSAGE);
                jd.setDate(old.getDate());
            }
        }
        mcrew.setDataChanged(true);
        checkEndCell(scv);
    }

    /**
     * Changes and assignes the new date present in the date cell of the MCREW table.
     */
    public void changeDates() {
        Vector<JCCellRange> scv = getSelectedRows();
        if (scv == null) {
            JOptionPane.showMessageDialog(Util.getParentJFrame(this),
                    "No row(s) selected to change", "Error changing dates", JOptionPane.ERROR_MESSAGE);
            return;
        }

        DateChange dc = new DateChange(Util.getParentJFrame(this));
        dc.setVisible(true);
        mManageData.changeDates(scv, dc);
        mcrew.setDataChanged(true);
        checkEndCell(scv);

    }

    /**
     * Changes and assignes the new date as value in the date field of the MCREW table.
     * @param field The field to which the new date needs to be assigned.
     * @param value The date value to be assigned to the field.
     */
    public void changeDates(int field, int value) {
        Vector<JCCellRange> scv = getSelectedRows();
        if (scv == null) {
            /* Since, changing date values is not a row operation, the operation can be contiued even if the user has not
             * selected any row(s). This is done by getting current row/ current col and then creating JCCellRange using those
             *
             */
            int row = jctable.getCurrentRow();
            int col = jctable.getCurrentColumn();
            JCCellRange singleCell = new JCCellRange(row, col, row, col);
            scv = new Vector<>();
            scv.add(singleCell);
            /*
             *JOptionPane.showMessageDialog(Util.getParentJFrame(this),
             "No row(s) selected to change",
             "Error changing dates",
             JOptionPane.ERROR_MESSAGE);
             return;
             */
        }

        if (mManageData.changeDates(scv, field, value)) {
            mcrew.setDataChanged(true);
            checkEndCell(scv);
        }
    }

    /**
     * Sorts the rows in ascending or descending order of dates in the MCREW table.
     */
    public void sortData() {
        mManageData.sortData();
    }

    /**
     * Inserts an empty row at a specified place or after the last row in the MCREW table
     * with default date inserted in the date column of that row.
     */
    public void insertRow() {
        Vector<JCCellRange> scv = getSelectedRows();

        if (isOneRowSelected("Insert Row")) {
            return;
        }

        int sRow = 0;
        try {
            sRow = scv.get(0).start_row;
        } catch (java.lang.ArrayIndexOutOfBoundsException aioobe) {
            sRow = jctable.getCurrentRow();
        }
        mManageData.insertRow(sRow);
    }

    /**
     * Cycles forward method takes the crop rotation cycle ahead by the number of years
     * specified in the argument.
     * @param rotYears The number of year by whichto cycle forward
     */
    public void cycleForward(int rotYears) {
        mManageData.cycleForward(rotYears);
    }

    /**
     * Cycles backward method takes the crop rotation cycle back by the number of years
     * specified in the argument.
     * @param rotYears The number of year by which to cycle backwards.
     */
    public void cycleBackward(int rotYears) {
        mManageData.cycleBackward(rotYears);
    }

    /**
     * Makes sure if only one row is selected in the table when the selection is
     * done on any row to pull the correct right-click menu options on each right-click
     * mouse event.
     * @param insertType Specifies where the new row if needed to be inserted should go
     * i:e after which row.
     * @return True if only one row is selected else false.
     */
    public boolean isOneRowSelected(String insertType) {
        Vector<JCCellRange> scv = getSelectedRows();
        if (scv == null) {
            JOptionPane.showMessageDialog(Util.getParentJFrame(this),
                    "Insert position not specified",
                    "Error: " + insertType, JOptionPane.ERROR_MESSAGE);
            return true;
//	  } else if (scv.size() > 1) {
//		  JOptionPane.showMessageDialog(Util.getParentJFrame(this),
//										"Multi-range selection not allowed for " + insertType,
//										"Error: " + insertType,
//										JOptionPane.ERROR_MESSAGE);
//		  return true;
        } else if (scv.size() < 1) {
            JOptionPane.showMessageDialog(Util.getParentJFrame(this),
                    "Insert position not specified - internal error",
                    "Error: " + insertType, JOptionPane.ERROR_MESSAGE);
            return true;
        } else {
            JCCellRange jccr = scv.get(0);
            if (jccr.start_row != jccr.end_row) {
                JOptionPane.showMessageDialog(Util.getParentJFrame(this),
                        "Multi-range selection not allowed for " + insertType,
                        "Error: " + insertType, JOptionPane.ERROR_MESSAGE);
                return true;
            }
        }
        {
        }
        return false;
    }

    /**
     * Insert the data from a new management file into the present data set
     * @param pInsertData The data object which needs to be populated with the new data from
     * management file.
     * @param adjustDates
     * @param magicAdjustInsertRow
     */
    public void insertFile(ManageData pInsertData, boolean adjustDates, boolean magicAdjustInsertRow) {

        if(mManageData.IntView())
        {
            insertRot(pInsertData);
            return;
        }
        int sRow;

        //if it's the blank row and adjust row is true, move the row to the first op after a harvest
        if (magicAdjustInsertRow) {
            //start at empty row
            sRow = mManageData.size();
            //find the last harvest

            for (int i = sRow - 1; i >= 0; i--) {
                CropIntervalInfo cii = mManageData.getCropIntervalInfo(i);
                if(cii.getEnd() + 1 == sRow) sRow = cii.getStart();
                else sRow = cii.getStart() > cii.getEnd() ? cii.getStart() : cii.getEnd() + 1;
            }
        } else {
            // would overwrite any changes made in the date cell editor with the value in the data
            List<JCCellRange> scv = getSelectedRows();
            if (scv == null || scv.isEmpty()) {
                sRow = jctable.getCurrentRow();
            } else {
                sRow = scv.get(0).start_row;
            }
        }

        //adjust the dates
        if (adjustDates) {
            JulianCalendar beforeDate = mManageData.getDisplayDate(sRow - 1);
            JulianCalendar importDate = pInsertData.getDisplayDate(0);
            int years = 0;
            while (beforeDate != null && importDate.before(beforeDate)) {
                pInsertData.changeDates(0, pInsertData.getRows().size() - 1, Calendar.YEAR, 1);
                importDate = pInsertData.getDisplayDate(0);
                years++;
            }

            importDate = pInsertData.getDisplayDate(pInsertData.getRows().size() - 1);
            mManageData.changeDates(sRow, mManageData.getRows().size() - 1, Calendar.YEAR, years);
        }

        mManageData.insertRows(sRow, pInsertData.getRows());
        mcrew.setDataChanged(true);

        JCCellRange range = new JCCellRange(sRow, 0, sRow + pInsertData.getRows().size() - 1, jctable.getNumColumns());
        jctable.setSelectedCells(range);
    }
    
    /**
     * The method that will handle the insertion of the specified management file
     * in the table, changing the value of the rotation years field.  
     * @param insertData 
     */
    public void insertRot(ManageData insertData)
    {
        //Make sure the dates we see are the actual dates.
        for(RowInfo row : mManageData.getRows()) row.synchDates();
        int sRow = 0;
        List<JCCellRange> scv = getSelectedRows();
        if (scv == null || scv.isEmpty()) sRow = jctable.getCurrentRow(); 
        else sRow = scv.get(0).start_row;
        //What row is the top of the selection?  We will insert above that row.
        JulianCalendar previous = mManageData.getDisplayDate(sRow == 0 ? mManageData.size() - 1 :  sRow - 1);
        JulianCalendar current = mManageData.getDisplayDate(sRow == mManageData.size() ? 0 : sRow);
        JulianCalendar first = insertData.getDate(0);
        JulianCalendar last = insertData.getDate(insertData.size() - 1);
        boolean sameYear = mManageData.getDate(sRow == 0 ? mManageData.size() - 1 :  sRow - 1)
                .get(Calendar.YEAR) == mManageData.getDate(sRow == mManageData.size() ? 0 : sRow).get(Calendar.YEAR);
        //Can we overlap the year at the beginning of the join?
        boolean beginOver = dayMonthAfter(previous, first);
        //Can we overlap the year at the end of the join?
        boolean endOver = dayMonthAfter(last, current);
        boolean inPivot = mManageData.inRotatedArea(sRow == mManageData.size() ? 0 : sRow);
        boolean atStart = sRow == 0;
        //How many years do we have to increment rows in our insertion by?
        int insertInc = 0;
        //How many years do we have to increment rows after our insertion by?
        int afterInc = 0;
        //If we've selected row zero, we don't need to increment our inserted file.
        if(sRow != 0) insertInc = previous.get(Calendar.YEAR) - (beginOver ? 1 : 0);
        afterInc = last.get(Calendar.YEAR) - (endOver ? 1 : 0);
        int newYears = mManageData.kRotationYears;
        newYears += insertData.kRotationYears;
        newYears -= (beginOver ? 1 : 0) + (endOver ? 1 : 0);
        newYears += sameYear ? 1 : 0;
        if(inPivot)
        {
            int setYear = endOver ? current.get(Calendar.YEAR) + afterInc: 
                    current.get(Calendar.YEAR) + afterInc - 1;
            int curYear = insertData.getDate(insertData.size() - 1).get(Calendar.YEAR);
            boolean wrapping = true;
            for(int index = insertData.size() - 1; index >= 0; index --)
            {
                if(insertData.getDate(index).get(Calendar.YEAR) != curYear)
                {
                    curYear = insertData.getDate(index).get(Calendar.YEAR);
                    setYear = setYear == 1 ? newYears : setYear - 1;
                    if(setYear == newYears) wrapping = false;
                }
                insertData.getDisplayDate(index).set(Calendar.YEAR, setYear);    
                if(wrapping) insertData.getRow(index).setYearOffset(newYears);
                insertData.getRow(index).resynchDates();
            }
            curYear = beginOver ? mManageData.getDate(sRow - 1).
                    get(Calendar.YEAR) : 0;
            int index = sRow - 1; 
            while(mManageData.inRotatedArea(index))
            {
                if(mManageData.getDate(index).get(Calendar.YEAR) != curYear)
                {
                    curYear = mManageData.getDate(index).get(Calendar.YEAR);
                    setYear = setYear == 1 ? newYears : setYear - 1;
                }
                mManageData.getDate(index).set(Calendar.YEAR, setYear);       
                mManageData.getRow(index).enforceActualDate();
                index --;
            }
        }
        else 
        {
            for(RowInfo row : insertData.getRows()) 
            {
                row.getDate().set(Calendar.YEAR,  row.getDate().get(Calendar.YEAR) 
                        + insertInc);
                row.synchDates();
            }
        }
        if(atStart)
        {
            //If we are inserting the file at the start, this file makes the new pivot.
            for(int index = 0; index < mManageData.size(); index ++)
            {
                mManageData.getDisplayDate(index).set(
                        Calendar.YEAR, mManageData.getDisplayDate(index).get(Calendar.YEAR) + afterInc);
                mManageData.getRow(index).enforceDisplayDate();
            }
        }
        else
        {
            for(int index = sRow; index < mManageData.size(); index ++)
            {
                if(!mManageData.inRotatedArea(index)) 
                {
                    mManageData.getDate(index).set(
                        Calendar.YEAR, mManageData.getDate(index).get(Calendar.YEAR) + afterInc + (sameYear ? 1: 0));
                    mManageData.getRow(index).enforceActualDate();
                }
                else 
                {
                    mManageData.getRow(index).setYearOffset(newYears);
                }
                mManageData.getRow(index).synchDates();
            }
        }
        mManageData.insertRows(sRow, insertData.getRows());
        mcrew.setDataChanged(true);
        
        mManageData.setRotationYears(newYears);
        mcrew.setRotText(Integer.toString(newYears));

        JCCellRange range = new JCCellRange(sRow, 0, sRow + insertData.getRows().size() - 1, jctable.getNumColumns());
        jctable.setSelectedCells(range);
    }
    
    /**
     * Returns true if the first's date is after the second, ignoring the value
     * in the years filed.
     * @param first
     * @param second
     * @return 
     */
    public boolean dayMonthAfter(JulianCalendar first, JulianCalendar second)
    {
        if(first.get(Calendar.MONTH) < second.get(Calendar.MONTH)) return true;
        else if(first.get(Calendar.MONTH) == second.get(Calendar.MONTH))
        {
            if(first.get(Calendar.DATE) <= second.get(Calendar.DATE)) return true;
            else return false;
        }
        else return false;
    }

    /**
     * Returns the row currently selected in the table.
     * @return 
     */
    private int getSelectedRow() {
        Vector<JCCellRange> srv = getSelectedRows();
        if (srv == null || srv.size() == 0) {
            return -1;
        }
        JCCellRange scr = srv.get(0);
        return scr.start_row;
    }

    /**
     * Displays the appropriate drill down screen i.e based upon the data in the column (from operation or crop),
     * this function displays the OperationDlg otr cropDlg
     */
    public void showDrillDownScreen() {
        int rowId = 0;
        int colId = 0;

        //	Vector srv = getSelectedRows();
        //	if (srv == null) return;
        //	JCCellRange scr = (JCCellRange) srv.get(0);
        //	colId = scr.start_column;
        rowId = getSelectedRow();
        if (rowId == -1) {
            System.out.println("Reject");
            return;
            //System.out.println("T_xx: " + rowId);
        }
        colId = jctable.getCurrentColumn();
        //	rowId = jctable.getCurrentRow();
        // would overwrite any changes made in the date cell editor with the value in the data
        String colObjName = MCREWConfig.getObjectName(colId);

        OperationObject obj = (OperationObject) mManageData.getDataObject(rowId, XMLConstants.soperation);
        if (obj == null) {
            return;
        }

        if (colObjName.equals(XMLConstants.scrop)) {
            //JOptionPane.showMessageDialog(this, "Sorry, Drill down screen for crops not implemented yet");
            String cropName = obj.getCropName();
            ////System.out.println("Table : sDDS - BEFORE object creation cropObj ");
            CropObject cropObj = obj.getCrop();
            ////System.out.println("Table : sDDS - AFTER object creation cropObj ");
            if (cropObj == null) {
                JOptionPane.showMessageDialog(Util.getParentJFrame(this),
                        "Sorry, No crops in this row", "Error displaying drill down screen",
                        JOptionPane.ERROR_MESSAGE);
                return;
            }

            CropDlg cropDlg = new CropDlg(this, cropName, cropObj,
                    mManageData, mManageData.getRows().get(rowId), mcrew);
            ////System.out.println("Table : sDDS - after object creation cropDlg which is : " + cropDlg);
            //For the Crop Notes Dialog to get focus, cropDlg should NOT be modal - neha
            cropDlg.setModal(true);
            cropDlg.setVisible(true);

        } else if (colObjName.equals(XMLConstants.soperation)) {
            String dateStr = " No date set";
            JulianCalendar cal = mManageData.getDisplayDate(rowId);
            if (cal != null) {
                SimpleDateFormat dateFormat;
                try {
                    String format = MCREWConfig.getOperationDateFormat();
                    dateFormat = new SimpleDateFormat(format);
                } catch (Exception e) {
                    dateFormat = new SimpleDateFormat("MMM dd, y");
                }
                dateStr = dateFormat.format(cal.getTime());
            }

            OperationDlg operationDlg = new OperationDlg(this,
                    obj, dateStr, mManageData, mManageData.getRows().get(rowId));
            operationDlg.setModal(true);
            operationDlg.setVisible(true);
        }

    }

    /** Puts new data into the column - Called upon double click
     * TEMPORARY SOLUTION - for adding new column data
     * @return 
     */
    public boolean addColumnData() {
        return addColumnData(-1);
    }

    /**
     * For documentation's sake, this is the method that is called on a double click to 
     * bring up the file or date chooser.
     * @param col
     * @return
     */
    public boolean addColumnData(int col) {
        jctable.commitEdit(true);
        Vector<JCCellRange> v = getSelectedRows();
        JCCellRange range = v.firstElement();
        boolean multiRow = false;
        if (range.start_row != range.end_row || v.size() > 1) {
            multiRow = true;
        }
        int row = getSelectedRow();
        if (row == -1) {
            return false;
        }
        if(col == -1) return false;
        LOGGER.info("cell: (" + row + ", " + col + ")");

        String name = MCREWConfig.getColumnNames().get(col);
        if (name.equals("date")) {
            if(!multiRow)
            {
                calendarDates();
                return true;
            }
            else return false;
        }
        if (!(name.equals("gcropname") || name.equals("operationname"))) {
            return false;
        }
        setCursor(new Cursor(Cursor.WAIT_CURSOR));

        String newObjectName = MCREWConfig.getObjectName(col);

        if (newObjectName.equals(XMLConstants.sdate)) {
            if(!multiRow)
            {
                calendarDates();
                setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                return true;
            }
            else return false;
        } else if (!newObjectName.equals(XMLConstants.soperation)) {
            //check if this operation has the values for the object objectName (theres only crop now)
            OperationObject oprnObj = (OperationObject) mManageData.getDataObject(row, XMLConstants.soperation);
            if (oprnObj == null) {
                // No Operation yet in this row
                setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                return false;
            }
            if (newObjectName.equals(XMLConstants.scrop)) {
                if (!(oprnObj.hasCrop())) {
                    //cant' add crops to no crop operation
                    setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                    return false;
                }
            }
        }

        String fileExtension = MCREWConfig.getFileExtension(newObjectName);

        TFile dir = new de.schlichtherle.truezip.file.TFile(MCREWConfig.getDirectoryName(newObjectName));
        String dirPath = dir.getAbsolutePath();
        WepsFileChooser chooser = new WepsFileChooser(
                WepsFileChooser.getType(fileExtension), dirPath, WepsFileChooser.SELECT);
        chooser.setCurrentDirectory(dir);
        //to hide the 'New Folder' button in the File Chooser Dialog
        chooser.disableNewFolder(chooser);
        //to set the tool tip of the Home Button to "Home" instead of "Desktop"
        chooser.homeToolTip(chooser);

        int result = chooser.showDialog(null);
        if (result == JFileChooser.APPROVE_OPTION) {
            TFile file = new TFile(chooser.getSelectedFile());
            String filePath = file.getAbsolutePath();
            String objectName = MCREWConfig.getObjectName(col);

            LOGGER.debug("cell: (" + row + ", " + col + ") = " + objectName);
            for(JCCellRange rowRange : v)
            {
                for(int index = rowRange.start_row; index <= rowRange.end_row; index ++)
                {
                    mManageData.readDataObject(index, objectName, filePath);
                }
            }
            checkData();
        } else {
            setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            return false;
        }
        setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
        return true;
    }

    /**
     *
     * @param file
     * @return
     */
    public boolean addColumnData(TFile file) {
        jctable.commitEdit(true);
        int row = getSelectedRow();
        if (row == -1) {
            return false;
        }
        int col = jctable.getCurrentColumn();

        LOGGER.info("cell: (" + row + ", " + col + ")");

        setCursor(new Cursor(Cursor.WAIT_CURSOR));

        String newObjectName = MCREWConfig.getObjectName(col);

        if (newObjectName.equals(XMLConstants.sdate)) {
            calendarDates();
            setCursor(new Cursor(Cursor.DEFAULT_CURSOR));

            return true;
        } else if (!newObjectName.equals(XMLConstants.soperation)) {
            //check if this operation has the values for the object objectName (theres only crop now)
            OperationObject oprnObj = (OperationObject) mManageData.getDataObject(row, XMLConstants.soperation);
            if (oprnObj == null) {
                // No Operation yet in this row
                setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                return false;
            }
            if (newObjectName.equals(XMLConstants.scrop)) {
                if (!(oprnObj.hasCrop())) {
                    //cant' add crops to no crop operation
                    setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                    return false;
                }
            }
        }

        String filePath = file.getAbsolutePath();
        String objectName = MCREWConfig.getObjectName(col);

        LOGGER.debug("cell: (" + row + ", " + col + ") = " + filePath);
        mManageData.readDataObject(row, objectName, filePath);
        checkData();

        setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
        return true;
    }
    private int tw = 600;

    /**
     * This method gets the preferred size i:e the width and height of the table used
     * for displaying the data when instantiated through the application.
     * @return The dimention object that stores the details of the table GUI like
     * width, height, etc.
     */
    @Override
    public Dimension getPreferredSize() {
        Dimension d = jctable.getPreferredSize();
        tw += 20;
        d.width = tw;
        Dimension p = getParent().getParent().getSize();
        if (p.width > 20) {
            d.width = p.width - 20;
        }
        if (d.height > 20) {
            d.height = p.height - 70;
        }
        return d;
    }

    /**
     * Gets the details of the maximium allowable sizes in terms of width, height, etc
     * for the table to be used for displayin the MCREW data. It could be used for
     * operation and crop dialog also if needed but currently is used
     * @return The dimension object that stores the values for these table properties.
     */
    @Override
    public Dimension getMaximumSize() {
        Dimension d = jctable.getMaximumSize();
        return d;
    }

    /**
     * Gets the details of the minimum permissible sizes in terms of width, height, etc
     * for the table to be used for displayin the MCREW data. It could be used for
     * operation and crop dialog also if needed but currently is used
     * @return The dimension object that stores the values for these table properties.
     */
    @Override
    public Dimension getMinimumSize() {
        Dimension d = new Dimension(300, 25);
        d.width = getParent().getSize().width - 40;
        return d;
    }

    /**
     *  Returns the table object that makes the data visible on main screen.
     * @return The table object responsoble got making the data viewable on main MCREW
     * screen.
     */
    public JCTable getJCTable() {
        return jctable;
    }

    class MyMouseAdapter extends MouseAdapter {

        private Table myTable = null;
        public int lastRow;

        /*
         * @param       (classes, interfaces, methods and constructors only)
         * @return      (methods only)
         * @exception   (@throws is a synonym added in Javadoc 1.2)
         * @author      (classes and interfaces only, required)
         * @version     (classes and interfaces only, required. See footnote 1)
         * @see
         * @since
         * @serial      (or @serialField or @serialData)
         * @deprecated  (see How and When To Deprecate APIs)
         */
        public MyMouseAdapter(Table myTable) {
            this.myTable = myTable;
        }

        public MouseEvent translateEvent(MouseEvent me) {
            int x = me.getXOnScreen() - Table.this.getLocationOnScreen().x;
            int y = me.getYOnScreen() - Table.this.getLocationOnScreen().y;

            MouseEvent newMe = new MouseEvent(Table.this, me.getID(), me.getWhen(),
                    me.getModifiers(), x, y, me.getClickCount(), true, me.getButton());

            return newMe;
        }
        
        boolean prev = false;
        
        public void selectRow()
        {
            jctable.setSelection(lastRow, 0, lastRow, jctable.getNumColumns() - 1);
        }

        /*
         * @param       (classes, interfaces, methods and constructors only)
         * @return      (methods only)
         * @exception   (@throws is a synonym added in Javadoc 1.2)
         * @author      (classes and interfaces only, required)
         * @version     (classes and interfaces only, required. See footnote 1)
         * @see
         * @since
         * @serial      (or @serialField or @serialData)
         * @deprecated  (see How and When To Deprecate APIs)
         */
        @Override
        public void mouseClicked(MouseEvent e) {
            //System.out.println("T_mC: mouse clicked " + cnt++);
            myTable.mouseFlg = e.getModifiers() != InputEvent.BUTTON1_MASK;
            usda.weru.util.Util.debugPrint(debugFlg, myTable.mouseFlg
                    + "Manmohan HERE in TABLE MyMouseAdapter " + e.getButton());
            if(arrayEditor != null) arrayEditor.hidePopup();
            MouseEvent toDecomp = translateEvent(e);
            JCCellPosition cellLoc = this.myTable.jctable.XYToCell(toDecomp.getX(), toDecomp.getY());
            int X = cellLoc.row;
            int Y = cellLoc.column;
            lastRow = X;
            
            if (e.getModifiers() == InputEvent.BUTTON1_MASK && e.getClickCount() > 1) {
                /* Left double click */

                //Get the cell associated with the mouse event
                
                if((X == -1)) return;
                if(Y == -1)  
                {
                    if(jctable.getDataSource() instanceof ManageData)
                    {
                        ((ManageData) jctable.getDataSource()).setPivot(X);
                        mcrew.setDataChanged(true);
                        myTable.refreshVisibleColumns();
                        return;
                    }
                }
                if(Y < 3)
                {
                    addColumnData(Y);
                }
                else if(Y == 3)
                {
                    setDirection();
                }
//                System.out.println("This is left double click.  (" + X + ", " + Y + ")");
                Rectangle tableRect = jctable.getBounds();
                ////System.out.println("MouseAdpater " + tableRect + "click point = " + e.getPoint());
                if (tableRect.contains(e.getPoint()) && getSelectedRow() != JCTableEnum.LABEL) {
                    // XXX //Does'nt work
                    addColumnData();
                }
            } else {
                usda.weru.util.Util.debugPrint(debugFlg, "consume");
            }
            mcrew.getCoordinator().dateChange(this);
        }

        public void openDrillDownScreen() {
            showDrillDownScreen();
        }

        /*
         * @param       (classes, interfaces, methods and constructors only)
         * @return      (methods only)
         * @exception   (@throws is a synonym added in Javadoc 1.2)
         * @author      (classes and interfaces only, required)
         * @version     (classes and interfaces only, required. See footnote 1)
         * @see
         * @since
         * @serial      (or @serialField or @serialData)
         * @deprecated  (see How and When To Deprecate APIs)
         */
        @Override
        @SuppressWarnings("unchecked")
        public void mousePressed(MouseEvent e) {
            if (e.getButton() != MouseEvent.BUTTON1) {
                int row = jctable.getCellAreaHandler().getRow(e.getX(), e.getY());
                boolean alreadySelected = false;
                if (jctable.getSelectedCells() != null) {
                    // this suppressed warning brought to you by Quest Software
                    // getSelectedCells() returns a Collection instead of a Collection<JCCellRange>
                    for (Iterator<JCCellRange> iterator = jctable.getSelectedCells().iterator(); iterator.hasNext();) {
                        JCCellRange range = iterator.next();
                        if (range.inRowRange2(row)) {
                            alreadySelected = true;
                            break;
                        }
                    }
                }
                if (!alreadySelected) {
                    jctable.setSelection(row, 0, row, jctable.getNumColumns());
                }
            }
            maybeShowPopup(e);
            //showSingleCellPopup(e);
        }

        /*
         * @param       (classes, interfaces, methods and constructors only)
         * @return      (methods only)
         * @exception   (@throws is a synonym added in Javadoc 1.2)
         * @author      (classes and interfaces only, required)
         * @version     (classes and interfaces only, required. See footnote 1)
         * @see
         * @since
         * @serial      (or @serialField or @serialData)
         * @deprecated  (see How and When To Deprecate APIs)
         */
        @Override
        public void mouseReleased(MouseEvent e) {
            maybeShowPopup(e);
        }

        /*
         * @param       (classes, interfaces, methods and constructors only)
         * @return      (methods only)
         * @exception   (@throws is a synonym added in Javadoc 1.2)
         * @author      (classes and interfaces only, required)
         * @version     (classes and interfaces only, required. See footnote 1)
         * @see
         * @since
         * @serial      (or @serialField or @serialData)
         * @deprecated  (see How and When To Deprecate APIs)
         */
        public void maybeShowPopup(MouseEvent e) {
            if (e.isPopupTrigger()) {
                showPopup(e);
            }
        }

        public void showPopup(MouseEvent e) {
            /* Right click */
            /* Check if within an already selected range (if any). If so, show row selection popup menu
             * else, clear the selections (if any).
             * If there are no slecetion, then just show the smaller popup menu (non row selection) for this cell
             */
            Vector<JCCellRange> scv = getSelectedRows();
            if (scv == null) {
                showMultiRowPopup(e);
                return;
            } else {
                /* Check if current row is withing selection */
                int currentRow = getSelectedRow();

                for (JCCellRange jccr : scv) {
                    int sRow = jccr.start_row;
                    int eRow = jccr.end_row;
                    /* Note: sRow may be greater than eRow if user selects the rows from bottom to top */
                    if (((currentRow >= sRow) && (currentRow <= eRow))
                            || ((currentRow <= sRow) && (currentRow >= eRow))) {
                        showMultiRowPopup(e);
                        return;
                    }
                }
                showMultiRowPopup(e);
            }
        }

        /*
         * @param       (classes, interfaces, methods and constructors only)
         * @return      (methods only)
         * @exception   (@throws is a synonym added in Javadoc 1.2)
         * @author      (classes and interfaces only, required)
         * @version     (classes and interfaces only, required. See footnote 1)
         * @see
         * @since
         * @serial      (or @serialField or @serialData)
         * @deprecated  (see How and When To Deprecate APIs)
         */
        private boolean checkPopupItem(boolean flg, JMenuItem jmi) {
            if (!flg) {
                return true;
            }
            if (jmi.getText().trim().equals("Operation Drill-down Screen")) {
                return false;
            }
            if (jmi.getText().trim().equals("Add/Change Operation")) {
                return false;
            }
            if (jmi.getText().trim().equals("Crop Drill-down Screen")) {
                return false;
            }
            if (jmi.getText().trim().equals("View Operation Notes")) {
                return false;
            }
            if (jmi.getText().trim().equals("View Crop/Residue Notes")) {
                return false;
            }
            if (jmi.getText().trim().equals("Add/Change Crop")) {
                return false;
            }
            if (jmi.getText().trim().contains("Insert")) {
                return false;
            }
            if (jmi.getText().trim().contains("Paste")) {
                return false;
            }

            if (jmi.getText().trim().equals("Calendar Date")) {
                return false;
            }

            return true;
        }

        private void showMultiRowPopup(MouseEvent e) {
            myTable.commitEdit();
            //int col = jctable.getCurrentColumn();
            int col = jctable.getCellAreaHandler().getColumn(e.getX(), e.getY());
            if (col < 0) {
                return;
            }
            usda.weru.util.Util.debugPrint(debugFlg, "" + col);
            //These variables contain the start row and end row of the selection
            int startRow = -1;
            int endRow = -1;
            boolean multiFlg = false;
            boolean onlyBlankRow = false;
            boolean tillagePopupEnable = false;
            String tillValue = null;
            Vector<JCCellRange> scv = getSelectedRows();
            if (scv != null) {
                if (scv.size() >= 1) {
                    //Even if the vector size> 1, check if the start row and end row are different - neha
                    JCCellRange jccr = scv.elementAt(0);
                    startRow = jccr.start_row;
                    endRow = jccr.end_row;
                    multiFlg = jccr.start_row != jccr.end_row || scv.size() > 1;
                    onlyBlankRow = jccr.start_row == jccr.end_row && jccr.start_row == jctable.getNumRows() - 1;
                } else {
                    //System.out.println("T_sMRP: scv size <= 0");
                    int crow = jctable.getCurrentRow();
                    usda.weru.util.Util.debugPrint(debugFlg, "current row " + crow);
                    // return immediately -- single cells are bad things
//					jctable.setRowSelection(crow, crow);
                    multiFlg = false;
                }
            } else {
                //System.out.println("T_sMRP: scv null");
                int crow = jctable.getCurrentRow();
                usda.weru.util.Util.debugPrint(debugFlg, "current row " + crow);
                // return immediately -- single cells are bad things
//				jctable.setRowSelection(crow, crow);
            }
            //If the Column is Tillage Direction - Column 3 then show a different popup menu - neha
            if (col == 3) {
                JPopupMenu popupMenu = new JPopupMenu();
                int row = getSelectedRow();
                if (row == -1) {
                    return;
                }
                OperationObject oprnObj = (OperationObject) mManageData.getDataObject(row, XMLConstants.soperation);
                if (oprnObj != null) {
                    if (startRow > endRow) {
                        int pivot = startRow;
                        startRow = endRow;
                        endRow = pivot;
                    }
                    if((startRow == endRow) && (startRow == -1)) 
                    {
                        startRow = 0;
                        endRow = mManageData.getNumRows();
                    }
                    for (int j = startRow; j <= endRow; j++) {
                        tillValue = mManageData.getColumnValueAsString(j,
                                MCREWConfig.getObjectName(3), MCREWConfig.getTagName(3));
                        if (tillValue != null) {
                            tillagePopupEnable = true;
                            break;
                        }
                    }
                    for (int i = 0; i < mcrew.getTillagePopupElements().size(); i++) {
                        JMenuItem jmi = popupMenu.add((JMenuItem) mcrew.getTillagePopupElements().get(i));
                        if (tillagePopupEnable == true) {
                            jmi.setEnabled(true);
                        } else {
                            jmi.setEnabled(false);
                        }
                    } //end of for loop

                } //end of if oprnObj is not null

                popupMenu.addSeparator();
                for (int i = 0; i < mcrew.getPopupElements().size(); i++) {
                    JMenuItem jmi = (JMenuItem) mcrew.getPopupElements().get(i);
                    popupMenu.add(jmi);
                    //Disable critical item based on multirow flag
                    ////System.out.println("Adding " + Mcrew.popupVec.get(i));
                }

                popupMenu.show(e.getComponent(), e.getX(), e.getY());
                popupMenu.setVisible(true);

                return;
            }

            if (col >= MCREWConfig.getFixedColumnsCount()) {
                JPopupMenu popupMenu = new JPopupMenu();
                for (int i = 0; i < mcrew.getPopupElements().size(); i++) {
                    JMenuItem jmi = (JMenuItem) mcrew.getPopupElements().get(i);
                    popupMenu.add(jmi);
                    //Disable critical item based on multirow flag
                    if(!jmi.getText().contains("Undo Delete")) jmi.setEnabled(checkPopupItem(multiFlg, jmi));
                    ////System.out.println("Adding " + Mcrew.popupVec.get(i));
                }

                popupMenu.show(e.getComponent(), e.getX(), e.getY());
                popupMenu.setVisible(true);

                return;
            }

            String newObjectName = MCREWConfig.getObjectName(col);
            //System.out.println("Mcrew-Table-newObjectName:"+newObjectName);
            if (newObjectName.equals(XMLConstants.sdate)) {
                //	MenuElement [] menuElements = Mcrew.datePopup.getSubElements();
                JPopupMenu popupMenu = new JPopupMenu();
                for (int i = 0; i < 3; i++) {
                    JMenuItem jmi = (JMenuItem) mcrew.getDatePopupElements().get(i);
                    popupMenu.add(jmi);
                    //Dont enable the "Set Date" and "Calendar Date"
                    // menu items when multi rows of Date are selected.
                    jmi.setEnabled(checkPopupItem(multiFlg, jmi));
                }
                //Add a Separator after "Calendar Date" menu item.
                popupMenu.addSeparator();

                for (int i = 3; i < mcrew.getDatePopupElements().size(); i++) {
                    JMenuItem jmi = (JMenuItem) mcrew.getDatePopupElements().get(i);
                    popupMenu.add(jmi);
                    //Disable critical item based on multirow flag
                    if(!jmi.getText().contains("Undo Delete")) jmi.setEnabled(checkPopupItem(multiFlg, jmi));
                    //If anything is to be disabled when multirows are selected, then it will be disabled.
                    jmi.setEnabled(!onlyBlankRow && checkPopupItem(multiFlg, jmi));
                }

                popupMenu.show(e.getComponent(), e.getX(), e.getY());
                popupMenu.setVisible(true);
            } else if (newObjectName.equals(XMLConstants.soperation)) {
                JPopupMenu popupMenu = new JPopupMenu();
                for (int i = 0; i < mcrew.getOperationPopupElements().size(); i++) {
                    ////System.out.println("Adding " + Mcrew.operationCellPopupVec.get(i));
                    JMenuItem jmi = (JMenuItem) mcrew.getOperationPopupElements().get(i);
                    popupMenu.add(jmi);
                    //Dont enable the "Operation drill down screen" and "Add/Change Operation"
                    // menu items when multi rows of Operation are selected.
                    jmi.setEnabled(checkPopupItem(multiFlg, jmi));

                }

                popupMenu.addSeparator();

                for (int i = 0; i < mcrew.getPopupElements().size(); i++) {
                    ////System.out.println("Adding " + Mcrew.popupVec.get(i));
                    ////System.out.println("Adding " + Mcrew.operationCellPopupVec.get(i));
                    JMenuItem jmi = (JMenuItem) mcrew.getPopupElements().get(i);
                    popupMenu.add(jmi);
                    //Disable critical item based on multirow flag
                    if(!jmi.getText().contains("Undo Delete")) jmi.setEnabled(checkPopupItem(multiFlg, jmi));

                    if(jmi.getText().toLowerCase().contains("unadjusted")) 
                    {
                        jmi.setEnabled(!mManageData.IntView());
                    }
                    if (jmi.getActionCommand().toLowerCase().contains("add rotation")) 
                    {
                        jmi.setEnabled(onlyBlankRow || mManageData.IntView());
                    }
                }

                popupMenu.show(e.getComponent(), e.getX(), e.getY());
                popupMenu.setVisible(true);
            } else if (newObjectName.equals(XMLConstants.scrop)) {
                JPopupMenu popupMenu = new JPopupMenu();

                int row = getSelectedRow();
                if (row == -1) {
                    return;
                }
                OperationObject oprnObj = (OperationObject) mManageData.getDataObject(row, XMLConstants.soperation);
                if (oprnObj != null) {
                    for (int i = 0; i < mcrew.getCropPopupElements().size(); i++) {
                        JMenuItem jmi = popupMenu.add((JMenuItem) mcrew.getCropPopupElements().get(i));
                        //Enable the "Crop drill down screen" and "Add/Change Crop"
                        // menu items Only when Single row of Crop is selected AND
                        // when the operation HAS a crop - neha
                        if (oprnObj.hasCrop() == true && checkPopupItem(multiFlg, jmi) == true) {
                            jmi.setEnabled(true);
                        } else {
                            jmi.setEnabled(false);
                        }

                        ////System.out.println("Adding " + Mcrew.cropCellPopupVec.get(i));
                    }
                }
                popupMenu.addSeparator();
                for (int i = 0; i < mcrew.getPopupElements().size(); i++) {
                    JMenuItem jmi = (JMenuItem) mcrew.getPopupElements().get(i);
                    popupMenu.add(jmi);
                    //Disable critical item based on multirow flag
                    if(!jmi.getText().contains("Undo Delete")) jmi.setEnabled(checkPopupItem(multiFlg, jmi));
                    ////System.out.println("Adding " + Mcrew.popupVec.get(i));
                }

                popupMenu.show(e.getComponent(), e.getX(), e.getY());
                popupMenu.setVisible(true);
            }
        }
        
        @Override
        public void mouseWheelMoved(MouseWheelEvent e)
        {
            if(arrayEditor != null) arrayEditor.hidePopup();
            arrayEditor = null;
        }

    } //end class
    private JCPrintTable printTable = null;
    private String printTitle = "";
//	public void doPrint(debugFlg, JCTable jct, String title

    /**
     * Called when the table is supposed to be printed in a default format, orientation
     * allowing the user to preview itbefore actually printing it. Shows the first page of
     * the entire printable matter.
     * @param title The title of the page to be printed with.
     */
    public void doPrint(String title) {
        printTable = new JCPrintTable(jctable);
        printTable.setFrozenColumns(0);

        printTitle = title;

        PageFormat pageFormat = new PageFormat();
        pageFormat.setOrientation(java.awt.print.PageFormat.LANDSCAPE);
        printTable.setPageFormat(pageFormat);

        printTable.addPrintListener(this);
        JCPrintPreview pf = new JCPrintPreview("Print Preview", printTable);
        pf.showPage(0);
    }

    /*********************************************************************** wjr */
    /**
     * printEnd, printPageBody, printPageFooter and printPageHeader
     * Implement the JCPrintListener interface and allow the reports to be
     * printed in a nice, formatted manner.
     * @param event The event listener for the print job when the print button is
     * hit from print dialog or print menu.
     */
    public void printEnd(JCPrintEvent event) {
    }

    /**
     * Implement the JCPrintListener interface and allow the reports to be
     * printed in a nice, formatted manner including the page body.
     * @param event The event listener for the print job invoked when the print button is
     * hit from print dialog or print menu. Here the body of the text will be used
     * for printing.
     */
    @Override
    public void printPageBody(JCPrintEvent event) {
    }

    /**
     * Implement the JCPrintListener interface and allow the reports to be
     * printed in a nice, formatted manner including the page footer information.
     * @param e The event listener for the print job. This is invoked when the print
     * button is hit from print dialog or print menu. Here the text for page footer
     * will also be included while printing the body.
     */
    @Override
    public void printPageFooter(JCPrintEvent e) {
        Graphics gc = e.getGraphics();
        Rectangle r = gc.getClip().getBounds(); // fix to get rid of dep method

        String page = "Page " + e.getPage() + " of " + printTable.getNumPages();
        // Pad the footer text to the right

        gc.drawString(page, 0, r.height / 2);

    }

    /**
     * Implement the JCPrintListener interface and allow the reports to be
     * printed in a nice,formatted manner including the page header information.
     * @param e The event listener for the print job. This is invoked when the print
     * button is hit from print dialog or print menu. Here the text for page header
     * will also be included while printing the body.
     */
    @Override
    public void printPageHeader(JCPrintEvent e) {
        Graphics gc = e.getGraphics();
        Rectangle r = gc.getClip().getBounds(); // fix to get rid of dep method

        // Pad the footer text to the right
        gc.drawString("Management  Rotation:", 0, r.height / 2);
        gc.drawString(printTitle, 0, r.height / 2 + 20);

    }
    private List<String> c_enabledViews;

    /**
     *
     * @param name
     * @param state
     */
    public void toggleTableView(String name, boolean state) {
        if (c_enabledViews == null) {
            c_enabledViews = new ArrayList<String>();
        }
        if (state) {
            if (!c_enabledViews.contains(name)) {
                c_enabledViews.add(name);
            }
        } else {
            if (c_enabledViews.contains(name)) {
                c_enabledViews.remove(name);
            }
        }

        refreshVisibleColumns();
    }

    /**
     *
     */
    public void refreshVisibleColumns() {
        List<Integer> indexesToShow = new ArrayList<Integer>();

        for (String viewName : c_enabledViews) {
            MCREWConfig.TableView view = MCREWConfig.getTableView(viewName);
            for (int i : view.getColumnIndexes()) {
                if (!indexesToShow.contains(i)) {
                    indexesToShow.add(i);
                }
            }
        }

        for (int i = 0; i < MCREWConfig.getColumnNames().size(); i++) {
            if (indexesToShow.contains(i)) {
                jctable.setColumnHidden(i, false);
            } else {
                jctable.setColumnHidden(i, true);
            }
        }
    }
    /**
     * Method that, row by row, marks the invalid data
     */
    public void checkData()
    {   
        for(int index = 0; index < mManageData.getRows().size(); index ++)
        {
            jctable.setUserData(index, 1, mManageData.getRows().get(index).
                    getDataObject(XMLConstants.soperation));
        }
        ArrayList<ManageData.Highlight> highlist = mManageData.checkData();
        for(ManageData.Highlight highlighter : highlist)
        {
            int row = highlighter.getRow();
            int column = highlighter.getColumn();
            InputLimits.TableStatus color = highlighter.getColor();
            MCREWConfig.ColumnDefn tempColumnDef = MCREWConfig.getColumns().get(column);
            MCREWConfig.CellStyle dataStyle = tempColumnDef.getDataCellStyle(color);
            if(dataStyle != null) jctable.setCellStyle(row, column, dataStyle.getJCCellStyle());
        }
    }
    
    /**
     * Shows the notes for the specified column (ie operation/crop)
     * @param col 
     */
    public void showNotes(int col)
    {
        Vector<JCCellRange> v = getSelectedRows();
        JCCellRange range = v.firstElement();
        if (range.start_row != range.end_row || v.size() > 1) {
            return;
        }
        int row = getSelectedRow();
        if (row == -1) {
            return;
        }
        if(col == -1) return;
        String newObjectName = MCREWConfig.getObjectName(col);
        String text = "";

        if (newObjectName.equals(XMLConstants.soperation)) {
            //check if this operation has the values for the object objectName (theres only crop now)
            OperationObject oprnObj = (OperationObject) mManageData.getDataObject(row, XMLConstants.soperation);
            if (oprnObj != null) text = oprnObj.getNotes();
            else return;
        }
        if(newObjectName.equals(XMLConstants.scrop))
        {
            OperationObject oprnObj = (OperationObject) mManageData.getDataObject(row, XMLConstants.soperation);
            CropObject crpObj = oprnObj.getCrop();
            if(crpObj != null) text = crpObj.getValue("crop_notes");
            else return;
        }
        NotesViewer notes = new NotesViewer(null, text, newObjectName);
        notes.setVisible(true);
    }
    
    private class NotesViewer extends javax.swing.JDialog 
    {
        private static final long serialVersionUID = 1L;

        private String title;
        
        /**
         * Single argument constructor for the about dialog GUI object.
         * @param parent The address of a parent frame in which the About dialog sits.
         */
        public NotesViewer(java.awt.Frame parent, String text, String cropOp) {
            super(parent);
            title = cropOp;
            if(title.charAt(0) == 'c' || title.charAt(0) == 'o')
            {
                title = title.substring(0, 1).toUpperCase() + title.substring(1);
            }
            title += " Notes";
            initComponents();
            g_aboutTextArea.setText(text);
        }

        /** 
         * This method is called from within the constructor to initialize the form.
         * WARNING: Do NOT modify this code. The content of this method is
         * always regenerated by the Form Editor.
         */                   
        private void initComponents() {

            g_closeButton = new javax.swing.JButton();
            g_aboutScrollPane = new javax.swing.JScrollPane();
            g_aboutTextArea = new javax.swing.JTextArea();

            setTitle(title);
            addWindowListener(new java.awt.event.WindowAdapter() {
                public void windowClosing(java.awt.event.WindowEvent evt) {
                    closeDialog(evt);
                }
            });

            g_closeButton.setMnemonic('O');
            g_closeButton.setText("Close");
            g_closeButton.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    g_closeButton_ActionPerformed(evt);
                }
            });

            g_aboutTextArea.setColumns(20);
            g_aboutTextArea.setEditable(false);
            g_aboutTextArea.setFont(new java.awt.Font("Monospaced", 0, 12)); // NOI18N
            g_aboutTextArea.setRows(8);
            g_aboutScrollPane.setViewportView(g_aboutTextArea);

            javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
            getContentPane().setLayout(layout);
            layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addContainerGap()
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addComponent(g_aboutScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 541, Short.MAX_VALUE)
                        .addComponent(g_closeButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 85, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addContainerGap())
            );
            layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addContainerGap()
                    .addComponent(g_aboutScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 340, Short.MAX_VALUE)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                    .addComponent(g_closeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addContainerGap())
            );

            setSize(new java.awt.Dimension(569, 538));
            setLocationRelativeTo(null);
        }// </editor-fold>                        

        private void g_closeButton_ActionPerformed(java.awt.event.ActionEvent evt) {                                               
            close();
    }                                              

        private void close() {
            setVisible(false);
            dispose();
        }

        /** 
         * This method is called when the about dialog is to be closed by hitting the 
         * "Red X" button of the window.
         * @param evt The event generated when the " Red X " button on the window is hit. 
         */
        private void closeDialog(java.awt.event.WindowEvent evt) {                             
            close();
        }                            



        // Variables declaration - do not modify                     
        private javax.swing.JScrollPane g_aboutScrollPane;
        public javax.swing.JTextArea g_aboutTextArea;
        public javax.swing.JButton g_closeButton;
        // End of variables declaration                   

    }
    /**
     * Getter for dataChanged.
     * @return 
     */
    public boolean getDataChanged() { return dataChanged; }
    /**
     * Setter for dataChanged.
     * @param changed 
     */
    public void setDataChanged(boolean changed) 
    { 
        dataChanged = changed; 
        checkData();
    }
    
    /**
     * This function calls other functions for checking all conditions on mManageData before saving the
     * file. Checks for correct rotation years, sorted mManageData and no empty rows
     *
     * @return Returns true if evrything passed OK else false.
     */
    public boolean checkAllConditions() {
//shouldn't need        checked = true;
        Vector<String> msgs = new Vector<String>();
        if (checkIfAllDatesPresent() == -1) {
            return false;
        }
        if (mManageData.checkIfSorted(msgs) == ManageData.CHECK_FAILED) {
            String[] errorMsg = {"The mManageData is not sorted according to the dates.", "",
                "Do you want to auto sort them before saving? Click 'No' to go back and change manually"};

            int option = JOptionPane.showConfirmDialog(this, errorMsg, "Sort mManageData", JOptionPane.YES_NO_OPTION);

            switch (option) {
                case JOptionPane.YES_OPTION:
                    //sort rows
                    mManageData.sortData();
                    break;
                case JOptionPane.NO_OPTION:
                    return false; // user resees no/cancel
            }
        }

        if (checkAndDeleteEmptyRows() == -1) {
            // user pressed cancel
            return false;
        }
        if (checkAndSetRotYears() == -1) {
            // user pressed cancel
            return false;
        }
        if (checkParameterConsistency() == -1) {
            return false;
        }
        return true;
    }

    /**
     * This method makes sure if rows exist in a table then their date cells are populated.
     *
     * @return True, if date is populated for every row in a table else false.
     */
    public int checkIfAllDatesPresent() {
        Vector<Integer> noDateRows = mManageData.checkIfAllDatesPresent();

        if (noDateRows == null) {
            return 1;
        }
        String noDateRowStr = null;
        String[] errorMsg = {"There are following rows with no dates in them.", "", "Please go back and enter the dates."};

        for (Integer noDateRow : noDateRows) {
            if (noDateRowStr == null) {
                noDateRowStr = noDateRow.toString();
            } else {
                noDateRowStr += ", " + noDateRow.toString();
            }
        }

        errorMsg[1] = noDateRowStr;

        JOptionPane.showMessageDialog(this, errorMsg);

        return -1;
    }

    /**
     * Check if there are any empty rows in the table and prompt user to delete them
     *
     * @return True if empty rows are found, else false
     */
    public int checkAndDeleteEmptyRows() {
        Vector<Integer> emptyRows = mManageData.checkEmptyRows();

        if (emptyRows == null) {
            return 1;
        }
        String emptyRowStr = null;
        String[] errorMsg = {"There are some empty rows in the table as given below.", "",
            "Do you want to delete the delete them before saving? Click 'No' to go back and change manually"};

        for (Integer emptyRow : emptyRows) {
            if (emptyRowStr == null) {
                emptyRowStr = emptyRow.toString();
            } else {
                emptyRowStr += ", " + emptyRow.toString();
            }
        }

        errorMsg[1] = emptyRowStr;

        int option = JOptionPane.showConfirmDialog(this, errorMsg, "Delete Empty Rows ?", JOptionPane.YES_NO_OPTION);

        switch (option) {
            case JOptionPane.YES_OPTION:
                //delete rows
                mManageData.deleteRows(emptyRows);
                mcrew.setUndoDeleteStatus(true);
                break;
            case JOptionPane.NO_OPTION:
                return -1; // user resees no/cance
        }

        return 1;
    }

    /**
     * Check if rotation years match the dates in the mManageData and set it to a correct value if user
     * enters one.
     *
     * @return Returns the integer value telling the length of the rotation if it is equal to or
     * greater than the rotation year specified for the last operation else -1. This is a check to
     * input correct values for rotation years.
     */
    public int checkAndSetRotYears() {
        int correctYears = mManageData.checkRotationYears(); // returns the correct year value
        if (correctYears == -1) {
            return -1;
        }
        int rotYears = mManageData.kRotationYears;

        if (rotYears >= correctYears) {
            return rotYears;

            //System.out.println("Mcrew:checkRotYears->"+ "RotYears= " + rotYears + ", Correct Yrs= " + correctYears);
        }
        do {
            RotationLengthDialog dialog = new RotationLengthDialog(Integer.toString(correctYears));
            dialog.setSize(300, 250);
            JScrollPane sp = new JScrollPane(dialog, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
            sp.setBorder(null);
            sp.setPreferredSize(new Dimension(365, 170));
            int ipValue = JOptionPane.showOptionDialog(this, sp, "Rotation Years", JOptionPane.OK_CANCEL_OPTION,
                    JOptionPane.QUESTION_MESSAGE, null, null, null);
            String newValue = dialog.getValue();

            if (ipValue == JOptionPane.CANCEL_OPTION) {
                return -1; //user pressed Cancel option
            } else {
                try {
                    rotYears = Integer.parseInt(newValue);
                } catch (NumberFormatException e) {
                    LOGGER.error("Non numeric value entered for rotation years: " + newValue, e);
                }
            }
        } while (rotYears < correctYears);

        String rotYearsStr = Integer.toString(rotYears);
        mcrew.setRotText(rotYearsStr);
        synchronized(mManageData) { mManageData.kRotationYears = Integer.parseInt(rotYearsStr); } // make changes in the mManageData object
        
        return rotYears;
    }

    /**
     * Checks if all the operations and their actions have values for all the parameters listed in
     * "operation_defn.xml"
     *
     * @return Returns 0 if there are no invalid operations in the vector else 1
     */
    public int checkParameterConsistency() {
        Vector<String> msgs = new Vector<String>();
        if (mManageData.checkParameterConsistency(msgs) == ManageData.CHECK_PASSED) {
            return ManageData.CHECK_PASSED;
        }
        WepsMessageLog log = new WepsMessageLog();
        for (String msg : msgs) {
            log.logMessage(WepsMessage.MessageSeverity.ERROR, msg);
        }
        WepsMessageDialog.showMessageList(this, "Management File Errors", "Errors were detected with the management file.", ".",
                log.getMessages());

        return ManageData.CHECK_FAILED;
    }
    
    /**
     * Returns the data associated with this table.
     * @return 
     */
    public ManageData getData() { return mManageData; }
    
    /**
     * Sets the current array editor tied to the table, so we can dispose it with
     * other events.
     * @param editor 
     */
    public void hookEditor(ArrayEditorPopup editor)
    {
        if(arrayEditor != null) arrayEditor.hidePopup();
        arrayEditor = editor;
    }
    
    /**
     * Removes the current array editor tied to the table, so we can stop trying to
     * dispose it.
     * @param editor 
     */
    public void unhookEditor(ArrayEditorPopup editor)
    {
        arrayEditor = null;
    }
    
    /**
     * This method will check to see if the selected cell vector contains the last
     * row of the table.  If it does, control passes to the check wrap method to
     * color said cells.
     * @param scv 
     */
    public void checkEndCell(List<JCCellRange> scv)
    {
        if(!mManageData.IntView()) return;
        boolean contains = false;
        for(JCCellRange range : scv)
        {
            int endrow = range.end_row > range.start_row ? range.end_row : range.start_row;
            if(endrow >= mManageData.getWrap() - 1) contains = true;
        }
        if(contains) checkWrap();
    }
    
    /**
     * This method will check (from the end of) a crop Interval view to see if
     * the table wraps correctly.
     */
    public void checkWrap()
    {
        if(!mManageData.IntView()) return;
        if(mManageData.size() < 2) return;
        JulianCalendar first = mManageData.getDate(0);
        int end = mManageData.size() - 1;
        JulianCalendar wrap = mManageData.getDisplayDate(end);
        JulianCalendar last = wrap.cloneDate();
        if(wrap.get(Calendar.YEAR) <= mManageData.kRotationYears) return;
        last.set(Calendar.YEAR, wrap.get(Calendar.YEAR) - mManageData.kRotationYears);
        if(!last.after(first)) //All is well.  Make sure to clear current ill wrap state.
        {
            mManageData.addIllWrap(mManageData.size());
            mcrew.clearIllWrap();
        }
        else
        {
            while(last.after(first))
            {
                end --;
                last = mManageData.getDate(end);
            }
            end ++;
            mManageData.addIllWrap(end);
            mcrew.setIllWrap();
        }
    }
    
    /**
     * We need to synch the tile drop downs to this table whenever we change
     * the table being displayed.
     */
    public void focusTable() { MCREWConfig.hackFileListThingies(this, mouseAdapter); }
    
}
