package iDSS.sm;

import java.util.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.awt.image.BufferedImage;
import java.beans.*;
import java.sql.Timestamp;

import iDSS.gridDisp.*;
import iDSS.disp.*;
import iDSS.utils.*;


public class EllipticSurvivalModel implements SurvivalModel, Serializable, ActionListener {


    private double majorAxis,minorAxis,axisShiftX,axisShiftY,axisRotation;
    private double criticalFloodingDepth;

    private String modelName;
    private double rateOfDescent = 0.001;
    private Vector textFieldsVector;

    private PropertyChangeSupport pcs;

    private DisplayFrame internalFrame;

    public EllipticSurvivalModel() {


        modelName = "Ellipse Model";

        majorAxis = 0;
        minorAxis = 0;
        axisShiftX = 0;
        axisShiftY = 0;
        axisRotation = 0;
        criticalFloodingDepth = 0;
        pcs = new PropertyChangeSupport(this);

    } //public EllipticSurvivalModel()




    public EllipticSurvivalModel(double a,double b,double delX,double delY,double theta,double critDepth) {

        modelName = "Ellipse Model";

        if (a > 0)
            majorAxis = a;
        else
            majorAxis = 0;

        if (b > 0)
            minorAxis = b;
        else
            minorAxis = 0;

        if (delX > 0)
            axisShiftX = delX;
        else
            axisShiftX = 0;

        if (delY > 0)
            axisShiftY = delY;
        else
            axisShiftY = 0;

        if ((theta >= -2*Math.PI) && (theta <= 2*Math.PI))
            axisRotation = theta;
        else {

            int aNum = (int)Math.floor(theta/(2*Math.PI));
            axisRotation = theta-aNum*Math.PI;

        }//else

        if(critDepth >= 0)
            criticalFloodingDepth = critDepth;
        else
            criticalFloodingDepth = 0;


        pcs = new PropertyChangeSupport(this);

    } //public EllipticSurvivalModel(....)



    public void addPropertyChangeListener(PropertyChangeListener l) {

        pcs.addPropertyChangeListener(l);

    } //public void addPropertyChangeListener(PropertyChangeListener l)





    public void removePropertyChangeListener(PropertyChangeListener l) {

        pcs.removePropertyChangeListener(l);

    } //public void removePropertyChangeListener(PropertyChangeListener l)






    public String getName() {

        return modelName;

    } //public String getName()



    public void setMajorAxis(double a) {

        majorAxis = a;

    }//public void setMajorAxis(double a)



    public void setMinorAxis(double b) {

        minorAxis = b;

    }//public void setMinorAxis(double b)




    public void setXShift(double delX) {

        axisShiftX = delX;

    }//public void setXShift(double delX)





    public void setYShift(double delY) {

        axisShiftY = delY;

    }//public void setYShift(double delY)



    public void setAxisRotation(double rotation) {

        axisRotation = rotation;

    } //public void setAxisRotation(double rotation)






    public void setCriticalFloodingDepth(double depth) {

        criticalFloodingDepth = depth;

    } //public void setCriticalFloodingDepth(double depth)








    public double getMajorAxis() {

        return majorAxis;

    }//public void setMajorAxis(double a)



    public double getMinorAxis() {

        return minorAxis;

    }//public void getMinorAxis()




    public double getXShift() {

        return axisShiftX;

    }//public double getXShift()





    public double getYShift() {

        return axisShiftY;

    }//public double getYShift()



    public double getAxisRotation() {

        return axisRotation;

    } //public double getAxisRotation()







    public double getCriticalFloodingDepth(Timestamp t) {

        return criticalFloodingDepth;

    } //public double getCriticalFloodingDepth(Timestamp t)





    private double getDistanceToPeripheri(double angle) {

        double term1 = Math.pow(Math.cos(angle),2)/Math.pow(majorAxis,2);
        double term2 = Math.pow(Math.sin(angle),2)/Math.pow(minorAxis,2);

        double dist = Math.sqrt(1/(term1+term2));

        return dist;

    } //private double getDistanceToPeripheri(double angle)





    private double getTheta(double x,double y) {

        double term1 = y-axisShiftY;
        double term2 = x-axisShiftX;

        double theta = Math.atan2(term1,term2)-axisRotation;

        return theta;

    } //private double getTheta(double x,double y)






