
package usda.weru.soil;

// import the necessary java classes, including the Table package
import java.awt.*;
import java.util.*;
import javax.swing.*;

//import java.awt.event.ActionListener;
import java.awt.event.*;
import com.klg.jclass.table.data.JCEditableVectorDataSource;
import com.klg.jclass.table.JCTableEnum;
import com.klg.jclass.table.CellStyleModel;
import com.klg.jclass.table.JCCellRange;
//import com.klg.jclass.table.JCScrollListener;
//import com.klg.jclass.table.JCScrollEvent;
import com.klg.jclass.table.JCEditCellListener;
import com.klg.jclass.table.JCEditCellEvent;
import com.klg.jclass.table.JCCellStyle;
import com.klg.jclass.field.cell.JCTextFieldCellEditor;
import com.klg.jclass.table.JCSelectListener;
import com.klg.jclass.table.JCSelectEvent;

import de.schlichtherle.io.File;
import usda.weru.util.Util;

/**
 * Simple LiveTable example.  Creates a simple table
 * using a JCVectorDataSource.
 */
//public class Grid extends JPanel implements JCEditCellListener, ActionListener {
public class Grid extends usda.weru.util.SimpleTable implements JCEditCellListener, JCSelectListener, ActionListener {
    
// initialize the Table object
//protected JCTable table;
    private	IFC	inputRecord;
    private	int	inputType;
    private JCEditableVectorDataSource dataSource;
    private	int	hdrRows;
    private	int	bodRows;
    
// Build the table, point to the data source and define the table
// properties.
    
