package usda.weru.erosion;

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;


/*
 * 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 WindDisp extends usda.weru.erosion.gui.WindDisp_n {

	private static final int numRows = 4;
	private static final int numCols = 17;		
//	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 static 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 static 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", "Total"};
									
//	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 String[] monthNames = {"January", "February", "March", "April", "May", "June",
//            "July", "August", "September", "October", "November", "December"};
            
    private static final String[] rowLbls = {"Threshold (m/s)", "Winds > Thresh (%)", "Dir Prob (%)", "Thresh Prob (%)"};
    
    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 WindDisp.
     *
     * @arg file name for wind data file
     * */
    public WindDisp(String fileName) {
//System.out.println("WD: filename " + 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";
            }
        }
        loadWindStationData(fileName);
		cellData[0][0] = "" + dbVec.size();
		cellData[0][1] = "" + staVec.size();
        DataWrapper dw = new DataWrapper(numRows, numCols, rowLbls, dirNames, cellData);
		jcTable.setMaxWidth(JCTableEnum.ALLCELLS, 70);
		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);
        jcTable.setData(dw);
    }

    public WindDisp() {
////System.out.println("WD: filename " + 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";
            }
        }
//        loadWindStationData(fileName);
		cellData[0][0] = "" + dbVec.size();
		cellData[0][1] = "" + staVec.size();
        DataWrapper dw = new DataWrapper(numRows, numCols, rowLbls, dirNames, cellData);
		jcTable.setMaxWidth(JCTableEnum.ALLCELLS, 70);
		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 WindDisp(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) HT_stations.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;
		}

        @Override
		public String toString() {
			return statDesc;
		}

        @Override
		public int compareTo(Object compTo) {
			return statDesc.compareTo(((StationRec) compTo).statDesc);
		}
        
        @Override
        public boolean equals(Object o) {
            if (!(o instanceof StationRec)) return false;
            StationRec sr = (StationRec) o;
            return this.statDesc.equals(sr.statDesc);
        }

        @Override
        public int hashCode() {
            int hash = 5;
            hash = 71 * hash + (this.statDesc != null ? this.statDesc.hashCode() : 0);
            hash = 71 * hash + this.statIdx;
            return hash;
        }
	}
	
	private Hashtable HT_stations = new Hashtable();
	private Vector staList = null;
	
    public void loadWindStationData(String fileName) {
//System.out.println("WD_lD: filename " + fileName);        

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

		if (staList == null) {
			staList = new Vector();
                        BufferedReader in = null;
			try {
////System.out.println("WD_lD: " + fileName);
				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) {
////System.out.println("WD_lD: " + inpStr);						
						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();
//							inpStr = "";
							while (st.hasMoreTokens()) {
                                sb.append(st.nextToken());
                                sb.append(" ");
//								inpStr += st.nextToken() + " ";
							}
//							StationRec sr = new StationRec(stationID, inpStr, staCnt);
							StationRec sr = new StationRec(stationID, sb.toString().trim(), staCnt);
							staList.add(sr);
							HT_stations.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{
                                if(in != null){
                                    in.close();
                                }
                            }
                            catch(Exception e){
                                e.printStackTrace();
                            }
                        }
			Collections.sort(staList);
		}
//		for (Iterator it = staList.iterator(); it.hasNext(); ) {
//			JCB_stationName.addItem(it.next());
//		}
//		JCB_month.removeAllItems();
//		for (int mdx = 0; mdx < monthNames.length; mdx++) {
//			JCB_month.addItem(monthNames[mdx]);
//		}
//		JCB_month.removeItemAt(0);
//		JCB_month.setSelectedIndex(0);
	}

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

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

	public int findStation(String stationID) {
		stationID = stationID.trim();
		StationRec rc = (StationRec) HT_stations.get(stationID);
		//System.out.println("WGD_fS: " + rc + " " + stationID + " " + HT_stations.size());
		return rc.statIdx;
	}

	public 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;

	public double[][] getWindTimes() {
		return windTimes.clone();
	}
	
	public 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;

	public double[][][] getCumProb() {
		return cumProb.clone();
	}
	
	public 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);
		}
	}

	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;
//	}

	double [] inpWS;
	double [][] inpPT;
	double [][] inpWT;

	private void changeDisplayMonth() {
//		if (JCB_month.getItemCount() == 13) {
//			JCB_month.removeItemAt(0);
//			JCB_month.setSelectedIndex(0);
////System.out.println("WD_cDM: remove item 1");			
//		}
		int mdx = JCB_month.getSelectedIndex();
//		if (mdx == 0) mdx++;
//		mdx--;
//System.out.println("WD_cDM: " + JCB_month.getItemCount());
		java.text.NumberFormat nf = java.text.NumberFormat.getNumberInstance();
		nf.setMaximumFractionDigits(2);
		nf.setMinimumFractionDigits(2);

		double dirTotal = 0.0;
		double probTotal = 0.0;
		for (int ddx = 0; ddx < inpWS.length; ddx++) {
			//System.out.print(" " + inpWS[ddx]);			
			cellData[0][ddx] = "" + inpWS[ddx];
			cellData[1][ddx] = "" + nf.format(inpPT[mdx][ddx]*100);
			cellData[2][ddx] = "" + nf.format(inpWT[ddx][mdx]);
			cellData[3][ddx] = "" + nf.format(inpPT[mdx][ddx]*inpWT[ddx][mdx]);
			dirTotal += inpWT[ddx][mdx];
			probTotal += inpPT[mdx][ddx]*inpWT[ddx][mdx];
		}
		cellData[0][inpWS.length] = ""; //nf.format(dirTotal);
		cellData[1][inpWS.length] = ""; //nf.format(dirTotal);
		cellData[2][inpWS.length] = nf.format(dirTotal);
		cellData[3][inpWS.length] = nf.format(probTotal);
		DataWrapper dw = new DataWrapper(numRows, numCols, rowLbls, dirNames, cellData);
		jcTable.setData(dw);
		//System.out.println();		
	}
	
	public void setCellData(double[] windSpeeds, double [][] probTable, double[][] windTimes) {
		inpWS = windSpeeds.clone();
		inpPT = probTable.clone();
		inpWT = windTimes.clone();
		changeDisplayMonth();
	}
	
	protected void JCB_monthActionPerformed(java.awt.event.ActionEvent evt) {
		changeDisplayMonth();
	}

	protected void JB_prevActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_JB_prevActionPerformed
		int idx = JCB_month.getSelectedIndex();
		if (idx == 0) return;
		JCB_month.setSelectedIndex(idx-1);
	}//GEN-LAST:event_JB_prevActionPerformed

	protected void JB_nextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_JB_nextActionPerformed
		int idx = JCB_month.getSelectedIndex();
		if (idx == 11) return;
		JCB_month.setSelectedIndex(idx+1);
	}//GEN-LAST:event_JB_nextActionPerformed

    protected void formComponentResized(java.awt.event.ComponentEvent evt) {        
        super.formComponentResized(evt);;
        //System.out.println("WD_fCR: " + evt);
        //System.out.println("WD_fCR: " + jcTable.getSize());
        java.awt.Dimension jctDim = jcTable.getSize();
        int wid = ((javax.swing.JFrame) evt.getSource()).getSize().width;
        jctDim.width = wid - 30;
        jcTable.setSize(jctDim);
        //System.out.println("WD_fCR: " + jcTable.getSize());
    }                                     
}
