/*
Generated by Cosmo Code 2.5.

Note: 
	Comments beginning with //{{ and ending with
	//}} denote non-editable code blocks. If you edit
	the code between these comments, your edits will be lost
	the next time you save from the Visual Builder.

	When generating the code for this class, Cosmo Code
	looks for these comments. If you remove the comments, 
	Cosmo Code will not generate the required code for this
	class.

	If you accidentally remove the comments, open any other
	source file generated by Cosmo Code, and copy the comments
	from that file into the corrupted file.
*/


import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.util.*;
import java.io.*;
import netscape.javascript.JSObject;
import vrml.external.field.*;
import vrml.external.Node;
import vrml.external.Browser;
import vrml.external.exception.*;


//{{ import_classes - Begin Non-Editable Code Block
import com.sgi.ccode.eventmaps.MouseEventMapper;
import com.sgi.ccode.eventmaps.TextEventMapper;
//}} import_classes - End Non-Editable Code Block

/**
 * Put the class description here.
 * @author AUTHORNAME
 * @version VERSIONDATA
 */
public class Promenad extends java.applet.Applet implements EventOutObserver
 
{
	/**
	 * init() is called by the browser or applet viewer to inform
	 * this applet that it has been loaded into the system. It is always
	 * called before the first time that the <code>start</code> method is
	 * called to initialize the applet.
	 */
	 
	 
	int DEBUG = 2;
	 
	// Browser we're using
  	Browser browser;
  	
  	//Data server name
  	String dtsName = new String("promenade1");
  	//DataServer port
  	int dtsPort = 9999;
  	//the current Vrml Object
  	int curVrmlObj = 1;
  	//the last Vrml Object Nb
  	int lastVrmlNb = 4;
  	//is it possible to change
  	int isChStatus = 1;
  	
  	// Root of the scene graph (to which we add our nodes)
  	Node root;
  	// Center viewpoint to navigate a special position
	Node center_vp;
	Node center_vp1;
	// Translation node
	Node transl_box;
	
	int vpinuse = 0;
	float opos[] = new float[3];
	float apos[] = new float[3];
	
  	// JSobjects
	private JSObject window;
	// EventIns of the root node
	EventInMFNode addChildren;
	EventInMFNode removeChildren;
	
	// Shape group hierarchy
	Node[] shape;
	Hashtable shapes = new Hashtable();
	
	// The current position in the scene
	EventOutSFVec3f curVec = null; 
	
	// The thread to read data from the fakeServer
	private NetThread nt;
	int NetRun = 0;
	
	private MoveVpThread mvpt;
	
	boolean error = false;

	public void init()
	{
		// TODO: Add initialization code before or after the 
		//       ccInit() method call.

		super.init();  // Call parent class's initialization routine
		
		if (DEBUG != 0) { System.out.println("init\n"); }

		Dimension d = null;	

		window = JSObject.getWindow(this); // this=applet
		
		// get parameters from the html
		dtsName = this.getParameter("dtsName");
		DEBUG = (new Integer(this.getParameter("DEBUG"))).intValue();
		dtsPort = (new Integer(this.getParameter("dtsPort"))).intValue();
		curVrmlObj = (new Integer(this.getParameter("curVrmlObj"))).intValue();
		lastVrmlNb = (new Integer(this.getParameter("lastVrmlNb"))).intValue();
				
		ccInit();      // Do local initializations
		

		// Fire off the net-input thread
		nt = new NetThread(this);
		mvpt = new MoveVpThread(this);
		opos[0] = 0;
		opos[1] = 0;
		opos[2] = 0;
		apos[0] = (float)3.2;
		apos[1] = (float)1;
		apos[2] = (float)3.75;
	}

	/**
	 * destroy() is called by the browser or applet viewer to inform
	 * this applet that it is being reclaimed and that it should destroy
	 * any resources that it has allocated. The <code>stop</code> method
	 * will always be called before <code>destroy</code>.
	 */

	public void destroy()
	{
		// TODO: Add any required clean up code here.

		super.destroy();
	}

	/**
	 * start() is called by the browser or applet viewer to inform
	 * this applet that it should start its execution. It is called after
	 * the <code>init</code> method and each time the applet is revisited
	 * in a Web page.
	 */

