package usda.weru.weps;

import java.beans.*;
import javax.help.*;
import usda.weru.util.*;


public class RegPanel extends usda.weru.weps.gui.RegPanel_n implements PropertyChangeListener {

    private static final long serialVersionUID = 1L;

    public static final String SHAPE_RECTANGLE = "rectangle";
    public static final String SHAPE_SQUARE = "square";
    public static final String SHAPE_CIRCLE = "circle";
    public static final String SHAPE_HALF_CIRCLE_KIND = "half_circle";
    public static final String SHAPE_HALF_CIRCLE_V_KIND = "half_circle_v";
    public static final String SHAPE_HALF_CIRCLE_VE = "half_circle_ve";
    public static final String SHAPE_HALF_CIRCLE_VW = "half_circle_vw";
    public static final String SHAPE_HALF_CIRCLE_H_KIND = "half_circle_h";
    public static final String SHAPE_HALF_CIRCLE_HN = "half_circle_hn";
    public static final String SHAPE_HALF_CIRCLE_HS = "half_circle_hs";
    public static final String SHAPE_QUARTER_CIRCLE_KIND = "quarter_circle";
    public static final String SHAPE_QUARTER_CIRCLE_NE = "quarter_circle_ne";
    public static final String SHAPE_QUARTER_CIRCLE_SE = "quarter_circle_se";
    public static final String SHAPE_QUARTER_CIRCLE_SW = "quarter_circle_sw";
    public static final String SHAPE_QUARTER_CIRCLE_NW = "quarter_circle_nw";
    protected static final String[] shapesComboBox = {"Rectangle", "Square", "Circle", "Half Circle VE", "Half Circle VW", "Half Circle HS", "Half Circle HN", "Quarter Circle NE", "Quarter Circle SE", "Quarter Circle SW", "Quarter Circle NW"};
    protected static final String[] shapesRunFile = {SHAPE_RECTANGLE, SHAPE_SQUARE, SHAPE_CIRCLE, SHAPE_HALF_CIRCLE_VE, SHAPE_HALF_CIRCLE_VW, SHAPE_HALF_CIRCLE_HS, SHAPE_HALF_CIRCLE_HN, SHAPE_QUARTER_CIRCLE_NE, SHAPE_QUARTER_CIRCLE_SE, SHAPE_QUARTER_CIRCLE_SW, SHAPE_QUARTER_CIRCLE_NW};

    String measurementUnits = Util.SIUnits;
    protected String c_shape = SHAPE_RECTANGLE;
    protected double Angle = 0;
    protected final ConvertedValue cXLen = new ConvertedValue(Util.SIUnits, "meter");
    protected final ConvertedValue cYLen = new ConvertedValue(Util.SIUnits, "meter");
    protected final ConvertedValue cRadius = new ConvertedValue(Util.SIUnits, "meter");
    protected final ConvertedValue cArea = new ConvertedValue(Util.SIUnits, "m^2");
    protected double lengthRatio = 1; // = x / y
    
    protected final int USER_INPUT_MODE_AREA = 1;
    protected final int USER_INPUT_MODE_LENGTH = 2;
    protected int userInputMode = -1;
    
    protected boolean suspendProperyChange = false;
    
    class regPanelPropChange extends PropertyChangeSupport {

        private static final long serialVersionUID = 1L;
        RegPanel rp;
        
        public regPanelPropChange(Object o) {
            super(o);
            rp = (RegPanel)o;
        }
        
        public void firePropertyChangeSkipThis(String propertyName, Object oldValue, Object newValue) {
            boolean spcSave = rp.suspendProperyChange;
            rp.suspendProperyChange = true;
            super.firePropertyChange(propertyName, oldValue, newValue);
            rp.suspendProperyChange = spcSave;
        }
    }
    protected final regPanelPropChange changes = new regPanelPropChange(this);


    public RegPanel() {
        super();
        JP_main.setVisible(true);
        for (String shapesComboBox1 : shapesComboBox) {
            JCB_Shape.addItem(shapesComboBox1);
        }

        cXLen.setValue(0);
        cYLen.setValue(0);
        cRadius.setValue(0);
        cArea.setValue(0);

        //Add units for US measurement system
        cXLen.addDisplayUnits(Util.USUnits, "foot");
        cYLen.addDisplayUnits(Util.USUnits, "foot");
        cRadius.addDisplayUnits(Util.USUnits, "foot");
        cArea.addDisplayUnits(Util.USUnits, "acre");
        cArea.addDisplayUnits(Util.SIUnits, "hectare");

        displayFields();
        addHelp();
        
        setUserInputMode(USER_INPUT_MODE_AREA);
        changes.addPropertyChangeListener(this);
    }