    /**
     *
     * @param inprec
     * @param gridType
     */
    public Grid(IFC inprec, int gridType) {
        boolean multiRowFlg = false;
        
        inputRecord = inprec;
        inputType = gridType;
        
        
        setLayout(new java.awt.GridLayout());
        
        // Create a default table object
//	table = new JCTable();
        
        //jctable = new usda.weru.util.ToolTipsTable();
        
        String fileName = "";
        switch (gridType) {
            case 1 : jctable = new usda.weru.util.ToolTipsTable("IDPanel", new File("cfg", "soiltooltips.cfg"));
            ToolTipManager.sharedInstance().registerComponent(jctable);
            jctable.setLabels(new String[]{"", "state", "county", "area", "ssid","mapunit",
            "compname", "comppercent", "soilorder","localphase","texture","losstol"});
            fileName = "soil1.cfg";
            multiRowFlg = false;
            break;
            case 2 : jctable = new usda.weru.util.ToolTipsTable("SurfPanel", new File("cfg", "soiltooltips.cfg"));
            ToolTipManager.sharedInstance().registerComponent(jctable);
            jctable.setLabels(new String[]{"", "crustthick", "crustdensity", "cruststability", "crustfract",
            "loosemass", "loosefract", "randruff", "ridgeorient","ridgeheight","ridgespace","ridgewidth",
            "albedo","slope","surffrag","bedrockdepth","resdepth"});
            fileName = "soil2.cfg";
            multiRowFlg = false;
            break;
            case 3 :jctable = new usda.weru.util.ToolTipsTable("LayerPanel", new File("cfg", "soiltooltips.cfg"));
            ToolTipManager.sharedInstance().registerComponent(jctable);
            jctable.setLabels(new String[]{"layernumber", "layerthick", "om", "sand",
            "silt","clay","rock","vcsand","csand","msand","fsand","vfsand","wetbd",
            "drybd", "aggmd", "aggsd", "agmax","agmin","agden","agstab","waterinit",
            "watersat","waterfc","waterpwp","cb","aep","satk","ph","caco3","cec","lep"});
            fileName = "soil3.cfg";
            multiRowFlg = true;
            break;
        }
        
        Hashtable HT_config = readConfig("cfg", fileName);
        
        readReports(null, repVec, HT_config);
        // Create a vector data source to contain our data
        dataSource = new JCEditableVectorDataSource();
        
        // Set the cell data in the data source.
        String[][] gridData = inputRecord.getGridValues(inputType);
//	String[][] colHeaders = inprec.getColumnHeaderValues(gridType);
        String [][] colHeaders = parseHeaders(HT_config, Util.USUnits);
        hdrRows = colHeaders.length;
        bodRows = gridData.length;
        int bodCols = gridData[0].length;
        
//System.out.println("g: bodCols " + bodCols);
        
        // Turn off column labels
        jctable.setColumnLabelDisplay(false);
        
        // Turn on/off row labels
        if (multiRowFlg) jctable.setRowLabelDisplay(true);
        else jctable.setRowLabelDisplay(false);
        
        // Set the number of rows in the data source.
        dataSource.setNumRows(bodRows + hdrRows);
        
        // Set the number of columns in the data source.
        dataSource.setNumColumns(bodCols); // error to fix
        
        
        dataSource.setColumnLabels(colHeaders[0]);
        
        if (multiRowFlg) {
            setRowLabels(hdrRows, bodRows);
        }
        
        tableData = new String[bodRows + hdrRows + 1][];
        
        try {
            for (int idx = 0; idx < colHeaders.length; idx++) {
                tableData[idx] = colHeaders[idx];
            }
        } catch (java.lang.ArrayIndexOutOfBoundsException e) {}//System.err.println(e + " " + tableData.length);}
            
            for (int idx = 0; idx < gridData.length; idx++) {
                tableData[idx + hdrRows] = gridData[idx];
            }
            
// temp fix to get last row to display
            tableData[tableData.length-1] = new String[gridData[0].length];
            for (int idx = 0; idx < tableData[tableData.length-1].length; idx++)
                tableData[tableData.length-1][idx] = " ";
            
//	dataSource.setCells(tableData);
            
//	makeSpan(inprec.getColumnHeaderValues(gridType));
            makeSpan(colHeaders, bodCols);
//	makeSpan(tableData, bodCols);
            dataSource.setCells(tableData);
            
            CellStyleModel labelStyle = jctable.getDefaultLabelStyle();
            
            labelStyle.setBackground(new Color(255,255,160));
            labelStyle.setForeground(Color.black);
            labelStyle.setHorizontalAlignment(JCTableEnum.LEFT);
            labelStyle.setClipHints(JCTableEnum.SHOW_NONE);
            labelStyle.setCellBorderSides(JCTableEnum.BORDERSIDE_ALL);
            labelStyle.setEditable(false);
            labelStyle.setTraversable(false);
            
            jctable.setCellStyle(new JCCellRange(0,0,0,bodCols-1), labelStyle);
            
            JCCellStyle cs = new JCCellStyle();
            cs.setBackground(new Color(255,255,210));
            cs.setForeground(Color.black);
            cs.setHorizontalAlignment(JCTableEnum.CENTER);
            cs.setClipHints(JCTableEnum.SHOW_NONE);
            cs.setCellBorderSides(JCTableEnum.BORDERSIDE_ALL);
            cs.setEditable(false);
            cs.setTraversable(false);
//	cs.Traversible = false;
            
            
            jctable.setCellStyle(new JCCellRange(1,0,hdrRows-1,bodCols-1), cs);
//	jctable.setCellStyle(new JCCellRange(0,0,hdrRows-1,bodCols-1), labelStyle);
            
//	jctable.setFrozenRows(hdrRows -1);
            jctable.setFrozenRows(hdrRows);
            jctable.setPixelWidth(JCTableEnum.ALLCELLS, JCTableEnum.VARIABLE);
            jctable.setPixelWidth(JCTableEnum.LABEL, 30);
            jctable.setSelectionPolicy(JCTableEnum.SELECT_RANGE);
            jctable.setAutoScroll(JCTableEnum.AUTO_SCROLL_BOTH);
            jctable.setHorizSBDisplay(JCTableEnum.SCROLLBAR_ALWAYS);
            jctable.setHorizSBPosition(JCTableEnum.ATTACH_SIDE);
            
            int[] cW2 = getColumnWidths(bodCols, HT_config);
//	for (int qdx = 0; qdx < cW2.length; qdx++) {
//		//System.out.println("G_G: " + qdx + " " + cW2[qdx]);
//	}
//	int[] columnWidths = inprec.getColumnWidths(gridType);
            
//	for (int cdx = 0; cdx < columnWidths.length; cdx++)
            for (int cdx = 0; cdx < cW2.length; cdx++)
                jctable.setPixelWidth(cdx, cW2[cdx]);
//		jctable.setPixelWidth(cdx, columnWidths[cdx]);
            
            jctable.addEditCellListener(this);
            jctable.addSelectListener(this);
            jctable.setDataSource(dataSource);
            
//	addToolTips(hdrRows, bodRows, bodCols);
            
            this.add(jctable);
        }
        