	public void start()
	{
		// TODO: Add startup code here when you want to perform an
		//       action each time the page containing this applet
		//       is visited.

		super.start();
		vrmlStart();
		mvpt.start();
		nt.start();
	}

	/**
	 * stop() is called by the browser or applet viewer to inform
	 * this applet that it should stop its execution. It is called when
	 * the Web page that contains this applet has been replaced by
	 * another page, and also just before the applet is to be destroyed.
	 */

	public void stop()
	{
		// TODO: Add shutdown code here when you want to perform an
		//       action each time the page containing this applet
		//       is exited.

		super.stop();
		nt.stop();
		mvpt.stop();
	}

	/**
	 * ccInit() performs local initialization for this class.
	 * Specifically, it's used for initialization by Cosmo Code.
	 */

	void ccInit()
	{       
		// TODO: Optionally add further initializations before or after
		//       the non-editable blocks.

		//{{ init_objects - Begin Non-Editable Code Block
		setSize( 800, 120 );
		setForeground( Color.black );
		setBackground( Color.black );
		setName( "mainpanel" );
		setLayout( null );

		label1 = new java.awt.Label();
		label1.setLocation( 13, 53 );
		label1.setSize( 17, 18 );
		add( label1 );
		label1.setText( "x:" );
		label1.setForeground( Color.black );
		label1.setBackground( Color.white );
		label1.setName( "x_lab" );

		label2 = new java.awt.Label();
		label2.setLocation( 13, 74 );
		label2.setSize( 17, 18 );
		add( label2 );
		label2.setText( "y:" );
		label2.setForeground( Color.black );
		label2.setBackground( Color.white );
		label2.setName( "y_lab" );

		label3 = new java.awt.Label();
		label3.setLocation( 13, 95 );
		label3.setSize( 17, 18 );
		add( label3 );
		label3.setText( "z:" );
		label3.setForeground( Color.black );
		label3.setBackground( Color.white );
		label3.setName( "z_lab" );

		xout = new java.awt.Label();
		xout.setLocation( 34, 51 );
		xout.setSize( 258, 21 );
		add( xout );
		xout.setText( "xout" );
		xout.setForeground( Color.red );
		xout.setName( "xout" );

		yout = new java.awt.Label();
		yout.setLocation( 34, 73 );
		yout.setSize( 258, 21 );
		add( yout );
		yout.setText( "yout" );
		yout.setForeground( Color.red );
		yout.setName( "yout" );

		zout = new java.awt.Label();
		zout.setLocation( 34, 95 );
		zout.setSize( 258, 21 );
		add( zout );
		zout.setText( "zout" );
		zout.setForeground( Color.red );
		zout.setName( "zout" );

		startbt = new java.awt.Button();
		startbt.setLocation( 179, 14 );
		startbt.setSize( 70, 24 );
		add( startbt );
		startbt.setLabel( "Start" );
		startbt.setName( "start" );

		dtsName_TF = new java.awt.TextField();
		dtsName_TF.setLocation( 441, 65 );
		dtsName_TF.setSize( 175, 31 );
		add( dtsName_TF );
		dtsName_TF.setForeground( Color.black );
		dtsName_TF.setBackground( Color.white );
		dtsName_TF.setFont( new Font("Dialog",  0,  18) );

		dtsPort_TF = new java.awt.TextField();
		dtsPort_TF.setLocation( 645, 65 );
		dtsPort_TF.setSize( 72, 31 );
		add( dtsPort_TF );
		dtsPort_TF.setForeground( Color.black );
		dtsPort_TF.setBackground( Color.white );
		dtsPort_TF.setFont( new Font("Dialog",  0,  18) );

		label7 = new java.awt.Label();
		label7.setLocation( 623, 68 );
		label7.setSize( 10, 25 );
		add( label7 );
		label7.setText( ":" );
		label7.setFont( new Font("Dialog",  1,  18) );

		label8 = new java.awt.Label();
		label8.setLocation( 377, 68 );
		label8.setSize( 56, 25 );
		add( label8 );
		label8.setText( "Connect" );
		label8.setFont( new Font("Dialog",  1,  12) );

		stopbt = new java.awt.Button();
		stopbt.setLocation( 484, 14 );
		stopbt.setSize( 70, 24 );
		add( stopbt );
		stopbt.setLabel( "Stop" );
		stopbt.setName( "stop" );

		// Initialize event maps
		
		try
		{
			mouseEventMapper = new MouseEventMapper();
			textEventMapper = new TextEventMapper();

			mouseEventMapper.wireMouseClicked(startbt, this, "onStartbtMouseClicked");
			textEventMapper.wireTextValueChanged(dtsName_TF, this, "onDtsName_TFTextValueChanged");
			textEventMapper.wireTextValueChanged(dtsPort_TF, this, "onDtsPort_TFTextValueChanged");
			mouseEventMapper.wireMouseClicked(stopbt, this, "onStopbtMouseClicked");

			startbt.addMouseListener(mouseEventMapper);
			dtsName_TF.addTextListener(textEventMapper);
			dtsPort_TF.addTextListener(textEventMapper);
			stopbt.addMouseListener(mouseEventMapper);
		}
		catch (ClassNotFoundException ex)
		{
			ccHandleEventMapExceptions(ex);
		}
		catch (NoSuchMethodException ex)
		{
			ccHandleEventMapExceptions(ex);
		}
		//}} init_objects - End Non-Editable Code Block
		
		// by Marci
		dtsName_TF.setText(dtsName);
		dtsPort_TF.setText(new Integer(dtsPort).toString());
	}

