package usda.weru.util;

import com.klg.jclass.table.beans.DataWrapper;
import com.klg.jclass.table.*;

import de.schlichtherle.io.File;
import de.schlichtherle.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.*;
import java.text.NumberFormat;
import org.apache.log4j.Logger;


/*
 * WindGenDisp.java
 *
 * Created on July 26, 2005, 1:52 PM
 *
 * To change this template, choose Tools | Options and locate the template under
 * the Source Creation and Management node. Right-click the template and choose
 * Open. You can then make changes to the template in the Source Editor.
 */

/**
 *
 * @author wjr
 */
public class WindGenDisp extends usda.weru.util.gui.WindGen_n {
    private static final Logger logger = Logger.getLogger(WindGenDisp.class);
	private static final int numRows = 5;
	private static final int numCols = 12;		
//	private double threshold = 8.0;
	private double threshold = 8.0;
	private static final int numMonths = 12;
	private static final int numDirections = 16;
	
	/* The boundaries array does not have a 0.5 category which the
	 * fortran program does have. This is left out so that the 1.5
	 * average corresponds to the first entry in the wind speed table.
	 */
	private final double[] boundaries = {1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5,
										9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5,
										18.5, 19.5, 20.5, 25.5, 30.5, 35.5, 40.5, 45.5};

	private final String[] dirNames = {"N-0", "NNE-22", "NE-45", "ENE-67", "E-90", "ESE-112", "SE-135", "SSE-157",
										"S-180", "SSW-202", "SW-225", "WSW-247", "W-270", "WNW-292", "NW-315", "NNW-337"};
									
//	private final String[] dirNames = {"North-0", "NNE-22.5", "NE-45", "ENE-67.5", "East-90", "ESE-112.5", "SE-135", "SSE-157.5",
//	"South-180", "SSW-202.5", "SW-225", "WSW-247.5", "West-270", "WNW-292.5", "NW-315", "NNW-337.5"};


	private static final int WIND_SPEED = 0;
	private static final int WIND_ENERGY = 1;
	private static final int WIND_FRACT = 2;
	private static final int WIND_PREPOND = 3;
	private static final int WIND_DIRECTION = 4;
	
    private String[] monthNames = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
            
    private String[] rowLbls = {"Winds > Threshold", "Energy kJ/m^2/day", "Monthly Percent", "Preponderance", "PWED"};
    
    private String[][] cellData = null;

	static Vector dbVec = new Vector();
	static Vector staVec = new Vector();
	double elevation = 1000.0; // default elevation in meters
	double temperature = 20.0; // default temperature Celsius
	double stepSize = 0.1; // width of integrating box
    
    /*
     * Creates a new instance of WindGenDisp.
     *
     * @arg file name for wind data file
     * */
    public WindGenDisp(String fileName) {
        cellData = new String[numRows][];
        for (int rdx = 0; rdx < cellData.length; rdx++) {
            cellData[rdx] = new String[numCols];
            for (int cdx = 0; cdx < cellData[rdx].length; cdx++) {
                cellData[rdx][cdx] = "a";
            }
        }
        loadData(fileName);
		cellData[0][0] = "" + dbVec.size();
		cellData[0][1] = "" + staVec.size();
        DataWrapper dw = new DataWrapper(numRows, numCols, rowLbls, monthNames, cellData);
		jcTable.setMaxWidth(JCTableEnum.ALLCELLS, 50);
		jcTable.setSize(720,140);
		JCCellStyle cs = new JCCellStyle();
		cs.setHorizontalAlignment(JCTableEnum.RIGHT);
		cs.setEditable(false);
		java.awt.Color col = new java.awt.Color(1.0f, 1.0f, 1.0f);
		cs.setBackground(col);
		JCCellRange cr = new JCCellRange(0, 0, numRows-1, numCols-1);
		jcTable.setCellStyle(cr, cs);
		JCCellStyle cs2 = new JCCellStyle();
		cs2.setHorizontalAlignment(JCTableEnum.RIGHT);
		cs2.setEditable(false);
		col = new java.awt.Color(1.0f, 1.0f, 1.0f);
		cs2.setBackground(col);
		java.awt.Font cf = cs2.getFont();
		cf = cf.deriveFont((float) (cf.getSize()*0.8));
		cs2.setFont(cf);
		cs2.setVerticalAlignment(cs2.BOTTOM);
		JCCellRange cr2 = new JCCellRange(WIND_DIRECTION, 0, WIND_DIRECTION, numCols-1);
		jcTable.setCellStyle(cr2, cs2);
        jcTable.setData(dw);
    }

