//[Update:[Sat Feb 12 IST 2022]]
/*History:
**Fri Oct 25 2019
   Started.
**Wed Oct 30 2019
 First working version.
**Wed Jul 22 2020
New Camera policy.
**Thu Jul 23 2020
Corrected an orientation bug. Now we use the CS coordinate system everywhere: X, Y on screen. Z sticking out.
**Fri Dec 11 2020
Now camera is controlled by mouse drag and wheel.
*/
import java.util.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.datatransfer.*;

public class Camera
    implements KeyListener, ClipboardOwner {
    double lat, lon, r;
    Screen scr;
    Vec3 origin, bkwd, up, rt, trueUp;
    Clipboard cb;
    private final static double R2D = 180/Math.PI;
    
    public void keyPressed(KeyEvent ke) {}
    public void keyReleased(KeyEvent ke) {
        switch(ke.getKeyCode()) {
        case KeyEvent.VK_UP:
            lat += 0.01;
            break;
        case KeyEvent.VK_DOWN:
            lat -= 0.01;
            break;
        case KeyEvent.VK_LEFT:
            lon += 0.01;
            break;
        case KeyEvent.VK_RIGHT:
            lon -= 0.01;
            break;
        case KeyEvent.VK_A:
            r -= 1;
            if(r < 1) r = 1;
            break;
        case KeyEvent.VK_V:
            r += 1;
            break;
        case KeyEvent.VK_C:
            String cstring = String.format("theta= %.2f, phi= %.2f, r= %.3f", R2D*lon, R2D*lat, r);
            System.err.println("Copying "+cstring);
            copy(cstring);
            break;
        }
        move();
    }

    public double getLat() {return lat;}
    public double getLon() {return lon;}
    public double getR() {return r;}

    public void setLatLon(double lt, double ln) {
        lat = lt; lon = ln;
        //System.err.format("lat=%.2f, lon=%.2f\n",lat,lon);
        move();
    }

    public void changeR(int dirn) {
        r += dirn*1.0;
        move();
    }
    public void keyTyped(KeyEvent ke) {}
    
    public Camera(Screen scr) {
        lat = 0;
        lon = 0;
        r = 50;
        this.scr = scr;
        trueUp = new Vec3(0,1,0);
        createMat();
        /*JFrame cf = new JFrame("Camera");
        cf.addKeyListener(this);
        cf.pack();
        cf.setSize(100,100);
        cf.setVisible(true);*/

        cb = Toolkit.getDefaultToolkit().getSystemClipboard();
    }
    void copy(String str) {
        cb.setContents(new StringSelection(str),this);
    }

      
    public void lostOwnership(Clipboard clip, 
                              Transferable transfer) {
        System.err.println("Lost ownnership["+transfer+"]");
    }
    
    Vec3 getOrigin() {return origin;}
    
    private void createMat() {
        bkwd = new Vec3(Math.sin(lon) * Math.cos(lat),
                        Math.sin(lat),
                        Math.cos(lon) * Math.cos(lat));

        origin = bkwd.times(r);

        double factor = bkwd.dot(trueUp);
        up = trueUp.minus(bkwd.times(factor));

        up = up.times(1/Math.sqrt(up.normsq()));

        rt = up.cross(bkwd);

        //System.err.println("bkwd = "+bkwd);
        //System.err.println("up = "+up);
        //System.err.println("rt = "+rt+" ("+rt.normsq()+")");
        //rt should have norm 1.
    }

    public void move() {
        createMat();
        scr.repaint();
        //System.err.println("World origin = "+see(worldOrigin));
    }

    private static final Vec3 worldOrigin = new Vec3(0,0,0);
    
    public Vec2 see(Vec3 p) {
        Vec3 temp = p.minus(origin);
        Vec3 computer =  new Vec3(temp.dot(rt), temp.dot(up), temp.dot(bkwd));
        return computer.proj();
    }
}