	public void addVrmlObjS(){

		if (DEBUG > 1) { System.out.println("AddVrmlObjS\n\n"); }
		
		for (int count = 1; count <= lastVrmlNb; count++) {
			String buf = new String("Group {\n" +
      			   "children [\n" +
			   "	   	Inline {\n"+
			   "		    url \""+count+"\\obj.wrl\" \n"+
			   "	   	}\n"+
			   "	    ]\n"+
			   "}\n");
			//System.out.println(buf);
		
			shape = browser.createVrmlFromString(buf);
			shapes.put(new Integer(count),shape);
		}
	}
	

	public void addFirstVrmlObj(){

		if (DEBUG > 1) { System.out.println("AddFirstVrmlObj\n\n"); }
		

		addChildren.setValue((Node[])shapes.get(new Integer(1)));
	}

	public void chVrmlObj(){

		if (DEBUG > 1) { System.out.println("chVrmlObj\n\n"); }
		
		removeChildren.setValue((Node[])shapes.get(new Integer(curVrmlObj)));
		curVrmlObj++;
		if (curVrmlObj > lastVrmlNb){
			curVrmlObj = 1;
		}
		addChildren.setValue((Node[])shapes.get(new Integer(curVrmlObj)));
	}


	void vrmlStart()
	{
		if (DEBUG > 1) { System.out.println("vrmlStart()..."); }
		
		// Get the browser
		for (int count = 0; count < 10; count++) {
			try {
				browser = (Browser) vrml.external.Browser.getBrowser(this,"fvrml",0);
			}
			catch (Exception e) { }  // getBrowser() can throw NullBrowserException
			if (browser != null) break;
			try { Thread.sleep(200); }
			catch (InterruptedException ignored) { }
			if (DEBUG > 0) { System.out.println("browser was null, trying again..."); }
		}
		if (browser == null) {
			throw new Error("Failed to get the browser after 10 tries!");
		}
		if (DEBUG > 1) { System.out.println("Got the browser: " + browser); }

		try {
			// Get root node of the scene, and its EventIns
			root = browser.getNode("ROOT");

			addChildren = (EventInMFNode) root.getEventIn("addChildren");
			removeChildren = (EventInMFNode) root.getEventIn("removeChildren");

			// Get node center
			center_vp = browser.getNode("Camera01");
			//center_vp1 = browser.getNode("CENTER1");
			
			//add the first object
			addVrmlObjS();
			addFirstVrmlObj();


/*	NINCS VRML->JAVA!!!
			// Get the Proximity Sensor
			Node sensor = browser.getNode("proxi");
			if (DEBUG > 1) { System.out.println("Got node: proxi\n"); }
			
			// Get the BoxPos Node
			//transl_box = browser.getNode("BoxPos");
			//if (DEBUG > 1) { System.out.println("Got node: boxpos\n"); }
	
			// Get its SFVec3f EventOut
			curVec = (EventOutSFVec3f) sensor.getEventOut("position_changed");
			if (DEBUG > 1) { System.out.println("Got EventOut: SFVec3f\n" +curVec); }


			// callback -- out nmbrs
			//curVec.advise(this, new Integer(1));
*/

		}
		catch (InvalidNodeException e) {
			if (DEBUG != 0) {System.out.println("PROBLEMS!: " + e + "\n");}
			error = true;
		}
		catch (InvalidEventInException e) {
			if (DEBUG != 0) {System.out.println("PROBLEMS!: " + e + "\n");}
			error = true;
		}
		catch (InvalidVrmlException e) {
			System.out.println("PROBLEMS!: " + e + "\n");
			error = true;
		}
		catch (NullPointerException e) {
			System.out.println("PROBLEMS!: " + e + "\n");
			error = true;
		}
	
		if (error == false)
			if (DEBUG > 1) { System.out.println("Ok...\n"); }
	}