    public RegPanel(String sTitle) {
        this();
        setTitle(sTitle);
    }

     
    @Override
    protected void setItemInShapeCombo (String name) {
        suspendProperyChange = true;
        super.setItemInShapeCombo(name);
        suspendProperyChange = false;
    }
   
    @Override
    public void addPropertyChangeListener(PropertyChangeListener l) {
        changes.addPropertyChangeListener(l);
    }

    @Override
    public void removePropertyChangeListener(PropertyChangeListener l) {
        changes.removePropertyChangeListener(l);
    }

    protected int convertComboShapeToIndex(String shapeFromCombo) {
        for (int i = 0; i < shapesComboBox.length; i++) {
            if (shapeFromCombo.equals(shapesComboBox[i])) {
                return i;
            }
        }
        return 0;
    }

    protected int convertRunFileShapeToIndex(String shapeFromCombo) {
        for (int i = 0; i < shapesRunFile.length; i++) {
            if (shapeFromCombo.equals(shapesRunFile[i])) {
                return i;
            }
        }
        return 0;
    }

    protected boolean isShapeKind(String kind) {
        return isShapeKind (c_shape, kind);
    }

    protected boolean isShapeKind(String test, String kind) {
        return (test != null) ? test.contains(kind) : false;
    }
    
    protected boolean isShape(String test) {
        return isShape(test, c_shape);
    }

    protected static boolean isShape(String test, String against) {
        if (test == null || against == null) {
            return false;
        }
        return against.equals(test);
    }

    private void addHelp() {
        CSH.setHelpIDString(JP_main, "regPanel_html");
        CSH.setHelpIDString(JL_shape, "regShape_html");
        CSH.setHelpIDString(JCB_Shape, "regShape_html");
        CSH.setHelpIDString(JL_xlength, "regDim_html");
        CSH.setHelpIDString(JTF_XLength, "regDim_html");
        CSH.setHelpIDString(JL_ylength, "regDim_html");
        CSH.setHelpIDString(JTF_YLength, "regDim_html");
        CSH.setHelpIDString(JL_area, "regDim_html");
        CSH.setHelpIDString(JTF_Area, "regDim_html");
        CSH.setHelpIDString(JL_orientation, "regOrientation_html");
        CSH.setHelpIDString(JTF_Orientation, "regOrientation_html");
    }


    static public void main(String args[]) {
        RegPanel rp = new RegPanel("RegPanel Test");
        rp.setVisible(true);
        RunFileData rfd = new RunFileData();
        ConfigData cd = ConfigData.getDefault();
        cd.addPropertyChangeListener(rp);
        rp.addPropertyChangeListener(cd);
        rfd.addPropertyChangeListener(rp);
        rp.addPropertyChangeListener(rfd);
    }
    

    @Override
    protected void action_xLength() {
        if (isUserInputMode(USER_INPUT_MODE_LENGTH)) {
            cXLen.setDisplayValue(JTF_XLength.getValue());
            if (isShape(SHAPE_SQUARE) && (cYLen.getValue() != cXLen.getValue())) {
                JTF_YLength.setValue(cXLen.getDisplayValue());
                action_yLength();
            }
            setAreaFromLength();
            // update related parms and fire property changes
            setLengthsFromArea();
        }
    }

    @Override
    protected void action_yLength() {
        if (isUserInputMode(USER_INPUT_MODE_LENGTH)) {
            cYLen.setDisplayValue(JTF_YLength.getValue());
            if (isShape(SHAPE_SQUARE) && (cYLen.getValue() != cXLen.getValue())) {
                JTF_XLength.setValue(cYLen.getDisplayValue());
                action_xLength();
            }
            setAreaFromLength();
            // update related parms and fire property changes
            setLengthsFromArea();
        }
    }

    @Override
    protected void action_radius() {
        if (isUserInputMode(USER_INPUT_MODE_LENGTH)) {
            cRadius.setDisplayValue(JTF_Radius.getValue());
            setAreaFromRadius();
            // update related parms and fire property changes
            setLengthsFromArea();
        }
    }

    @Override
    protected void action_area() {
        if (isUserInputMode(USER_INPUT_MODE_AREA)) {
            cArea.setDisplayValue(JTF_Area.getValue());
            setLengthsFromArea();
        }
    }

    @Override
    protected void action_orientation() {
        Angle = JTF_Orientation.getValue();
        if (Angle > 45) {
            Angle = 45;
            JTF_Orientation.setValueInternal(Angle);
        }
        if (Angle < -45) {
            Angle = -45;
            JTF_Orientation.setValueInternal(Angle);
        }

        changes.firePropertyChangeSkipThis(RunFileData.RegionAngle, null, Double.toString(Angle));
    }