	/*
	 * Constructor
	 *
	 * @arg args is String array -- args[0] is station number, args[1] is
	 * file name
	 */
	
	public WindGenDisp(String[] args) {
////System.out.println("WGD_WGD: " + java.lang.management.MemoryUsage.toString());
//		if (args.length > 2) { // threshold specified
//			threshold = Double.parseDouble(args[2]);
//		}
		this(args[1]);
		try {
//			//System.out.println("WGD: htsize " + args[0] + HT_stations.get(args[0]) + " " + HT_stations.size());
			StationRec rc = (StationRec) c_stattionMap.get(args[0]);
			if (rc != null) JCB_stationName.setSelectedItem(rc);
		} catch (ArrayIndexOutOfBoundsException e) {
			//System.err.println("WGD: " + ">" + args[0] + "<" + e);
			e.printStackTrace();
		}
	}

	static class StationRec implements Comparable {
//		String statID = "000000";
		String statDesc = "desc";
		int statIdx = 0;

		StationRec(String id, String desc, int stat) {
//			statID = id;
			statDesc = desc;
			statIdx = stat;
		}

		public String toString() {
			return statDesc;
		}

		public int compareTo(Object compTo) {
			return statDesc.compareTo(((StationRec) compTo).statDesc);
		}

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 13 * hash + (this.statDesc != null ? this.statDesc.hashCode() : 0);
            return hash;
        }