	public void callback(EventOut who, double when, Object which) {
		//System.out.println("EAI callback()...");
		//Browser.print("RGBTest: EAI callback()...");

		Integer whichNum = (Integer) which;
		if (DEBUG > 1) { System.out.println("Num:" + whichNum + "\n"); }
   
		if ( whichNum.intValue() == 1) { 
			float[] val = curVec.getValue();
	
			if (DEBUG > 1) { 
				System.out.println("Val:" + val[0] + ", " + val[1] + ", " + val[2] + "\n");
				xout.setText(" "+val[0]);
			}
			xout.setText(" "+val[0]);
			yout.setText(" "+val[1]);
			zout.setText(" "+val[2]);
		}
	}


	public void move_trans (float x, float y, float z){
		if( !((opos[0] == x) && (opos[1] == y) && (opos[2] ==z)) ){
		
			opos[0] = x;
			opos[1] = y;
			opos[2] = z;
			
			//SET VP
			EventInSFVec3f set_transl = null;
			try {
					set_transl = (EventInSFVec3f)transl_box.getEventIn("set_translation");
			}
			catch(InvalidEventInException e) {
				System.out.println("move_trans: InvalidEventInException: " + e);
				return;
			}
		
			float spos[] = new float[3];
			spos[0] = (float)x;
			spos[1] = (float)y;
			spos[2] = (float)z;
		
			set_transl.setValue(spos);
			
			if (DEBUG > 1) { System.out.println("move_vp: setpos"); }
		}
	}
			

	public void move_vp (float x, float y, float z){
	
	
		if( !((opos[0] == x) && (opos[1] == y) && (opos[2] ==z)) ){
		
			opos[0] = x;
			opos[1] = y;
			opos[2] = z;
			
			xout.setText(" "+x);
			yout.setText(" "+y);
			zout.setText(" "+z);
		

			//SET VP
			EventInSFVec3f set_position = null;
			try {
					set_position = (EventInSFVec3f)center_vp.getEventIn("set_position");
			}
			catch(InvalidEventInException e) {
				System.out.println("move_vp: InvalidEventInException: " + e);
				return;
			}
		
			float spos[] = new float[3];
			spos[0] = (float)x;
			spos[1] = (float)y;
			spos[2] = (float)z;
		
			set_position.setValue(spos);
			
			if (DEBUG > 1) { System.out.println("move_vp: setpos"); }

		

/*			
			//SET VP
			EventInSFVec3f set_position = null;
			try {
				if (vpinuse == 0){
					set_position = (EventInSFVec3f)center_vp1.getEventIn("set_position");
					vpinuse = 1;
				}
				else {
					set_position = (EventInSFVec3f)center_vp.getEventIn("set_position");
					vpinuse = 0;
				}
			}
			catch(InvalidEventInException e) {
				System.out.println("move_vp: InvalidEventInException: " + e);
				return;
			}
		
			float spos[] = new float[3];
			spos[0] = (float)x;
			spos[1] = (float)y;
			spos[2] = (float)z;
		
			set_position.setValue(spos);
			
			if (DEBUG > 1) { System.out.println("move_vp: setpos"); }
			
			//BIND VP
			EventInSFBool set_bind = null;
			try {
				if (vpinuse == 0){
					set_bind = (EventInSFBool)center_vp.getEventIn("set_bind");
				}
				else {
					set_bind = (EventInSFBool)center_vp1.getEventIn("set_bind");
				}
			}
			catch(InvalidEventInException e) {
				System.out.println("move_vp: InvalidEventInException: " + e);
				return;
			}
			if (DEBUG > 1) {System.out.println("move_vp: got the EventIn: "+set_bind);}

			set_bind.setValue(true);
			
			//JUMP VP
			EventInSFBool jump = null;
			try{
				if (vpinuse == 0){
					jump = (EventInSFBool) center_vp.getEventIn("set_jump");
				}
				else {
					jump = (EventInSFBool) center_vp1.getEventIn("set_jump");
				}
			}
			catch(InvalidEventInException e) {
				System.out.println("move_vp: InvalidEventInException: " + e);
				return;
			}
        	
        	
        	jump.setValue(true);
*/

		}
		
		
		
		
		if (DEBUG > 1) { System.out.println("move_vp() done."); }



	}