    //
    // for action shape, since data is from user,
    // always set the lengths from the area, 
    // which allows area to remain constant.
    //
    @Override
    protected void action_shape() {
        String selectedShape = JCB_Shape.getSelectedItem().toString();
        int shapeIndex = convertComboShapeToIndex(selectedShape);
        c_shape = shapesRunFile[shapeIndex];
        displayFields ();
        refreshUserInputMode ();
        
        lengthRatio = 1.;
        setLengthsFromArea();            
        changes.firePropertyChangeSkipThis(RunFileData.Shape, null, c_shape);
    }

    @Override
    protected void dimClicked(java.awt.event.MouseEvent evt) {
        String j = evt.getComponent().getName();
        switch (evt.getComponent().getName()) {
            case ("Radius"):
                if (setUserInputMode(USER_INPUT_MODE_LENGTH)) {
                    JTF_Radius.dispatchEvent(evt);
                }
                break;
            case ("X-Length"):
                if (setUserInputMode(USER_INPUT_MODE_LENGTH)) {
                    JTF_XLength.dispatchEvent(evt);
                }
                break;
            case ("Y-Length"):
                if (setUserInputMode(USER_INPUT_MODE_LENGTH)) {
                    JTF_YLength.dispatchEvent(evt);
                }
                break;
            case ("Area"):
                if (setUserInputMode(USER_INPUT_MODE_AREA)) {
                    JTF_Area.dispatchEvent(evt);
                }
                break;
        }
    }                          

    @Override
    public void propertyChange(PropertyChangeEvent e) {
        if (!this.suspendProperyChange) {
            switch (e.getPropertyName()) {
                case RunFileData.XLength:
                    try {
                        cXLen.setValue(Double.parseDouble((String) e.getNewValue()));
                        JTF_XLength.setValue(cXLen.getDisplayValue());
                        setAreaFromLength();
                    } catch (NumberFormatException k) {
                    }
                    break;
                case RunFileData.YLength:
                    try {
                        cYLen.setValue(Double.parseDouble((String) e.getNewValue()));
                        JTF_YLength.setValue(cYLen.getDisplayValue());
                        setAreaFromLength();
                    } catch (NumberFormatException k) {
                    }
                    break;
                case RunFileData.Radius:
                    try {
                        cRadius.setValue(Double.parseDouble((String) e.getNewValue()));
                        JTF_Radius.setValue(cRadius.getDisplayValue());
                        if (isShape(SHAPE_CIRCLE) || isShapeKind(SHAPE_HALF_CIRCLE_KIND) || isShapeKind(SHAPE_QUARTER_CIRCLE_KIND)) {
                            //setAreaFromRadius();
                            setAreaFromLength();
                        }
                    } catch (NumberFormatException k) {
                    }
                    break;
                //
                // for property change shape, since data is from runfile,
                // always set the area from the existing lengths.
                //
                case RunFileData.Shape:
                    c_shape = e.getNewValue().toString();
                    int idx = convertRunFileShapeToIndex(c_shape);
                    suspendProperyChange = true;
                    setItemInShapeCombo(shapesComboBox[idx]);
                    suspendProperyChange = false;
                    if (isShape(SHAPE_SQUARE) || isShape(SHAPE_RECTANGLE)) {
                        setAreaFromLength();
                    } else if (isShape(SHAPE_CIRCLE) || isShapeKind(SHAPE_HALF_CIRCLE_KIND) || isShapeKind(SHAPE_QUARTER_CIRCLE_KIND)) {
                        setAreaFromRadius();                   
                    }
                   break;
                case RunFileData.RegionAngle:
                    try {
                        Angle = Double.parseDouble((String) e.getNewValue());
                        if (Angle > 45) {
                            Angle = 45;
                        }
                        if (Angle < -45) {
                            Angle = -45;
                        }
                    } catch (NumberFormatException k) {
                    }
                    JTF_Orientation.setValueInternal(Angle);
                    break;
                case ConfigData.Units:
                    measurementUnits = e.getNewValue().toString();
                    setDisplayUnits(measurementUnits);
                    updateDisplayValues();
                    break;
                default:
                    break;
            }
        }
    }
    
