//-*- eval: (progn (folding-mode) (auto-fill-mode 0)) -*- 
//[Update:[Tue Nov 05 IST 2019]]
/*History:
**Sat Oct 26 2019
Started.
**Wed Oct 30 2019
First working version.
*/
import java.util.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
import javax.swing.*;

public class Cylinder extends Object3D {
    static int count = 0;
    double r, h;
    JTextField radFld, htFld;

    public Cylinder(Screen scr) {
        super(new Pose(scr,0,0,0,0,0,0), scr, "Cyl"+Cylinder.count);
        count++;
        r = 5;
        h = 10;
        panel.add(new JLabel("Radius: "));
        radFld = new JTextField(""+r);
        htFld = new JTextField(""+h);
        panel.add(radFld);
        panel.add(new JLabel("Height: "));
        panel.add(htFld);
    }

    public void save(PrintWriter pw) {
        pw.format(" %f %f\n",r,h);
        pose.save(pw);
    }

    protected void load(Scanner scnr) {
        System.err.println("Loading a cone");
        double tmpr,tmph;
        try {
            tmpr = scnr.nextDouble();
            tmph = scnr.nextDouble();
            pose.load(scnr);
        }
        catch(Exception ex) {
            System.err.println("Failed to load cone");
            ex.printStackTrace(System.err);
            return;
        }
        r = tmpr; h = tmph;
        scr.repaint();
    }
    
    protected void updating() {
        r = Double.parseDouble(radFld.getText());
        h = Double.parseDouble(htFld.getText());
    }
    protected void fillGui() {
        radFld.setText(""+r);
        htFld.setText(""+h);
    }

    public void dump(Camera cam, Pad pad) {
        // {{{ Check if missed or not
        Vec3 c = pose.invRot(pose.getOrigin().minus(cam.getOrigin()));
        Vec3 scales = pose.getScales();
        double xScale = scales.x;
        double yScale = scales.y;
        double zScale = scales.z;
        double agamma = c.x*zScale;
        double calpha = c.z*xScale;
        
        double off = Math.atan2(agamma, calpha);
        double sin = -r*xScale*zScale / Math.sqrt(agamma*agamma+calpha*calpha);
        boolean missed = Math.abs(sin) > 1;
        // }}}

        double delta = Math.PI/50.0;
        double theta;
        double gap; int n;
        

        if(missed) {
            pad.startGroup();
            // {{{ Draw bottom ellipse in one piece
            pad.startPath();
            for(theta=0;theta<=2*Math.PI;theta+= 0.01) {
                Vec3 tmp = pose.wrt(new Vec3(r*Math.cos(theta), 0, r*Math.sin(theta)));
                pad.addPoint(cam.see(tmp));
            }
            pad.endPath();
            // }}}
            // {{{ Draw top ellipse in one piece
            pad.startPath();
            for(theta=0;theta<=2*Math.PI;theta+= 0.01) {
                Vec3 tmp = pose.wrt(new Vec3(r*Math.cos(theta), h, r*Math.sin(theta)));
                pad.addPoint(cam.see(tmp));
            }
            pad.endPath();
            // }}}
            pad.endGroup();
            return;
        }

        // {{{ Find theta0 and theta1 and find closer part
        
        double t = Math.asin(sin);
        double theta0 = t-off;
        double theta1 = -Math.PI-t-off;
        Vec3 minusSide = pose.wrt(new Vec3(r*Math.cos(-Math.PI-off), 0, r*Math.sin(-Math.PI-off)));
        Vec3 plusSide = pose.wrt(new Vec3(r*Math.cos(Math.PI-off), 0, r*Math.sin(Math.PI-off)));
        boolean minusIsCloser = (minusSide.minus(cam.getOrigin()).normsq() < plusSide.minus(cam.getOrigin()).normsq());
            
        // }}}
        


        Vec3 top1 = pose.wrt(new Vec3(r*Math.cos(theta0), h, r*Math.sin(theta0)));
        Vec3 top2 = pose.wrt(new Vec3(r*Math.cos(theta1), h, r*Math.sin(theta1)));
        Vec3 bot1 = pose.wrt(new Vec3(r*Math.cos(theta0), 0, r*Math.sin(theta0)));
        Vec3 bot2 = pose.wrt(new Vec3(r*Math.cos(theta1), 0, r*Math.sin(theta1)));
        

        Vec2 ptop1 = cam.see(top1);
        Vec2 ptop2 = cam.see(top2);
        Vec2 pbot1 = cam.see(bot1);
        Vec2 pbot2 = cam.see(bot2);

        pad.startGroup();
        if(!minusIsCloser) {
            // {{{ Bottom plus 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++) {
                Vec3 tmp = pose.wrt(new Vec3(r*Math.cos(theta), 0, r*Math.sin(theta)));
                pad.addPoint(cam.see(tmp));
                theta += delta;
            }
            pad.endPath();
            // }}}
            // {{{ Top plus 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++) {
        Vec3 tmp = pose.wrt(new Vec3(r*Math.cos(theta), h, r*Math.sin(theta)));
        pad.addPoint(cam.see(tmp));
        theta += delta;
    }
    pad.endPath();
    // }}}
            // {{{ Side lines
        