	/**
	 * ccHandleEventMapExceptions() handles exceptions that may have
	 * occurred during event mapping.  This method will not be 
	 * regenerated by Cosmo Code and you may therefore freely modify it 
	 * to fit your needs.
	 */

	void ccHandleEventMapExceptions(Throwable thrown)
	{
		if (thrown instanceof ClassNotFoundException)
		{
			// TODO: Optionally provide your own error handling code

			System.err.println("EXCEPTION: Can't find class for EventMapper: " + thrown.getMessage());
		}
		else if (thrown instanceof NoSuchMethodException)
		{
			// TODO: Optionally provide your own error handling code

			System.err.println("EXCEPTION: Can't find method for event map: " + thrown.getMessage());
		}
		else
		{
			// TODO: Optionally provide your own error handling code

			System.err.println("EXCEPTION: Unexpected exception during event map: " + thrown.getMessage());
			thrown.printStackTrace();
		}
	}

	//{{ declarations - Begin Non-Editable Code Block
	java.awt.Label label1;
	java.awt.Label label2;
	java.awt.Label label3;
	java.awt.Label xout;
	java.awt.Label yout;
	java.awt.Label zout;
	java.awt.Button startbt;
	java.awt.TextField dtsName_TF;
	java.awt.TextField dtsPort_TF;
	java.awt.Label label7;
	java.awt.Label label8;
	java.awt.Button stopbt;
	MouseEventMapper mouseEventMapper;
	TextEventMapper textEventMapper;
	//}} declarations - End Non-Editable Code Block 

	//{{ adaptors - Begin Non-Editable Code Block
	//}} adaptors - End Non-Editable Code Block

	public void onStartbtMouseClicked(java.awt.event.MouseEvent event)
	{
		// TODO: Add code to handle this event.
		
		System.out.println("StartNet!");
		nt.start();
	}
	
	public void onStopbtMouseClicked(java.awt.event.MouseEvent event)
	{
		// TODO: Add code to handle this event.
		
		System.out.println("StopNet!");
		nt.stop();
	}
	public void onDtsName_TFTextValueChanged(java.awt.event.TextEvent event)
	{
		// TODO: Add code to handle this event.
		
		dtsName = dtsName_TF.getText();
	}

	public void onDtsPort_TFTextValueChanged(java.awt.event.TextEvent event)
	{
		// TODO: Add code to handle this event.
		
		dtsPort = new Integer(dtsPort_TF.getText()).intValue() ;
	}
}

/**
 * NetThread: Thread started from Promenad.init().
 *  We wake up 20 times per second, read data from the VirtualPointer
 *  and call Promenad.movevp()...
 */
class NetThread extends Thread {
		Promenad the_applet;

   	static long SLEEP_DELAY = 50;  // milliseconds

	private String host;
	private Socket so;
	private DataOutputStream out;
	private BufferedReader in;
	int port;
	int id;
	private String line = new String();
	int n;
	int i;

	NetThread(Promenad the_applet) {
		this.the_applet = the_applet;
	}
	