    protected void setDisplayUnits (String measurementUnits) {
        this.measurementUnits = measurementUnits;
        cXLen.setDisplaySystem(measurementUnits);
        cYLen.setDisplaySystem(measurementUnits);
        cRadius.setDisplaySystem(measurementUnits);
        cArea.setDisplaySystem(measurementUnits);
        if (measurementUnits.equals(Util.USUnits)) {
            JL_xlengthUnits.setText("ft");
            JL_ylengthUnits.setText("ft");
            JL_areaUnits.setText("ac");
            JL_radiusUnits.setText("ft");
        } else {
            JL_xlengthUnits.setText("m");
            JL_ylengthUnits.setText("m");
            JL_areaUnits.setText("ha");
            JL_radiusUnits.setText("m");
        }
        updateDisplayValues();
    }

    protected void updateDisplayValues() {
        JTF_XLength.setValueInternal(cXLen.getDisplayValue());
        JTF_YLength.setValueInternal(cYLen.getDisplayValue());
        JTF_Radius.setValueInternal(cRadius.getDisplayValue());
        JTF_Area.setValueInternal(cArea.getDisplayValue());
    }

    protected void displayFields() {
        //Hide everything but the combo box.
        //Fields
        JTF_XLength.setVisible(false);
        JTF_YLength.setVisible(false);
        JTF_YLength.setEditable(true);
        JTF_Radius.setVisible(false);
        //Labels
        JL_area.setVisible(false);
        JL_xlength.setVisible(false);
        JL_ylength.setVisible(false);
        JL_orientation.setVisible(false);
        JL_radius.setVisible(false);
        //Units
        JL_areaUnits.setVisible(false);
        JL_xlengthUnits.setVisible(false);
        JL_ylengthUnits.setVisible(false);
        JL_orientationUnits.setVisible(false);
        JL_radiusUnits.setVisible(false);

        boolean circles = false;
        boolean rectangles = false;

        if (isShape(SHAPE_CIRCLE) || isShape(SHAPE_HALF_CIRCLE_VE) || isShape(SHAPE_HALF_CIRCLE_VW) || isShape(SHAPE_HALF_CIRCLE_HN) || isShape(SHAPE_HALF_CIRCLE_HS) || isShape(SHAPE_QUARTER_CIRCLE_NE) || isShape(SHAPE_QUARTER_CIRCLE_SE) || isShape(SHAPE_QUARTER_CIRCLE_SW) || isShape(SHAPE_QUARTER_CIRCLE_NW)) {
            circles = true;
        } else if (isShape(SHAPE_SQUARE)) {
            rectangles = true;
            JTF_YLength.setEditable(false);
        } else {
            rectangles = true;
        }

        if (rectangles) {
            //Fields
            JTF_XLength.setVisible(true);
            JTF_YLength.setVisible(true);
            //Labels
            JL_area.setVisible(true);
            JL_xlength.setVisible(true);
            JL_ylength.setVisible(true);
            JL_orientation.setVisible(true);
            //Units
            JL_areaUnits.setVisible(true);
            JL_xlengthUnits.setVisible(true);
            JL_ylengthUnits.setVisible(true);
            JL_orientationUnits.setVisible(true);
        } else if (circles) {
            //Fields
            JTF_Radius.setVisible(true);
            //Labels
            JL_area.setVisible(true);
            JL_orientation.setVisible(true);
            JL_radius.setVisible(true);
            //Units
            JL_areaUnits.setVisible(true);
            JL_orientationUnits.setVisible(true);
            JL_radiusUnits.setVisible(true);
        }

    }
    
    protected void setAreaFromLength() {
        cArea.setValue(cXLen.getValue() * cYLen.getValue());
        JTF_Area.setValue(cArea.getDisplayValue());
        lengthRatio = cXLen.getValue() / cYLen.getValue();
    }
    
    protected void setAreaFromRadius() {
        double area = (Math.PI * cRadius.getValue() * cRadius.getValue());
        if (isShape(SHAPE_CIRCLE)) {
        } else if (isShapeKind(SHAPE_HALF_CIRCLE_KIND)) {
            area /= 2;
        } else if (isShapeKind(SHAPE_QUARTER_CIRCLE_KIND)) {
            area /= 4;
        } else {
            area = -1.;
        }
        
        if (area > 0.) {
            cArea.setValue(area);
            JTF_Area.setValue(cArea.getDisplayValue());
        }
    }
    