        /*********************************************************************** wjr */
        
        private	void	addToolTips(int hdrRows, int bodRows, int bodCols) {
////System.out.println("aTT : " + hdrRows + " " + bodRows + " " + bodCols);
            ErrorRange[] eR = inputRecord.getToolTipText(inputType);
            for (int rdx = hdrRows; rdx < (hdrRows + bodRows); rdx++) {
                for (int cdx = 0; cdx < bodCols; cdx++) {
                    CellStyleModel csm = jctable.getUniqueCellStyle(rdx, cdx);
//			 JCCellEditor jcce = csm.getCellEditor();
//			 JCTextFieldCellEditor jcce = csm.getCellEditor();
//			 JComponent jcce = csm.getCellEditor();
//			 jcce.setToolTipText("fred is here");
//			(csm.getCellEditor()).setToolTipText("fred is here");
////System.out.println("aTT: " + csm.getCellEditor());
                    JCTextFieldCellEditor tfce = new JCTextFieldCellEditor();
//			tfce.setToolTipText("fred is here " + rdx + cdx);
////System.out.println("aTT: " + cdx + " " + eR[cdx].getToolTipText());
                    tfce.setToolTipText(eR[cdx].getToolTipText());
                    csm.setCellEditor(tfce);
                    jctable.setCellStyle(hdrRows, bodCols-1, csm);
                }
            }
        }
        
        /*********************************************************************** wjr */
        
        private	void	makeSpan(String[][] labelArray, int bodCols)
        
        {
            int	crx;		// current row
//	int nrx;
            int ccx;		// current col
//	int ncx;
            int scx;		// start col
            
            super.makeSpan(labelArray, labelArray.length, jctable);
/*	// test to span col
        JCCellRange spanrange = new JCCellRange(0, 0, 0, bodCols);
        try {
                jctable.addSpannedRange(spanrange);
        } catch (java.lang.IllegalArgumentException e) {
        }
 
        // start at one since we already spanned top row
        for (crx = 1; crx < labelArray.length; crx++) {
                String lastHdr = "";
//		for (ccx = 0, scx = -1; ccx < labelArray[crx].length; ccx++) {
                for (ccx = 2, scx = 1; ccx < labelArray[crx].length; ccx++) {
////System.out.println("mS: " + crx + " " + ccx + " " + labelArray[crx][ccx]);
                        if (labelArray[crx][ccx].trim().equals("~*R")) {
//System.out.println("G_mS: " + lastHdr);
                                labelArray[crx][ccx] = lastHdr;
                                continue;
                        }
                        lastHdr = labelArray[crx][ccx];
                        if (scx != ccx - 1) {
////System.out.println("G_mS: " + crx + "," + ccx + "," + nrx + "," + crx);
                                // subtract 1 from rows because first row of labels is
                                // handled by system
                                spanrange = new JCCellRange(crx, scx, crx, ccx - 1);
////System.out.println("G_mS: " + spanrange);
                                try {
                                        jctable.addSpannedRange(spanrange);
                                } catch (java.lang.IllegalArgumentException e) {
                                        //System.err.println("overlapping spanning ranges " + spanrange);
                                }
                        }
                        scx = ccx;
                }
        }
        Collection col = jctable.getSpannedRanges();
        for (Iterator coli = col.iterator(); coli.hasNext(); ) {
                //System.out.println("G_mS: " + coli.next());
        }*/
        }
        
        /*********************************************************************** wjr */
        
        /**
         * testing doc of setHeight
         *
         * @title xxxx
         * @param rh
         */
        
        public	void	setHeight(int rh)
        
/*
 * testing doc of setHeight 3
 * */
        
        {
            jctable.setPixelHeight(JCTableEnum.ALLCELLS, rh);
        }
        
/*
 * testing doc of setHeight 2
 * */
        
        /*********************************************************************** wjr */
        
        private	int	tw = 600;
        
