//-*- eval: (progn (folding-mode) (auto-fill-mode 0)) -*- 
//[Update:[Wed Nov 06 IST 2019]]
/*History:
**Sun Nov 03 2019
   Started.
*/
import java.util.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
import javax.swing.*;

public class RotX extends Object3D {
    static int count = 0;
    RotXable info;
    JTextField clsFld;
    String clsName;
    
    protected void fillGui() {
        clsFld.setText(clsName);
    }

    private JTextField xsFld, ysFld, zsFld;
    public RotX(Screen scr) {
        super(new Pose(scr,0,0,0,0,0,0), scr, "RotX"+RotX.count);
        count++;
        clsFld = new JTextField(10);
        panel.add(clsFld);
    }
    protected void updating() {
        try {
            clsName = clsFld.getText().trim();
            Class cls = Class.forName(clsName);
            info = (RotXable) cls.newInstance();
            System.err.println("a = "+info.getA());
        }
        catch(Exception ex) {
            ex.printStackTrace(System.err);
        }

    }

    private final static int
        DRAWING = 1,
        NOT_DRAWING = 2;


    public void dump(Camera cam, Pad pad) {
        if(info==null) return;
        double startValue = info.getA();
        double endValue = info.getB();

        Vec3 scales = pose.getScales();
        double xScale = scales.x;
        double yScale = scales.y;
        double zScale = scales.z;
        
        Vec3 tmp = pose.invRot(pose.getOrigin().minus(cam.getOrigin()));
        double a = tmp.x/xScale;
        double gammab = zScale*tmp.y;
        double betac = yScale*tmp.z;
        double off = Math.atan2(gammab, betac);
        double constant = Math.sqrt(gammab*gammab+betac*betac);
        Vec3 p3= null;

        pad.startGroup();
        // {{{ One horizon
        int state = NOT_DRAWING;

        for(double x=startValue; x<endValue+0.05; x+= 0.05) {
            double fx = info.f(x);
            double fpx = info.fp(x);
            double sin = yScale*zScale*(fpx*(a+x)-fx)/constant;
            boolean good = false;
            if(Math.abs(sin) <= 1) {
                good = true;
                double t = Math.asin(sin);
                double theta0 = t-off;
                p3 = pose.wrt(new Vec3(x,fx*Math.cos(theta0), fx*Math.sin(theta0)));
            }
            else {
                good = false;
            }

            switch(state) {
            case DRAWING:
                if(good) {
                    pad.addPoint(cam.see(p3));
                }
                else {
                    pad.endPath();
                    state = NOT_DRAWING;
                }
                break;
            case NOT_DRAWING:
                if(good) {
                    pad.startPath();
                    pad.addPoint(cam.see(p3));
                    state = DRAWING;
                }
                break;
            }
        }
        if(state==DRAWING) pad.endPath();
        // }}}
        // {{{ The other horizon
        state = NOT_DRAWING;
        for(double x=startValue; x<endValue+0.05; x+= 0.05) {
            double fx = info.f(x);
            double fpx = info.fp(x);

            double sin = yScale*zScale*(fpx*(a+x)-fx)/constant;
            boolean good = false;
            if(Math.abs(sin) <= 1) {
                good = true;
                double t = Math.asin(sin);
                double theta0 = -Math.PI-t-off;
                p3 = pose.wrt(new Vec3(x,fx*Math.cos(theta0),fx*Math.sin(theta0)));
            }
            else {
                good = false;
            }
            switch(state) {
            case DRAWING:
                if(good) {
                    pad.addPoint(cam.see(p3));
                }
                else {
                    pad.endPath();
                    state = NOT_DRAWING;
                }
                break;
            case NOT_DRAWING:
                if(good) {
                    pad.startPath();
                    pad.addPoint(cam.see(p3));
                    state = DRAWING;
                }
                break;
            } 
        }
        if(state==DRAWING) pad.endPath();

        // }}}
        
        double delta = Math.PI/50.0;
        double theta, theta0, theta1;
        double gap; int n; 

        // {{{ Start ellipse
        double x = startValue;
        double fx = info.f(x);
        double fpx = info.fp(x);
        double sin = yScale*zScale*(fpx*(a+x)-fx)/constant;
        theta = Math.asin(sin);
        theta0 = theta-off;
        theta1 = -Math.PI-theta-off;
        // {{{ One part 
        gap = theta0 - theta1;
        n = (int)(50*gap/Math.PI);
        delta = gap/n;
        theta=theta1;
        pad.startPath();
        for(int i=0;i<=n;i++) {
            pad.addPoint(cam.see(pose.wrt(new Vec3(x,fx*Math.cos(theta), fx*Math.sin(theta)))));
            theta += delta;
        }
        pad.endPath();
        // }}}
        // {{{ The other part
        gap = (2*Math.PI+theta1) - theta0;
        n = (int)(50*gap/Math.PI);
        delta = gap/n;
        theta=theta0;
        pad.startPath();
        for(int i=0;i<=n;i++) {
            pad.addPoint(cam.see(pose.wrt(new Vec3(x,fx*Math.cos(theta), fx*Math.sin(theta)))));
            theta += delta;
        }
        pad.endPath();
        // }}}
        // }}}
        // {{{ End ellipse
        x = endValue;
        fx = info.f(x);
        fpx = info.fp(x);
        sin = yScale*zScale*(fpx*(a+x)-fx)/constant;
        theta = Math.asin(sin);
        theta0 = theta-off;
        theta1 = -Math.PI-theta-off;
        // {{{ One part 
        gap = theta0 - theta1;
        n = (int)(50*gap/Math.PI);
        delta = gap/n;
        theta=theta1;
        pad.startPath();
        for(int i=0;i<=n;i++) {
            pad.addPoint(cam.see(pose.wrt(new Vec3(x,fx*Math.cos(theta), fx*Math.sin(theta)))));
            theta += delta;
        }
        pad.endPath();
        // }}}
        // {{{ The other part
        gap = (2*Math.PI+theta1) - theta0;
        n = (int)(50*gap/Math.PI);
        delta = gap/n;
        theta=theta0;
        pad.startPath();
        for(int i=0;i<=n;i++) {
            pad.addPoint(cam.see(pose.wrt(new Vec3(x,fx*Math.cos(theta), fx*Math.sin(theta)))));
            theta += delta;
        }
        pad.endPath();
        // }}}
        // }}}

        pad.endGroup();
    }

    protected void save(PrintWriter pw) {}
    protected void load(Scanner scnr) {}

}