    protected void setLengthsFromArea() {
        if (!suspendProperyChange) {
            if (isShape(SHAPE_SQUARE) || isShape(SHAPE_RECTANGLE)) {
                cYLen.setValue(Math.sqrt(cArea.getValue() / lengthRatio));
                cXLen.setValue(cYLen.getValue() * lengthRatio);
                JTF_XLength.setValue(cXLen.getDisplayValue());
                JTF_YLength.setValue(cYLen.getDisplayValue());
                changes.firePropertyChangeSkipThis(RunFileData.XLength, null, cXLen.toStringValue());
                changes.firePropertyChangeSkipThis(RunFileData.YLength, null, cYLen.toStringValue());
            } else if (isShape(SHAPE_CIRCLE)) {
                double area = cArea.getValue();
                cRadius.setValue(Math.sqrt(area / Math.PI));
                JTF_Radius.setValue(cRadius.getDisplayValue());
                changes.firePropertyChangeSkipThis(RunFileData.Radius, null, cRadius.toStringValue());
                
                area = Math.sqrt(area);
                cXLen.setValue(area);
                cYLen.setValue(area);
                JTF_XLength.setValue(cXLen.getDisplayValue());
                JTF_YLength.setValue(cYLen.getDisplayValue());
                changes.firePropertyChangeSkipThis(RunFileData.XLength, null, cXLen.toStringValue());
                changes.firePropertyChangeSkipThis(RunFileData.YLength, null, cYLen.toStringValue());
            } else if (isShapeKind(SHAPE_HALF_CIRCLE_V_KIND)) {
                double area = cArea.getValue() * 2.;
                cRadius.setValue(Math.sqrt(area / Math.PI));
                JTF_Radius.setValue(cRadius.getDisplayValue());
                changes.firePropertyChangeSkipThis(RunFileData.Radius, null, cRadius.toStringValue());
                
                area = Math.sqrt(area);
                cXLen.setValue(area / 2.);
                cYLen.setValue(area);
                JTF_XLength.setValue(cXLen.getDisplayValue());
                JTF_YLength.setValue(cYLen.getDisplayValue());
                changes.firePropertyChangeSkipThis(RunFileData.XLength, null, cXLen.toStringValue());
                changes.firePropertyChangeSkipThis(RunFileData.YLength, null, cYLen.toStringValue());
            } else if (isShapeKind(SHAPE_HALF_CIRCLE_H_KIND)) {
                double area = cArea.getValue() * 2.;
                cRadius.setValue(Math.sqrt(area / Math.PI));
                JTF_Radius.setValue(cRadius.getDisplayValue());
                changes.firePropertyChangeSkipThis(RunFileData.Radius, null, cRadius.toStringValue());
                
                area = Math.sqrt(area);
                cXLen.setValue(area);
                cYLen.setValue(area/2);
                JTF_XLength.setValue(cXLen.getDisplayValue());
                JTF_YLength.setValue(cYLen.getDisplayValue());
                changes.firePropertyChangeSkipThis(RunFileData.XLength, null, cXLen.toStringValue());
                changes.firePropertyChangeSkipThis(RunFileData.YLength, null, cYLen.toStringValue());
            } else if (isShapeKind(SHAPE_QUARTER_CIRCLE_KIND)) {
                double area = cArea.getValue() * 4.;
                cRadius.setValue(Math.sqrt(area / Math.PI));
                JTF_Radius.setValue(cRadius.getDisplayValue());
                changes.firePropertyChangeSkipThis(RunFileData.Radius, null, cRadius.toStringValue());
                
                area = Math.sqrt(area)/2;
                cXLen.setValue(area);
                cYLen.setValue(area);
                JTF_XLength.setValue(cXLen.getDisplayValue());
                JTF_YLength.setValue(cYLen.getDisplayValue());
                changes.firePropertyChangeSkipThis(RunFileData.XLength, null, cXLen.toStringValue());
                changes.firePropertyChangeSkipThis(RunFileData.YLength, null, cYLen.toStringValue());
            }
        }
    }
    
    protected boolean refreshUserInputMode () {
        int mode = userInputMode;
        userInputMode = -1;
        return setUserInputMode(mode);
    }
    
    protected boolean setUserInputMode (int mode) {
        boolean changed = false;
        if (mode != userInputMode) {
            switch (mode) {
                case (USER_INPUT_MODE_LENGTH):
                    JTF_Area.setEditable(false);
                    JTF_XLength.setEditable(true);
                    JTF_YLength.setEditable(true);
                    JTF_Radius.setEditable(true);
                    break;
                case (USER_INPUT_MODE_AREA):
                default:
                    JTF_Area.setEditable(true);
                    JTF_XLength.setEditable(false);
                    JTF_YLength.setEditable(false);
                    JTF_Radius.setEditable(false);
                    
                    mode = USER_INPUT_MODE_AREA;
            }
            userInputMode = mode;
            changed = true;
        }
        return changed;
    }
    
    protected boolean isUserInputMode (int mode) {
        return userInputMode == mode;
    }
    
}