        /**
         *
         * @return
         */
        public	Dimension	getPreferredSize() {
            Dimension d = jctable.getPreferredSize();
//	d.height += 65;
//	d.width = 600;
            tw += 20;
            d.width = tw;
            Dimension p = getParent().getParent().getSize();
////System.out.println("gPS: called " + d + super.getSize());
////System.out.println("gPS: called " + d + getParent().getSize());
            if (p.width > 20) d.width = p.width - 20;
////System.out.println("gPS: p " + p.width + " d " + d.width);
//	jctable.setPreferredSize(d);
            return d;
        }
        
        /**
         * wjr
         * @return
         */
        
        public	Dimension	getMaximumSize() {
            Dimension d = jctable.getMaximumSize();
////System.out.println("gMxS: called " + d);
            return d;
        }
        
        /**
         * wjr
         * @return
         */
        
        public	Dimension	getMinimumSize() {
//	Dimension d = jctable.getMinimumSize();
            Dimension d = new Dimension(300, 25);
            d.width = getParent().getSize().width - 40;
////System.out.println("gMnS: called " + d + getParent().getSize());
            return d;
        }
        
        /*********************************************************************** wjr */
        
        private	JTextField cellEditor = null;
        private	String	oldValue = null;
        private	int	editRow = -1;
        
        /**
         * wjr
         * @param event
         */
        
        public void beforeEditCell(JCEditCellEvent event) {
            
            Util.debugPrint(true, "edit row " + event.getRow());
            cellEditor = null;
        }
        
        /**
         * wjr
         * @param event
         */
        
        public void editCell(JCEditCellEvent event) {
            ////System.out.println("eC:");
            Component c = event.getEditingComponent();
            if(c instanceof JTextField) {
                cellEditor = (JTextField) c;
                if (oldValue == null) oldValue = cellEditor.getText();
                cellEditor.selectAll();
            }
            editRow = event.getRow();
            Util.debugPrint(true, "current row " + editRow);
        }
        
        /**
         * wjr
         * @param event
         */
        
        public void afterEditCell(JCEditCellEvent event) {
            ////System.out.println("aEC: " + " row " + event.getRow() + " col " + event.getColumn()
//						   + " " + ((cellEditor != null) ? cellEditor.getText() : "!none"));
            if (cellEditor != null) {
                if (!inputRecord.updateRecordFromGrid(event.getColumn(), event.getRow(),
                        inputType, cellEditor.getText())) dataSource.setTableDataItem(oldValue,
                                event.getRow(), event.getColumn());
//		cellEditor.setText(oldValue);
//		cellEditor.validate();
            }
            cellEditor = null;
            oldValue = null;
            
        }
        
        /**
         * wjr
         * @param e
         */
        
        public void actionPerformed(ActionEvent e)
        
        {
//System.out.println("aP:");
        }
        
        /*********************************************************************** wjr */
//Instead of having a single vector that will contain the row values that
// are copied or cut, we use a array of vectors - neha
//private	Vector	lineBuffer = null;
        private Vector[] lineBuffers = null;
        
        /*********************************************************************** wjr */
        
        private	void	setRowLabels(int hdrRows, int bodRows)
        
        {
//System.out.println("sRL: ");
            String[] labels = new String[bodRows + hdrRows];
            for (int idx = 0; idx < hdrRows; idx++)
                labels[idx] = " ";
            for (int idx = 0; idx < bodRows; idx++)
                labels[idx + hdrRows] = " " + (idx + 1);
            dataSource.setRowLabels(labels);
        }
        
        /*********************************************************************** wjr */
/*
public	void	deleteRow()
 
{
        if (editRow > -1) {
                dataSource.deleteRows(editRow, 1);
 
                bodRows--;
                setRowLabels(hdrRows, bodRows);
                inputRecord.rowsChanged(bodRows, this);
        }
}
 */
        /*********************************************************************** wjr */
        
        
        public	void	copyRow()
        
        {
            Vector tmpBuffer;
            if (!checkSelection(true)) {
                return;
            }
            //System.out.println("CopyRow:startRow value:"+startRow+" endRow:"+endRow);
            
            //Use startRow - value of the row that has been selected
            // not the editRow which is for selecting cells - neha
            if (startRow > -1) {
                Util.debugPrint(true, "copy row " + startRow);
                Vector cells = dataSource.getCells();
                //lineBuffer = new Vector();
                lineBuffers = new Vector[endRow - startRow + 1];
                for(int i = 0; i < endRow - startRow + 1; i++){
                    lineBuffers[i] = new Vector();
                }
                int k = 0;
                for(int i = startRow;i <= endRow; i++, k++){
                    tmpBuffer = (Vector) cells.elementAt(i);
                    for (int idx = 0; idx < tmpBuffer.size(); idx++) {
                        String str = (String) tmpBuffer.elementAt(idx);
                        Util.debugPrint(true, "copy row " + str);
                        //lineBuffer.add(new String(str));
                        lineBuffers[k].add(str);
                    }
                }//end of outer for loop
            }
        }
        