            // {{{ Ghost boundary
        pad.startPath1();
        pad.addPoint(pbot2);
        pad.addPoint(ptop2);
        pad.addPoint(ptop1);
        pad.addPoint(pbot1);
        pad.endPath1();
        // }}}
    
            // {{{ One side
        pad.startPath();
        pad.addPoint(pbot1);
        pad.addPoint(ptop1);
        pad.endPath();
        // }}}
            
            // {{{ Other side
        pad.startPath();
        pad.addPoint(pbot2);
        pad.addPoint(ptop2);
        pad.endPath();
        // }}}
            // }}}
            // {{{ Bottom minus part
            gap = theta0 - theta1;
            n = (int)(50*gap/Math.PI);
            delta = gap/n;
            theta=theta1;
            pad.startPath();
            for(int i=0;i<=n;i++) {
                Vec3 tmp = pose.wrt(new Vec3(r*Math.cos(theta), 0, r*Math.sin(theta)));
                pad.addPoint(cam.see(tmp));
                theta += delta;
            }
            pad.endPath();
            // }}}
            // {{{ Top minus part
    gap = theta0 - theta1;
    n = (int)(50*gap/Math.PI);
    delta = gap/n;
    theta=theta1;
    pad.startPath();
    for(int i=0;i<=n;i++) {
        Vec3 tmp = pose.wrt(new Vec3(r*Math.cos(theta), h, r*Math.sin(theta)));
        pad.addPoint(cam.see(tmp));
        theta += delta;
    }
    pad.endPath();
    // }}}
        }
        else {
            // {{{ Bottom minus part
            gap = theta0 - theta1;
            n = (int)(50*gap/Math.PI);
            delta = gap/n;
            theta=theta1;
            pad.startPath();
            for(int i=0;i<=n;i++) {
                Vec3 tmp = pose.wrt(new Vec3(r*Math.cos(theta), 0, r*Math.sin(theta)));
                pad.addPoint(cam.see(tmp));
                theta += delta;
            }
            pad.endPath();
            // }}}
            // {{{ Top minus part
    gap = theta0 - theta1;
    n = (int)(50*gap/Math.PI);
    delta = gap/n;
    theta=theta1;
    pad.startPath();
    for(int i=0;i<=n;i++) {
        Vec3 tmp = pose.wrt(new Vec3(r*Math.cos(theta), h, r*Math.sin(theta)));
        pad.addPoint(cam.see(tmp));
        theta += delta;
    }
    pad.endPath();
    // }}}
            // {{{ Side lines

        // {{{ Ghost boundary
        pad.startPath1();
        pad.addPoint(pbot2);
        pad.addPoint(ptop2);
        pad.addPoint(ptop1);
        pad.addPoint(pbot1);
        pad.endPath1();
        // }}}
    
        // {{{ One side
        pad.startPath();
        pad.addPoint(pbot1);
        pad.addPoint(ptop1);
        pad.endPath();
        // }}}

        // {{{ Other side
        pad.startPath();
        pad.addPoint(pbot2);
        pad.addPoint(ptop2);
        pad.endPath();
        // }}}
        // }}}
            // {{{ Bottom plus 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++) {
                Vec3 tmp = pose.wrt(new Vec3(r*Math.cos(theta), 0, r*Math.sin(theta)));
                pad.addPoint(cam.see(tmp));
                theta += delta;
            }
            pad.endPath();
            // }}}
            // {{{ Top plus 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++) {
        Vec3 tmp = pose.wrt(new Vec3(r*Math.cos(theta), h, r*Math.sin(theta)));
        pad.addPoint(cam.see(tmp));
        theta += delta;
    }
    pad.endPath();
    // }}}
        }
        pad.endGroup();


    }
}