    private double getR(double x,double y,double theta) {

        double term1 = x-axisShiftX;
        double term2 = Math.cos(theta+axisRotation);

        double r = term1/term2;
        return r;

    } //private double getR(double x,double x,double theta)






    public double getProbability(long longDuration,double depth,Timestamp t) {

        double duration = (double)longDuration;

        if(duration == getXShift())
            duration = duration*1.01;

        double theta = getTheta((double)duration,depth);
        double r = getR((double)duration,depth,theta);
        double distToPeripheri = getDistanceToPeripheri(theta);
        //double p = (distToPeripheri-r)/distToPeripheri;
        //p = Math.max(0,p);

        double p = Math.exp((distToPeripheri-r)*rateOfDescent);
        p = Math.min(1,p);

        return p;

    } //public double getProbability(double duration,double depth,Timestamp t)





    public DisplayFrame showDetails(boolean editable) {

        internalFrame = new DisplayFrame(modelName,false,true,false,true,null);

        DrawingPanel2 picturePanel = new DrawingPanel2(400,100);
        EllipticSurvivalModel.drawModel(picturePanel);

        JLabel majorAXisLabel = new JLabel("Major axis (hours):");
        JLabel minorAxisLabel = new JLabel("Minor axis (depth units):");
        JLabel axisShiftXLabel = new JLabel("X-axis shift (hours):");
        JLabel axisShiftYLabel = new JLabel("Y-axis shift (depth units):");
        JLabel axisRotationLabel = new JLabel("Axis rotation (degrees):");
        JLabel criticalFloodingDepthLabel = new JLabel("Cirtical flood depth (depth units):");

        JTextField majorAxisTextField = new JTextField(String.valueOf(majorAxis/(1000*60*60)),10);
        JTextField minorAxisTextField = new JTextField(String.valueOf(minorAxis),10);
        JTextField axisShiftXTextField = new JTextField(String.valueOf(axisShiftX/(1000*60*60)),10);
        JTextField axisShiftYTextField = new JTextField(String.valueOf(axisShiftY),10);
        JTextField axisRotationTextField = new JTextField(String.valueOf(Math.toDegrees(axisRotation)),10);
        JTextField criticalFloodingDepthTextField = new JTextField(String.valueOf(criticalFloodingDepth),10);

        majorAxisTextField.setEditable(editable);
        minorAxisTextField.setEditable(editable);
        axisShiftXTextField.setEditable(editable);
        axisShiftYTextField.setEditable(editable);
        axisRotationTextField.setEditable(editable);
        criticalFloodingDepthTextField.setEditable(editable);

        textFieldsVector = new Vector();
        textFieldsVector.add(majorAxisTextField);
        textFieldsVector.add(minorAxisTextField);
        textFieldsVector.add(axisShiftXTextField);
        textFieldsVector.add(axisShiftYTextField);
        textFieldsVector.add(axisRotationTextField);
        textFieldsVector.add(criticalFloodingDepthTextField);

        JButton acceptButton = new JButton(IDSSAppConstants.acceptButtonText);
        acceptButton.setEnabled(editable);
        acceptButton.setActionCommand(IDSSAppConstants.acceptButtonCommand);
        acceptButton.addActionListener(this);

        JPanel textPanel = new JPanel();
        textPanel.setLayout(new GridLayout(6,2));
        textPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
        textPanel.add(majorAXisLabel);
        textPanel.add(majorAxisTextField);
        textPanel.add(minorAxisLabel);
        textPanel.add(minorAxisTextField);
        textPanel.add(axisShiftXLabel);
        textPanel.add(axisShiftXTextField);
        textPanel.add(axisShiftYLabel);
        textPanel.add(axisShiftYTextField);
        textPanel.add(axisRotationLabel);
        textPanel.add(axisRotationTextField);
        textPanel.add(criticalFloodingDepthLabel);
        textPanel.add(criticalFloodingDepthTextField);

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new BoxLayout(buttonPanel,BoxLayout.X_AXIS));
        buttonPanel.add(Box.createHorizontalGlue());
        buttonPanel.add(acceptButton);

        internalFrame.getContentPane().setLayout(new BoxLayout(internalFrame.getContentPane(),BoxLayout.Y_AXIS));
        internalFrame.getContentPane().add(picturePanel);
        internalFrame.getContentPane().add(textPanel);
        internalFrame.getContentPane().add(buttonPanel);
        internalFrame.pack();
        internalFrame.setVisible(true);