        /*********************************************************************** wjr */
        
        public	void	cutRow()
        
        {
            if (!checkSelection(true)) {
                return;
            }
            //System.out.println("CutRow:startRow value:"+startRow+" endRow:"+endRow);
            //Use startRow - value of the row that has been selected
            // not the editRow which is for selecting cells - neha
            if (startRow > -1) {
                Util.debugPrint(true, "cut row " + startRow);
//          Vector cells = dataSource.getCells();
//          lineBuffer = (Vector) cells.elementAt(editRow);
                copyRow();
                for(int i = startRow;i <= endRow; i++){
                    dataSource.deleteRows(i, 1);
                    bodRows--;
                }
                setRowLabels(hdrRows, bodRows);
                inputRecord.rowsChanged(bodRows, this);
            }
        }
        
        /*********************************************************************** wjr */
        
        public	void	pasteBeforeRow()
        
        {
            //System.out.println("PasteBeforeRow:startRow value:"+startRow+" endRow:"+endRow);
            if (startRow > -1 && lineBuffers != null) {
                Util.debugPrint(true, "paste row " + startRow + " " + lineBuffers[0].elementAt(0));
                int k = startRow;
                for(int j = 0; j < lineBuffers.length; j++){
                    dataSource.addRow(k, " ", (Vector)lineBuffers[j]);
                    k++;
                    bodRows++;
                }
                setRowLabels(hdrRows, bodRows);
                inputRecord.rowsChanged(bodRows, this);
            }
        }
        
        public	void	pasteAfterRow()
        
        {
            //System.out.println("PasteAfterRow:startRow value:"+startRow+" endRow:"+endRow);
            if (startRow > -1 && lineBuffers != null) {
                Util.debugPrint(true, "paste row " + startRow + " " + lineBuffers[0].elementAt(0));
                int k = startRow;
                for(int j = 0; j < lineBuffers.length; j++){
                    dataSource.addRow(k+1, " ", (Vector)lineBuffers[j]);
                    k++;
                    bodRows++;
                }
                setRowLabels(hdrRows, bodRows);
                inputRecord.rowsChanged(bodRows, this);
            }
        }
        
        /*********************************************************************** wjr */
        
//This method is obsolete - should be deleted later - Neha, 04/19/05
        public	void	insertRow()
        
        {
            if (editRow > -1) {
                Vector cells = dataSource.getCells();
                Vector cello = (Vector) cells.elementAt(editRow);
                Vector newVec = new Vector();
                for (int idx = 0; idx < cello.size(); idx++) {
                    String str = (String) cello.elementAt(idx);
                    newVec.add(str);
                }
                dataSource.addRow(editRow, " ", newVec);
                inputRecord.rowsChanged(++bodRows, this);
                setRowLabels(hdrRows, bodRows);
//		dataSource.setNumRows(dataSource.getNumRows() + 1);
            }
        }
        
        /**
         * wjr
         * @param row
         * @param col
         * @param val
         */
        
        public	void	updateValue(int row, int col, String val)
        
        {
//System.out.println("uV : " + row + " " + col + " " + val);
            Vector cells = dataSource.getCells();
            Vector cello = (Vector) cells.elementAt(row + hdrRows);
            cello.setElementAt(val, col);
        }
        
        /**
         * wjr
         * @return
         */
        
        public	int	getHeaderRowCount() {
            return hdrRows;
        }
        
        /**
         * wjr
         * @param row
         * @param col
         * @return
         */
        