	public void run() {
		host = the_applet.dtsName;
		port = the_applet.dtsPort;
		System.out.println("NetThread: running..."+host+":"+port);

		try {
			so = new Socket(host, port);
			if (the_applet.DEBUG > 1) {System.out.println("Socket");}
			out = new DataOutputStream(so.getOutputStream());
			if (the_applet.DEBUG > 1) {System.out.println("stream");}
			in = new BufferedReader(new InputStreamReader(so.getInputStream()));
			
			//line = in.readLine();
			//if (the_applet.DEBUG > 1) {System.out.println("line:"+line);}
			
			//???????????????????????????????????????????????????????
			
			for( int i = 0; i < 7; i++){
				n = in.read();
				line = line + (char)n;
			}
			if (the_applet.DEBUG > 1) {System.out.println("line:"+line);} 
			 
			
			// ???????????????????????????
			
			while (true) {

				the_applet.NetRun = 1;
		
				try {sleep(SLEEP_DELAY);}
				catch (InterruptedException e) {}
				
				out.writeBytes("test \n");
				
				line = in.readLine();
				if (the_applet.DEBUG > 1) { System.out.println("line:"+line); }
				
				//if (the_applet.DEBUG == 1) { System.out.print("."); }
				//???????????????????????????????????????????????????????
			/*
				line = "";
				
				for( i = 0 ; i < 14 ; i++ ){
					n = in.read();
					line = line + (char)n;
				}
				if (the_applet.DEBUG > 1) {System.out.println("line:"+line);} 
			 
			*/
				// ???????????????????????????
				
				StringTokenizer st = new StringTokenizer(line,",");
				//StringTokenizer st = new StringTokenizer(line," ");

				float pos[] = new float[3];
				pos[0] = (Float.valueOf(st.nextToken())).floatValue();
				pos[1] = (Float.valueOf(st.nextToken())).floatValue();
				pos[2] = (Float.valueOf(st.nextToken())).floatValue();

				if (the_applet.DEBUG > 1) {
					System.out.println("x:"+pos[0]);
					System.out.println("y:"+pos[1]);
					System.out.println("z:"+pos[2]); 
				}
				
				the_applet.apos[0] = pos[0];
				the_applet.apos[1] = pos[1];
				the_applet.apos[2] = pos[2];
				
				//System.out.println("NetThread: tick.");

			}
		} catch (UnknownHostException e) {
			System.err.println("Bad host name.");
		} catch (IOException e) {
			System.err.println("Error connecting the server.");
		} catch (NumberFormatException e) {
			System.err.println("Bad ID.");
		} catch (SecurityException e) {
			System.err.println("Security.");
		}

		the_applet.NetRun = 0;
	}

	public void quit() {
		try {
			out.writeBytes("quit \n");
			so.close();
		} catch (IOException e) {
			System.err.println("Error connecting the server.");
		}
	}



}



/**
 * Two class for calc orientation
 *
 */
 
class orient {
		double[] v;
		double	theta;

	orient(double[] v,double theta) {
		this.v=v;
		this.theta = theta;
	}
}

class quaternion{
		double[] vect;
		double	real; 

	quaternion(double[] v,double r) {
		this.vect = v;
		this.real = r;
	}
}

/**
 * MoveVpThread: Thread started from Promenad.init().
 *  We wake up 20 times per second
 *  and call Promenad.movevp()...
 */
class MoveVpThread extends Thread {
		Promenad the_applet;

   	static long SLEEP_DELAY = 50;  // milliseconds
	private EventInSFVec3f set_position = null;
	private EventInSFRotation set_orientation = null;
	
	

	MoveVpThread(Promenad the_applet) {
		this.the_applet = the_applet;
	}
	
	double VDist(double[] v1, double[] v2) {
		return 	(double)(Math.sqrt((v1[0]-v2[0])*(v1[0]-v2[0]) + 
					(v1[1]-v2[1])*(v1[1]-v2[1]) + 
					(v1[2]-v2[2])*(v1[2]-v2[2]))) ;
	}