        return internalFrame;

    } //public void showDetails(boolean editable)




    public static void drawModel(DrawingPanel2 picturePanel) {

        BufferedImage bi = picturePanel.getCanvas();
        Graphics g = bi.getGraphics();

        int sizeX = picturePanel.getCanvasX();
        int sizeY = picturePanel.getCanvasY();

        g.setColor(Color.lightGray);
        g.fillRect(0,0,sizeX,sizeY);

        int margin = 10;

        int width = 200; //Ellipse width and height
        int height = 90;

        g.setColor(Color.black);

        int x = (sizeX-width)/2;
        int y = (sizeY-height)/2;

        int centerX = x+width/2;
        int centerY = y+height/2;

        g.drawOval(x,y,width,height);

        g.drawLine(centerX,centerY,x,centerY);
        g.drawLine(centerX,centerY,centerX,y);
        g.drawString("Major axis",x+20,centerY+15);
        g.drawString("Minor axis",centerX+5,centerY-height/4);



    } //public void drawModel(DrawingPanel2 picturePanel)








    public void actionPerformed(ActionEvent ae) {

        if (ae.getActionCommand().equals(IDSSAppConstants.acceptButtonCommand)) {

            JTextField tf;

            tf = (JTextField)textFieldsVector.elementAt(0);
            double a = Double.parseDouble(tf.getText());
            a = a*60*60*1000;

            tf = (JTextField)textFieldsVector.elementAt(1);
            double b = Double.parseDouble(tf.getText());

            tf = (JTextField)textFieldsVector.elementAt(2);
            double delX = Double.parseDouble(tf.getText());
            delX = delX*60*60*1000;

            tf = (JTextField)textFieldsVector.elementAt(3);
            double delY = Double.parseDouble(tf.getText());

            tf = (JTextField)textFieldsVector.elementAt(4);
            double theta = Double.parseDouble(tf.getText());
            theta = Math.toRadians(theta);

            tf = (JTextField)textFieldsVector.elementAt(5);
            double critFD = Double.parseDouble(tf.getText());

            setMajorAxis(a);
            setMinorAxis(b);
            setXShift(delX);
            setYShift(delY);
            setAxisRotation(theta);
            setCriticalFloodingDepth(critFD);

            pcs.firePropertyChange(IDSSAppConstants.setSurvivalModel,null,getCopy());
            pcs.firePropertyChange(IDSSAppConstants.removeFromModelView,null,internalFrame);

            //internalFrame.setClosed(true);


        } //if (ae.getActionCommand().equals(IDSSAppConstants.acceptButtonCommand))

    } //public void actionPerformed(ActionEvent ae)




    public SurvivalModel getCopy() {

        Timestamp t = null;
        SurvivalModel aModel = new EllipticSurvivalModel(
            getMajorAxis(),
            getMinorAxis(),
            getXShift(),
            getYShift(),
            getAxisRotation(),
            getCriticalFloodingDepth(t)
        );

        return aModel;

    } //public SurvivalModel getCopy()





    public Hashtable getParameters() {

        Hashtable h = new Hashtable();

        h.put("majorAxis",new Double(majorAxis));
        h.put("minorAxis",new Double(minorAxis));
        h.put("axisShiftX",new Double(axisShiftX));
        h.put("axisShiftY",new Double(axisShiftY));
        h.put("axisRotation",new Double(axisRotation));
        h.put("criticalFloodingDepth",new Double(criticalFloodingDepth));

        return h;

    } //public Hashtable getParameters()





    public void setParameters(Hashtable h) {

        String s;
        double d;

        majorAxis = StringHandler.stringToDouble((String)h.get("majorAxis"));
        minorAxis = StringHandler.stringToDouble((String)h.get("minorAxis"));
        axisShiftX = StringHandler.stringToDouble((String)h.get("axisShiftX"));
        axisShiftY = StringHandler.stringToDouble((String)h.get("axisShiftY"));
        axisRotation = StringHandler.stringToDouble((String)h.get("axisRotation"));
        criticalFloodingDepth = StringHandler.stringToDouble((String)h.get("criticalFloodingDepth"));

    } //public void setParameters(Hashtable h)







} //public class EllipticSurvivalModel