        public	String	getValue(int row, int col) {
            
            Vector cells = dataSource.getCells();
            Vector cello = (Vector) cells.elementAt(row + hdrRows);
            try {
                return (String) cello.elementAt(col);
            } catch (java.lang.ArrayIndexOutOfBoundsException e) {
                return "???";
            }
        }
        /*********************************************************************** neha */
        int startRow = -1;
        int endRow = -1;
        int startCol = -1;
        int endCol = -1;
        boolean showPopupMenu = false;
        /**
         *
         * @param e
         */
        public void select(JCSelectEvent e){
            showPopupMenu = false;
        }
        /**
         *
         * @param e
         */
        public void afterSelect(JCSelectEvent e){
            startRow = e.getStartRow();
            endRow = e.getEndRow();
            startCol = e.getStartColumn();
            endCol = e.getEndColumn();
            //This becomes true only after the entire row is selected
            //If only one or two rows are selected, then it remains false - neha
            showPopupMenu = true;
        }
        /**
         *
         * @param e
         */
        public void beforeSelect(JCSelectEvent e){
            
        }
        
        /**
         * neha
         * @return
         */
        //Return true if the entire row is selected
        public boolean showPopup(){
            boolean retValue = false;
            // //System.out.println("showPopupMenu value:"+showPopupMenu);
            if(showPopupMenu){
           /* Only when the entire row is selected, the startCol and
            * endCol both have a value of -1; If multiple range of cells are
            * selected, then startCol and endCol will have a positive value
            * We take advantage of this here to pick out those instances where only
            * the entire row is selected, to show the popup menu - neha
            */
                //   //System.out.println("startCol:"+startCol+" endCol:"+endCol);
                if(startCol == -1 && endCol == -1)
                    retValue = true;
            }
            return retValue;
        }
        /*********************************************************************** neha */
        /**
         * wjr
         * @param l
         */
        
        public void addMouseListener(MouseListener l) {
            super.addMouseListener(l);
            jctable.addMouseListener(l);
        }
        
        /**
         * wjr
         * @return
         */
        public int getCurrentRow() {
            Util.debugPrint(true, "current cell " + jctable.getCurrentCell());
            return jctable.getCurrentRow();
        }
        
        /**
         * wjr
         * @param msgFlg
         * @return
         */
        
        public boolean checkSelection(boolean msgFlg) {
            Vector scv = getSelectedRows();
            if (scv == null || scv.size() == 0) {
                if (msgFlg) JOptionPane.showMessageDialog(Util.getParentJFrame(this),
                        "No row selected",
                        "Error changing layers",
                        JOptionPane.ERROR_MESSAGE);
                return false;
            }
            return true;
        }
        
        
        private Vector getSelectedRows() {
            
            Collection sc = jctable.getSelectedCells();
            if (sc == null) return null;
            int numCols = jctable.getNumColumns();
            
            //     //System.out.println("Number of Rows:"+jctable.getNumRows());
            //     //System.out.println("Number of Visible Rows:"+jctable.getNumVisibleRows());
            //     //System.out.println("Number of Columns:"+jctable.getNumColumns());
            //     //System.out.println("Number of Visible Columns:"+jctable.getNumVisibleColumns());
            
            
            Vector scv = new Vector();
            for (Iterator sci = sc.iterator(); sci.hasNext(); ) {
                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 */
                //     //System.out.println("Start Column:"+jccr.start_column+"  End Column:"+jccr.end_column);
                //     //System.out.println("Start Row:"+jccr.start_row+"  End Row:"+jccr.end_row);
                if(jccr.start_row < 0 || jccr.end_row < 0)
                    continue;
                if(jccr.start_column < 0 || jccr.end_column >= numCols)
                    jccr = new JCCellRange(jccr.start_row,0,jccr.end_row,numCols);
                
                
                scv.add(jccr);
            }
            
            Collections.sort(scv, new CompareRange());
            
            return scv;
        }
        
        public void setReadonly(boolean readonly){
            for (Object o : jctable.getCellStyles()){
                JCCellStyle style = (JCCellStyle) o;
                style.setEditable(!readonly);
            }
        }
        
        private static class CompareRange extends JCCellRange implements java.util.Comparator {
            
        @Override
            public boolean equals(Object to) {
            if (!(to instanceof JCCellRange)) return false;
                return this.start_row == ((JCCellRange) to).start_row;
            }
            
        @Override
            public int compare(Object o1, Object o2) {
                return ((JCCellRange) o2).start_row - ((JCCellRange) o1).start_row;
            }

        @Override
        public int hashCode() {
            int hash = 3;
            return hash;
        }
        }
        
        /*********************************************************************** wjr */
    }
    
