/**
 * EarthApplet.java
 *
 * Alex S.
 */

import java.util.*;
import java.awt.*;
import java.awt.image.*;

public class EarthApplet extends PixApplet {

    /**
     * the renderer
     */
    Render r;

    pMatrix matrix = new pMatrix();

    // angle, mouse state
    private float m_anglex,m_angley;
    private int m_mousex,m_mousey;

    public float m_angledx = (float)Math.PI/156;
    public float m_angledy = (float)Math.PI/128;

    public boolean dragged = false;

    float[] vect = new float[4];
    float[] norm = new float[4];

    Vector lights = new Vector();

    public Shape shape;

    public Shape sphere = new Sphere(
        new Material(
            0,0,1,      // ambient
            1,1,1,      // diffuse
            1,1,1,      // specular
            (float)2       // the higher, the more concentrated
        )       
    );

    public Shape cube = new Cube(
        new Material(
            1,0,0,      // ambient
            1,1,1,      // diffuse
            1,1,1,      // specular
            (float)0.2       // the higher, the more concentrated
        )       
    );

    MediaTracker tracker;
    Image earth,moon;
    Texture eartht,moont;

    /**
     * initialize
     */
    public void init(){
        super.init();
        r = new Render(W,H,pix);

        tracker = new MediaTracker(this);
        earth = getImage(getDocumentBase(), "EarthMap.jpg");
        tracker.addImage(earth, 0);
        //moon = getImage(getDocumentBase(), "MoonMap.jpg");
        //tracker.addImage(moon, 0);
               
        try {
            tracker.waitForID(0);
            eartht = new Texture(earth,this);
            //moont = new Texture(moon,this);
        } catch (InterruptedException e) {
            return;
        }
        
	m_mousex = m_mousey = 0;
	m_anglex = m_angley = 0;
            
        lights.addElement( new Light( -30, -30,-70, 1,1,1 ) );
        //lights.addElement( new Light( 0, 0,-60, 1,1,1 ) );
        fixlights();

        shape = sphere;
    }

    /**
     * ensure all lights sum upto 1.
     */
    public void fixlights(){
        float r,g,b;
        Enumeration enum;
        r=g=b=(float)0.0;
        enum = lights.elements();
        while(enum.hasMoreElements()){
            Light l = (Light)enum.nextElement();
            r += l.r;
            g += l.g;
            b += l.b;
        }
        enum = lights.elements();
        while(enum.hasMoreElements()){
            Light l = (Light)enum.nextElement();
            l.r /= r;
            l.g /= g;
            l.b /= b;
        }
    }

    /**
     * SET PIXELS FOR THIS ANIMATION FRAME
     * (THIS OVERRIDES A METHOD IN PIXAPPLET CLASS)
     */
    public void setPix(int frame) 
    {
    
        m_angley += m_angledy;
        m_anglex += m_angledx;

        r.clear();

 	matrix.push();
			
	matrix.translate(0,0,-100);
	matrix.scale(60);
	matrix.rotatey(m_angley);
	matrix.rotatex(m_anglex);

        //matrix.translate(0,0,-1.4);

        // dump objects
        //shape = cube;
        //dumpObject();
        //matrix.translate(0,0,+2.8);
        
        shape = sphere;
        dumpObject();
                
	matrix.pop();
        
    }

    public void dumpObject()
    {
        matrix.computeInvTrans();
        float focallength = W/2;
            
        r.setshape(shape.faces,shape.verticest);

        r.settexture(eartht);
        
        float[] v;
        for(int i=0;i<shape.vertices.length;i++){
            vect[0] = shape.vertices[i][0]; 
            vect[1] = shape.vertices[i][1]; 
            vect[2] = shape.vertices[i][2]; 
            vect[3] = 1;
                
            norm[0] = shape.vertices[i][3]; 
            norm[1] = shape.vertices[i][4]; 
            norm[2] = shape.vertices[i][5]; 
            norm[3] = 0;
                
            vect = matrix.mult(vect);
            norm = matrix.multinvtrans(norm);
                
            
            float r,g,b;
            r = 0; // shape.m.ar;
            g = 0; // shape.m.ag;
            b = 0; //shape.m.ab;

            Enumeration enum = lights.elements();
            while(enum.hasMoreElements()){
                Light l = (Light)enum.nextElement();
                float[] Li = {
                    l.x-vect[0], 
                    l.y-vect[1], 
                    l.z-vect[2]
                };
                vectorNormalize(Li,Li);
                float Lidotn = dotProduct(Li,norm);
                float[] Hi = {
                    2 * Lidotn * norm[0] - Li[0],    
                    2 * Lidotn * norm[1] - Li[1],    
                    2 * Lidotn * norm[2] - Li[2],    
                };
                vectorNormalize(Hi,Hi);
                float[] Ei = {
                    0 - vect[0],
                    0 - vect[1],
                    0 - vect[2]
                };
                vectorNormalize(Ei,Ei);
                float Hidote = dotProduct(Hi,Ei);
                float p = (float)Math.pow(Math.max(0,Hidote),shape.m.p);
                    
                r += l.r * (shape.m.dr*Math.max(0,Lidotn)+shape.m.sr*p);
                g += l.g * (shape.m.dg*Math.max(0,Lidotn)+shape.m.sg*p);
                b += l.b * (shape.m.db*Math.max(0,Lidotn)+shape.m.sb*p);
            }
            
            shape.verticest[i][0] = 
                W/2 + (float)Math.floor(focallength*vect[0]/vect[2]);
            shape.verticest[i][1] = 
                H/2 + (float)Math.floor(focallength*vect[1]/vect[2]);
            shape.verticest[i][2] = focallength/vect[2];
            shape.verticest[i][3] = r;
            shape.verticest[i][4] = g;
            shape.verticest[i][5] = b;
            shape.verticest[i][6] = shape.vertices[i][6]*eartht.height;
            shape.verticest[i][7] = shape.vertices[i][7]*eartht.width;

                /*
                String s = "";
                for(int q=0;q<6;q++){                    
                    s += "["+shape.verticest[i][q]+"]";
                }
                s += "";
                System.out.println(s);
                */

        }
        r.rendershape();
    }

    /**
     * normalize
     */
    float vectorNormalize(float[] in, float[] out ) {
        float	length, ilength;
        length = (float)Math.sqrt(in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
        if (length == 0){
            return 0;
        }
        ilength = (float)1.0/length;
        out[0] = in[0]*ilength;
        out[1] = in[1]*ilength;
        out[2] = in[2]*ilength;
        return length;
    }	
	
    /**
     * dot product
     */
    float dotProduct (float[] v1, float[] v2){
        return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
    }    
        
    /**
     * mouse event handler: let the user move things
     */
    public boolean mouseDown(Event evt, int x, int y)
    {
        dragged = false;
        m_angledx = 0;
        m_angledy = 0;
        return true;
    }
    
    public boolean mouseUp(Event evt, int x, int y)
    {
        dragged = false;
        m_angledx = (float)Math.PI/156;
        m_angledy = (float)Math.PI/128;
        return true;
    }
	
    /**
     * mouse event handler: let the user move things
     */
    public boolean mouseDrag(Event evt, int x, int y)
    {
        dragged = true;
        if((m_mousey - y) < 0)
            m_anglex += (float)Math.PI/45;
        if((m_mousey - y) > 0)
            m_anglex -= (float)Math.PI/45;
        if((m_mousex - x) < 0)
            m_angley -= (float)Math.PI/45;
        if((m_mousex - x) > 0)
            m_angley += (float)Math.PI/45;
        m_mousex = x;
        m_mousey = y;
        damage = true;
        return true;
    }	


}