	double VMod(double[] v) {
		return 	(double)(Math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2])) ;
	}

	double VDot(double[] v1, double[] v2){
		return (double)(v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]) ;
	}

	double[] VAdd(double[] v1, double[] v2) {
	   	double r[] = new double[3];
	   	r[0] = v1[0] + v2[0];
	   	r[1] = v1[1] + v2[1];
	   	r[2] = v1[2] + v2[2];
		return r;
	}

	double[] VSub(double[] v1, double[] v2){
		double r[] = new double[3];
	   	r[0] = v1[0] - v2[0];
	   	r[1] = v1[1] - v2[1];
	   	r[2] = v1[2] - v2[2];
		return r;
	}

	double[] VCross(double[] v1, double[] v2){
		double r[] = new double[3];
		r[0] = v1[1]*v2[2] - v1[2]*v2[1];
	   	r[1] = v1[2]*v2[0] - v1[0]*v2[2];
	   	r[2] = v1[0]*v2[1] - v1[1]*v2[0];
		return r;
	}

	double[] VScalarMul(double[] v, double d){
		double r[] = new double[3];
        r[0] = v[0] * d;
        r[1] = v[1] * d;
        r[2] = v[2] * d;
		return r;
	}

	double[] VUnit(double[] v)	{
		double r[] = new double[3];
		r = VScalarMul(v, (double)(1.0 / VMod(v)));
		return r;
	}

	

	orient quaternionToOrientation (quaternion q) {
		double axis[] = new double[3];
        double half_angle = (double)Math.acos(q.real);
        double sin_half_angle = (double)Math.sin(half_angle);
        double angle = (double)half_angle * 2;
        if ( sin_half_angle < 1e-8 && sin_half_angle > -1e-8 ){
			axis[0] = 0;
			axis[1] = 0;
			axis[2] = 0;
		}
        else
        {
			sin_half_angle = 1 / sin_half_angle;
			axis = VScalarMul(q.vect, sin_half_angle);
		}
		orient ori = new orient(axis,angle);

		return ori;

	}

	quaternion qqMul2 (double[] v1, double r1, double[] v2, double r2) {
		double resr  = (double)r1  * r2  - VDot(v1 , v2 );        
		double[] resv = VCross(v1 , v2 );
		double[] temp_v = VScalarMul(v1 , r2 );
		resv = VAdd(temp_v, resv);
		temp_v = VScalarMul(v2 , r1 );
		resv = VAdd(temp_v, resv);
		quaternion resq = new quaternion(resv, resr);
		return resq;
	}

	quaternion buildRotateQuaternion(double[] axis, double cos_angle) {
		if ( cos_angle > 1.0 ) cos_angle = (double)1.0;
		if ( cos_angle < -1.0 ) cos_angle = (double)-1.0;
		double angle = (double)Math.acos(cos_angle);
		double sin_half_angle = (double)Math.sin(angle / 2);
		double cos_half_angle = (double)Math.cos(angle / 2);
		quaternion quat = new quaternion(VScalarMul(axis, sin_half_angle), cos_half_angle);

		return quat;
	}

	orient convertCameraModel(double[] pos, double[] at, double[] up) {
		double tempv[] = new double[3];
		tempv[0] = 0;
		tempv[1] = 0;
		tempv[2] = 0;
		orient ori = new orient(tempv,(double)0.0); 

		quaternion norm_quat = new quaternion(tempv,(double)0.0);
		quaternion inv_norm_quat =  new quaternion(tempv,(double)0.0);
		double tempv1[] = new double[3];
		tempv1[0] = 0;
		tempv1[1] = 1;
		tempv1[2] = 0;
		quaternion y_quat = new quaternion(tempv1,(double)0.0);

		double[] n = VUnit(VSub(at, pos));
		up = VUnit(up);
		double[] v = VUnit(VSub(up, VScalarMul(n, VDot(up, n))));
		
		double norm_axis[] = new double[3];
		norm_axis[0] = n[1];
		norm_axis[1] = -n[0];
		norm_axis[2] = 0;
		
		if ( VDot(norm_axis, norm_axis) < 1e-8 ) {
			if ( n[2] > 0.0 ) {
				norm_quat.real= (double)0.0;
				norm_quat.vect[0] = 0;
				norm_quat.vect[1] = 1;
				norm_quat.vect[2] = 0;
			}
			else
			{
				norm_quat.real= (double)1.0;
				norm_quat.vect[0] = 0;
				norm_quat.vect[1] = 0;
				norm_quat.vect[2] = 0;
			}
		}
		else {
			norm_axis = VUnit(norm_axis);
			norm_quat = buildRotateQuaternion(norm_axis, -n[2]);
		}
 
		inv_norm_quat =  new quaternion(VScalarMul(norm_quat.vect, -1),
						norm_quat.real);
 
		quaternion new_y_quat = qqMul2(norm_quat.vect, norm_quat.real, 
					y_quat.vect, y_quat.real);
					
		new_y_quat = qqMul2(new_y_quat.vect, new_y_quat.real, 
				inv_norm_quat.vect, inv_norm_quat.real);
				
		double temp_v[] = new double[3];
		temp_v = VCross(new_y_quat.vect, v);
		
		if ( VDot(temp_v, temp_v) < 1.e-8 )
		{
			temp_v[0] = 0;
			temp_v[1] = -v[2];
			temp_v[2] = v[1];
			if ( VDot(temp_v, temp_v) < 1.e-8 ){
				temp_v[0] = v[2];
				temp_v[1] = 0;
				temp_v[2] = -v[0];
			}
		}
		
		quaternion rot_y_quat = buildRotateQuaternion(VUnit(temp_v),
						VDot(new_y_quat.vect, v)); 
		quaternion rot_quat = qqMul2(norm_quat.vect, norm_quat.real,
				rot_y_quat.vect, rot_y_quat.real);
		ori = quaternionToOrientation(rot_quat);

		return ori;
	}
	
	public void iter_vp(float x, float y, float z){
		float dx = 0;
		float dy = 0;
		float dz = 0;
		int step = 5;					// the number of iteration
		double at[] = new double[3];
		double up[] = new double[3];
		double from[] = new double[3];
		float orientation[] = new float[4];
		float ipos[] = new float[3];
		at[0] = 1.5;							//ide kell a kozeppont
		at[1] = 1.1;
		at[2] = -1000;
		up[0] = 0;
		up[1] = 1;
		up[2] = 0;
		from[0] = 0;
		from[1] = 0;
		from[2] = 0;
		ipos[0] = 0;
		ipos[1] = 0;
		ipos[2] = 0;
		orientation[0] = 0;
		orientation[1] = 0;
		orientation[2] = 0;
		orientation[3] = 0;
		
		if((the_applet.isChStatus == 1) && (z < 1.5)){
			the_applet.chVrmlObj();
			the_applet.isChStatus = 0;
		}
		
		if (z > 3.2) {
			the_applet.isChStatus = 1;
		}
		
				
		if( !((the_applet.opos[0] == x) && (the_applet.opos[1] == y) && (the_applet.opos[2] == z)) ){
		
		
			dx = x - the_applet.opos[0];
			dy = y - the_applet.opos[1];
			dz = z - the_applet.opos[2];
			
			
			
			for( int i = 1; i <= step ; i++){
				from[0] = the_applet.opos[0] + (i*(dx/step));
				from[1] = the_applet.opos[1] + (i*(dy/step));
				from[2] = the_applet.opos[2] + (i*(dz/step));
				
				ipos[0] = (float)from[0];
				ipos[1] = (float)from[1];
				ipos[2] = (float)from[2];
				the_applet.xout.setText(" "+from[0]);
				the_applet.yout.setText(" "+from[1]);
				the_applet.zout.setText(" "+from[2]);
				
				orient ori = convertCameraModel(from,at,up);
				
				if (the_applet.DEBUG > 1) {			
					System.out.println("p-x:"+from[0]+",y:"+from[1]+",z:"+from[2]);
					System.out.println("o-x:"+ori.v[0]+",y:"+ori.v[1]+",z:"+ori.v[2]+",r:"+ori.theta);
				}
				
				orientation[0] = (float)ori.v[0];
				orientation[1] = (float)ori.v[1];
				orientation[2] = (float)ori.v[2];
				orientation[3] = (float)ori.theta;
				
				set_position.setValue(ipos);
				set_orientation.setValue(orientation);
		
				if (the_applet.DEBUG > 1) { System.out.println("movevp: setpos"); }
			}

						
			the_applet.opos[0] = x;
			the_applet.opos[1] = y;
			the_applet.opos[2] = z;
		}
		
		
	}

	
	public void run() {

		
		System.out.println("MoveVpThread: running...");

		try {
			set_position = (EventInSFVec3f)the_applet.center_vp.getEventIn("set_position");
		}
		catch(InvalidEventInException e) {
			System.out.println("move_vp: InvalidEventInException: " + e);
			return;
		}
		
		try {
			set_orientation = (EventInSFRotation)the_applet.center_vp.getEventIn("set_orientation");
		}
		catch(InvalidEventInException e) {
			System.out.println("move_vp: InvalidEventInException: " + e);
			return;
		}
		
		while (true) {
			try {sleep(SLEEP_DELAY);}
			catch (InterruptedException e) {}
			
			iter_vp(the_applet.apos[0],the_applet.apos[1],the_applet.apos[2]);
			
		}
	}

}


