        public boolean equals(Object obj) {
            if (!(obj instanceof StationRec)) return false;
            return this.statDesc.equals(obj.toString());
        }
    }
	
	private Map <String, StationRec> c_stattionMap = new Hashtable<String, StationRec> ();
	private List <StationRec> c_stationList = null;
	
    private void loadData(String fileName) {

		int staCnt = 1;
//		Vector staList = new Vector();

		if (c_stationList == null) {
			c_stationList = new Vector<StationRec>();
                        BufferedReader in = null;
			try {

				in = new BufferedReader(new FileReader(new File(fileName)));
//				new File("C:/weps/weps1.install/db/wind_gen", "wind_test.wdb")));

				while (true) {
					String inpStr;
					while((inpStr = in.readLine())!=null) {
						if (inpStr.length() == 0) continue;
						if (inpStr.charAt(0) != '#') {
							staVec.add(inpStr);
							continue;
						} else {
							StringTokenizer st = new StringTokenizer(inpStr, " ");
							st.nextToken();
							String stationID = st.nextToken();
                            StringBuffer sb = new StringBuffer();
							while (st.hasMoreTokens()) {
								sb.append(st.nextToken() + " ");
							}
							StationRec sr = new StationRec(stationID, sb.toString(), staCnt);
							c_stationList.add(sr);
							c_stattionMap.put(stationID, sr);
							dbVec.add(staVec);
							staVec = new Vector();
							staCnt++;
						}
					}
					dbVec.add(staVec);
					if (inpStr == null) break;
				}
			} catch (IOException e) {
				//System.err.println("WGD_lD: " + e);
			}
                        finally{
                            try{
                                in.close();
                            }
                            catch(Exception e){
                                logger.error("Error closing file stream.", e);
                            }
                        }
			Collections.sort(c_stationList);
		}
		for (Iterator it = c_stationList.iterator(); it.hasNext(); ) {
			JCB_stationName.addItem(it.next());
		}
	}

	private ConfigData cd = null;
	
    public static void main(String[] args) {

		WindGenDisp wgd = null;
		if (args.length > 0) {
			wgd = new WindGenDisp(args);
		} else {
//			wgd = new WindGenDisp("C:/weps/weps1.install/db/wind_gen/wind_test.wdb");
			wgd = new WindGenDisp("db/wind_gen/wind_gen_his_upper_US.wdb");
            
		}
        wgd.setVisible(true);
    }

	private void parseElevation(int staIdx) {
		Vector selVec = (Vector) dbVec.get(staIdx);
		String inpLin = (String) selVec.get(0); //elevation in first line
		StringTokenizer st = new StringTokenizer(inpLin);
		for (int edx = 0; st.hasMoreTokens() && edx < 6; edx++) st.nextToken();
		String elevStr = st.nextToken();
		JL_Elevation.setText(elevStr);
		elevation = Double.parseDouble(elevStr);
	}

	private double[][] windTimes = null;
	
	private void parseWindTimes(int staIdx) {
		Vector selVec = (Vector) dbVec.get(staIdx);
		windTimes = new double[numDirections][];
		for (int ddx = 0; ddx < numDirections; ddx++) {
			String[] inpArr = new String[numMonths];
			windTimes[ddx] = new double[numMonths];
			String inpLin = (String) selVec.get(ddx+1); //skip the first line, use next 16
			StringTokenizer st = new StringTokenizer(inpLin);
			for (int mdx = 0; st.hasMoreTokens(); mdx++) {
				inpArr[mdx] = st.nextToken();
				if (ddx == 0) {
					cellData[ddx][mdx] = inpArr[mdx];
				}
				windTimes[ddx][mdx] = Double.parseDouble(inpArr[mdx]);
			}
		}
	}

	private double[][][] cumProb = null;
	private double[][][] intvProb = null;

	private void parseWindSpeeds(int staIdx) {
		Vector selVec = (Vector) dbVec.get(staIdx);
		cumProb = new double[numMonths][][];
		intvProb = new double[numMonths][][];
		for (int mdx = 0; mdx < numMonths; mdx++) {
			cumProb[mdx] = new double[numDirections][];
			intvProb[mdx] = new double[numDirections][];
			for (int ddx = 0; ddx < numDirections; ddx++) {

				// load cumulative probability curve for each direction
				String inpLin = (String) selVec.get(mdx*numDirections+ddx+18); //skip the direction data, use next 16*12
				StringTokenizer st = new StringTokenizer(inpLin);
				int numTok = st.countTokens();
				String[] inpArr = new String[numTok];
				cumProb[mdx][ddx] = new double[numTok+2];
				intvProb[mdx][ddx] = new double[numTok+2];
				for (int pdx = 0; st.hasMoreTokens(); pdx++) {
					inpArr[pdx] = st.nextToken();
					if (mdx ==0 && ddx == 0 && pdx < cellData[1].length) {
						cellData[1][pdx] = inpArr[pdx];
					}
					cumProb[mdx][ddx][pdx] = Double.parseDouble(inpArr[pdx]);
				}
				cumProb[mdx][ddx][numTok] = 1.0; // put 1 in last 2 positions
				cumProb[mdx][ddx][numTok+1] = 1.0;

				// convert cumulative curve to interval values
				intvProb[mdx][ddx] = new double[numTok+2];
				for (int pdx = 1; pdx < cumProb[mdx][ddx].length; pdx++) {
					try {
						double deltaY = cumProb[mdx][ddx][pdx] - cumProb[mdx][ddx][pdx-1];
						double deltaX = boundaries[pdx] - boundaries[pdx-1]; 
						intvProb[mdx][ddx][pdx] = deltaY / deltaX;
					} catch (ArrayIndexOutOfBoundsException f) {
						// wind prob array > # of boundaries -- skip it
						//System.err.println("WGD_pWD: " + f);
					}
				}
			}
		}
	}

	private void calcThreshold() {
		int tdx = 0;

		while (boundaries[tdx] < threshold && tdx < boundaries.length) tdx++;

		for (int mdx = 0; mdx < numMonths; mdx++) {
			double overThreshold = 0.0;
			for (int ddx = 0; ddx < numDirections; ddx++) {
				try {
					// find interpolation fraction between two boundary
					// points
					double interp = (threshold - boundaries[tdx-1]) /
									(boundaries[tdx] - boundaries[tdx-1]);
					// calculate the interpolated value for winds over
					// theshold and multiply by the fraction of time
					// the wind is coming from that direction and
					// normalize by dividing by number of wind
					// directions (16);
					double windSpeedProb = 1 - (cumProb[mdx][ddx][tdx-1] +
						interp*(cumProb[mdx][ddx][tdx] - cumProb[mdx][ddx][tdx-1]));
					double addOn = windSpeedProb * windTimes[ddx][mdx] / 100;
					overThreshold += addOn;
						
				} catch (ArrayIndexOutOfBoundsException e) {
					// if array doesn't have any winds over threshold,
					// just skip that direction
				}
			}

			NumberFormat cf = NumberFormat.getNumberInstance(Locale.US);
			cf.setMaximumFractionDigits(1);
			cf.setMinimumFractionDigits(1);

			cellData[WIND_SPEED][mdx] = cf.format(overThreshold * 100);
		}
	}

	/**
	 ** Calculate erosive wind energy by integrating wind probability
	 ** distribution greater than theshold wind speed.
	 */
	
	private void calcEWP() {
		int tdx = 0;
		// magic formula for air density based upon elev and temp
		double airDensity = 348.56*(
					(1.013 - 0.1183*(elevation/1000) + 
                    0.0048*(elevation/1000)*(elevation/1000)) /
									(temperature + 273.1));
//		double weFactor = 0.1*3.6*24*0.5;
		double weFactor = 3.6*24*0.5;
////System.out.println("WGD_cEWP: air density " + airDensity);        
		NumberFormat cf = NumberFormat.getNumberInstance(Locale.US);
		cf.setMaximumFractionDigits(0);
		cf.setMinimumFractionDigits(0);

		while (boundaries[tdx] < threshold && tdx < boundaries.length) tdx++;

		double[] monWindEnrgArr = new double[numMonths];
		double totalWindEnrg = 0;

		// calc total & monthly energies by month
		for (int mdx = 0; mdx < numMonths; mdx++) { 
			double monWindEnrg = 0.0;
			// calc wind enrg by direction
			for (int ddx = 0; ddx < numDirections; ddx++) {

// calculate wind enrg from short first interval
				double dirWindEnrg = 0.0;
				int ntdx = tdx;
				if (ntdx >= intvProb[mdx][ddx].length) continue;

				double curPos = threshold;

				if ((threshold % stepSize) > 0.000000001) {
					double currentStepSize = stepSize - (threshold % stepSize);
					curPos += currentStepSize / 2;
////System.out.println("WGD_cWEP: " + mdx + " " + ddx + " " + ntdx + " " + intvProb[mdx][ddx].length);					
					double stepValue = intvProb[mdx][ddx][ntdx] * (curPos - threshold) * curPos * curPos * currentStepSize;
//if (ddx == 0 && mdx == 0) //System.out.println("WGD_cWEP: " + stepValue);
					dirWindEnrg += stepValue;
					curPos += currentStepSize / 2;
					}

				curPos +=  stepSize / 2;

				try {

					int stpIdx = 0;
					while (ntdx < intvProb[mdx][ddx].length) {
						while (curPos <= boundaries[ntdx]) {
							double stepValue = intvProb[mdx][ddx][ntdx] * (curPos - threshold) * curPos * curPos * stepSize;
//if (ddx == 0 && mdx == 0) //System.out.println("WGD_cWEP: " + stepValue);
							dirWindEnrg += stepValue;
							curPos += stepSize;
							stpIdx++;
						}
						ntdx++;
					}
				} catch (ArrayIndexOutOfBoundsException e) {
					//System.err.println("WGD_cWEP: AIOOBE");					
				}
				monWindEnrg += weFactor * airDensity * dirWindEnrg * windTimes[ddx][mdx] / 100;
			}
			cellData[WIND_ENERGY][mdx] = cf.format(monWindEnrg);
			monWindEnrgArr[mdx] = monWindEnrg;
			totalWindEnrg += monWindEnrg;
		}

		for (int mdx = 0; mdx < numMonths; mdx++) {
			cellData[WIND_FRACT][mdx] = cf.format(monWindEnrgArr[mdx] * 100 / totalWindEnrg);
		}
		JL_avgEng.setText(cf.format(totalWindEnrg/12));
	}

	/**
	 ** Calculate erosive wind energy by integrating wind probability
	 ** distribution greater than theshold wind speed.
	 */

	private void calcPrevailingWind() {
		int tdx = 0;

		NumberFormat cf = NumberFormat.getNumberInstance(Locale.US);
		cf.setMaximumFractionDigits(1);
		cf.setMinimumFractionDigits(1);

		// find threshold boundary
		while (boundaries[tdx] < threshold && tdx < boundaries.length) tdx++;

		double[][] windErosionForces = new double[numMonths][numDirections];
		double[][] paraForces = new double[numMonths][numDirections];
		double[][] perpForces = new double[numMonths][numDirections];
		double[][] posvForces = new double[numMonths][numDirections];
		double[][] ratioForces = new double[numMonths][numDirections];
		
		for (int mdx = 0; mdx < numMonths; mdx++) {

		// calc wind forces by month and direction
			for (int ddx = 0; ddx < numDirections; ddx++) {
				try {
					double firstFrac = (boundaries[tdx] - threshold) / (boundaries[tdx] - boundaries[tdx-1]);
					windErosionForces[mdx][ddx] = firstFrac * Math.pow(((boundaries[tdx] + threshold) / 2), 3) * intvProb[mdx][ddx][tdx] * windTimes[ddx][mdx];
////System.out.println("WGD_cPW: " + firstFrac + " " +  Math.pow(((boundaries[tdx] + threshold) / 2), 3) + " " + intvProb[mdx][ddx][tdx] + " " +
//				  windTimes[ddx][mdx] + " " +
//				  windErosionForces[mdx][ddx]);
////System.out.println("WGD_cPW: 1 " + windErosionForces[mdx][ddx]);
					for (int pdx = tdx+1; pdx < intvProb[mdx][ddx].length; pdx++) {
//if (mdx == 0) //System.out.println("WGD_cPW: " + windErosionForces[mdx][ddx]);	
						windErosionForces[mdx][ddx] += Math.pow(((boundaries[pdx] + boundaries[pdx-1]) / 2), 3) * intvProb[mdx][ddx][pdx] * windTimes[ddx][mdx];
					}
////System.out.println("WGD_cPW: 2 " + windErosionForces[mdx][ddx]);
				} catch (ArrayIndexOutOfBoundsException e) {
					// simply means we have run out of probs
				}
						 
////System.out.println("WGD_cPW: wEF " + monthNames[mdx] + " " + ddx + " " + cf.format(windErosionForces[mdx][ddx]));
			}

			for (int ddx = 0; ddx < numDirections; ddx++) {
				for (int adx = 0; adx < numDirections; adx++) {
					double cos = Math.cos((adx - ddx) * 22.5 * Math.PI / 180);
					double sin = Math.sin((adx - ddx) * 22.5 * Math.PI / 180);
					paraForces[mdx][ddx] += windErosionForces[mdx][adx] * Math.abs(cos);
					perpForces[mdx][ddx] += windErosionForces[mdx][adx] * Math.abs(sin);
////System.out.println("WGD_cPW: wEF " + monthNames[mdx] + " " + ddx + " " + adx + " " + cf.format(windErosionForces[mdx][adx]) +
//				  " " + cf.format(cos) + " " + cf.format(sin));
					if (cos > 0) {
						posvForces[mdx][ddx] += windErosionForces[mdx][adx] * cos;
					}
				}
				try {
					ratioForces[mdx][ddx] = paraForces[mdx][ddx] / perpForces[mdx][ddx];
				} catch (Exception f) {
					ratioForces[mdx][ddx] = Double.NaN;
				}
			}

			double maxRatio = 0.0;
			int maxDirection = 0;
			for (int ddx = 0; ddx < numDirections; ddx++) {
////System.out.println("WGD_cP: pF " + monthNames[mdx] + " " + ddx +
//				   " " + cf.format(paraForces[mdx][ddx]) +
//				   " " + cf.format(perpForces[mdx][ddx]) +
//				   " " + cf.format(posvForces[mdx][ddx]) +
//				   " " + cf.format(paraForces[mdx][ddx] / perpForces[mdx][ddx]));
				if (maxRatio < ratioForces[mdx][ddx]) {
					maxRatio = ratioForces[mdx][ddx];
					maxDirection = ddx;
				}
			}
////System.out.println("WGD_cP: mD " + monthNames[mdx] + " " + maxDirection);
			if (posvForces[mdx][maxDirection] * 2 < paraForces[mdx][maxDirection]) {
				maxDirection = (maxDirection + numDirections / 2) % numDirections;
			}

			cellData[WIND_PREPOND][mdx] = cf.format(maxRatio);
			cellData[WIND_DIRECTION][mdx] = dirNames[maxDirection];
		}
	}

	private void setThreshold() {
		JL_Threshold.setText(threshold + " m/s ");
	}
	
	private String[][] getStationData(int staIdx) {
		setThreshold();
		parseElevation(staIdx);
		parseWindTimes(staIdx);
		parseWindSpeeds(staIdx);
		calcThreshold();
		calcEWP();
		calcPrevailingWind();
		return cellData;
	}

	protected void JCB_stationNameActionPerformed(java.awt.event.ActionEvent evt) {
////System.out.println("WGD_sNAP: " + evt);		
		int sdx = JCB_stationName.getSelectedIndex();
//		String selStr = (String) JCB_stationName.getSelectedItem();
		if (sdx == 0) {
			JCB_stationName.setSelectedIndex(1); //don't allow 0 because no data is there
		}
		StationRec sr = (StationRec) JCB_stationName.getSelectedItem();
		sdx = sr.statIdx;
		cellData = getStationData(sdx);
		DataWrapper dw = new DataWrapper(numRows, numCols, rowLbls, monthNames, cellData);
		jcTable.setData(dw);
	}

	public static String parseWinCmd(String inpStr) {
		StringTokenizer st = new StringTokenizer(inpStr);
		String fileToken = null;
		while (st.hasMoreTokens()) {
			fileToken = st.nextToken();
			if (fileToken.startsWith("-f") || fileToken.startsWith("-F")) break;
			fileToken = "";
		}
//		if (fileToken.length() == 0) return "C:/weps/weps1.install/db/wind_gen/wind_test.wdb";
//		if (fileToken.length() == 0) return "C:/weps/weps1.install/db/wind_gen/wind_gen_his.wdb";

		if (fileToken.length() > 2) return fileToken.substring(2);

		if (st.hasMoreTokens()) return st.nextToken();

		return "C:/weps/weps1.install/db/wind_gen/wind_gen_his.wdb";
		
	}

	protected void JTF_thesholdActionPerformed(java.awt.event.ActionEvent evt) {
////System.out.println("WGD_tAP: " + evt);
		String valStr = JTF_threshold.getText();
		double thres = Double.parseDouble(valStr);
		if (thres < 2 || thres > boundaries[boundaries.length-1]) {
			javax.swing.JOptionPane.showMessageDialog(this,
										  "Number specified is out of range\n" +
											  "must be between 2 & " + boundaries[boundaries.length-1],
											  "Number out of range",
											  javax.swing.JOptionPane.ERROR_MESSAGE);
			NumberFormat cf = NumberFormat.getNumberInstance(Locale.US);
			cf.setMaximumFractionDigits(0);
			cf.setMinimumFractionDigits(0);
			JTF_threshold.setText(cf.format(threshold));
			return;
		}
		threshold = thres;
		StationRec sr = (StationRec) JCB_stationName.getSelectedItem();
		int sdx = sr.statIdx;
		cellData = getStationData(sdx);
		DataWrapper dw = new DataWrapper(numRows, numCols, rowLbls, monthNames, cellData);
		jcTable.setData(dw);
	}

	protected void JTF_thresholdFocusLost(java.awt.event.FocusEvent evt) {
		String valStr = JTF_threshold.getText();
		double thres = Double.parseDouble(valStr);
		if (thres < 2 || thres > boundaries[boundaries.length-1]) {
			javax.swing.JOptionPane.showMessageDialog(this,
				"Number specified is out of range\n" +
				"must be between 2 & " + boundaries[boundaries.length-1],
				"Number out of range",
				javax.swing.JOptionPane.ERROR_MESSAGE);
			NumberFormat cf = NumberFormat.getNumberInstance(Locale.US);
			cf.setMaximumFractionDigits(0);
			cf.setMinimumFractionDigits(0);
			JTF_threshold.setText(cf.format(threshold));
			return;
		}
		threshold = thres;
		try {
			StationRec sr = (StationRec) JCB_stationName.getSelectedItem();
			int sdx = sr.statIdx;
			cellData = getStationData(sdx);
			DataWrapper dw = new DataWrapper(numRows, numCols, rowLbls, monthNames, cellData);
			jcTable.setData(dw);
		} catch (java.lang.ClassCastException c) {
			// lost focus before a station was selected
		}
	}

}
