package com.phonegap;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;

/**
 * This class provides a way for Java to run JavaScript in the web page that has loaded PhoneGap.
 * The CallbackServer class implements an XHR server and a list of JavaScript statements
 * that are to be executed on the web page.
 * 
 * The process flow is:
 * 1. JavaScript makes an async XHR call. 
 * 2. The server holds the connection open until data is available. 
 * 3. The server writes the data to the client and closes the connection. 
 * 4. The server immediately starts listening for the next XHR call. 
 * 5. The client receives this XHR response, processes it.
 * 6. The client sends a new async XHR request.
 *
 */
public class CallbackServer implements Runnable {
	
	/**
	 * The list of JavaScript statements to be sent to JavaScript.
	 */
	private LinkedList<String> javascript;
	
	/**
	 * The port to listen on.
	 */
	private int port;
	
	/**
	 * The server thread.
	 */
	private Thread serverThread;
	
	/**
	 * Indicates the server is running.
	 */
	private boolean active;
	
	/**
	 * Indicates that the JavaScript statements list is empty
	 */
	private boolean empty;
	
	/**
	 * Constructor.
	 */
	public CallbackServer() {
		//System.out.println("CallbackServer()");
		this.active = false;
		this.empty = true;
		this.port = 0;
		this.javascript = new LinkedList<String>();
		this.startServer();
	}
	
	/**
	 * Get the port that this server is running on.
	 * 
	 * @return
	 */
	public int getPort() {
		return this.port;
	}
	
	/**
	 * Start the server on a new thread.
	 */
	public void startServer() {
		//System.out.println("CallbackServer.startServer()");
		this.active = false;
		
		// Start server on new thread
		this.serverThread = new Thread(this);
		this.serverThread.start();
	}

	/**
	 * Restart the server on a new thread.
	 */
	public void restartServer() {
		
		// Stop server
		this.stopServer();
				
		// Start server again
		this.startServer();
	}

	/**
	 * Start running the server.  
	 * This is called automatically when the server thread is started.
	 */
	public void run() {
		
		// Start server
		try {
			this.active = true;
			String request;
			ServerSocket waitSocket = new ServerSocket(0);
			this.port = waitSocket.getLocalPort();
			//System.out.println(" -- using port " +this.port);

			 while (this.active) {
				 //System.out.println("CallbackServer: Waiting for data on socket");
				 Socket connection = waitSocket.accept();
				 BufferedReader xhrReader = new BufferedReader(new InputStreamReader(connection.getInputStream()),40);
				 DataOutputStream output = new DataOutputStream(connection.getOutputStream());
				 request = xhrReader.readLine();
				 //System.out.println("Request="+request);
				 if(request.contains("GET"))
				 {
					 //System.out.println(" -- Processing GET request");
					 
					 // Wait until there is some data to send, or send empty data every 30 sec 
					 // to prevent XHR timeout on the client 
					 synchronized (this) { 
						 while (this.empty) { 
							 try { 
								 this.wait(30000); // prevent timeout from happening
								 //System.out.println(">>> break <<<");
								 break;
							 } 
							 catch (Exception e) { }
						 } 
					 }
					 
					 // If server is still running
					 if (this.active) {
					
						 // If no data, then send 404 back to client before it times out
						 if (this.empty) {
							 //System.out.println(" -- sending data 0");
							 output.writeBytes("HTTP/1.1 404 NO DATA\r\n\r\n");
						 }
						 else {
							 //System.out.println(" -- sending item");
							 output.writeBytes("HTTP/1.1 200 OK\r\n\r\n"+this.getJavascript());
						 }
					 }					 
				 }
				 //System.out.println("CallbackServer: closing output");
				 output.close();				 
			 }
		 } catch (IOException e) {
			 e.printStackTrace();
		 }
		 this.active = false;
		 //System.out.println("CallbackServer.startServer() - EXIT");
	}
		
	/**
	 * Stop server.  
	 * This stops the thread that the server is running on.
	 */
	public void stopServer() {
		//System.out.println("CallbackServer.stopServer()");
		this.active = false;

		// Break out of server wait
		synchronized (this) { 
			this.notify();
		}		
	}

    /**
     * Destroy
     */
    public void destroy() {
    	this.stopServer();
    }

	/**
	 * Get the number of JavaScript statements.
	 * 
	 * @return int
	 */
	public int getSize() {
		int size = this.javascript.size();
		//System.out.println("getSize() = " + size);
		return size;
	}
	
	/**
	 * Get the next JavaScript statement and remove from list.
	 *  
	 * @return String
	 */
	public String getJavascript() {
		if (this.javascript.size() == 0) {
			return null;
		}
		String statement = this.javascript.remove(0);
		//System.out.println("CallbackServer.getJavascript() = " + statement);
		if (this.javascript.size() == 0) {
			synchronized (this) { 
				this.empty = true;
			}
		}
		return statement;
	}
	
	/**
	 * Add a JavaScript statement to the list.
	 * 
	 * @param statement
	 */
	public void sendJavascript(String statement) {
		//System.out.println("CallbackServer.sendJavascript("+statement+")");
		this.javascript.add(statement);
		synchronized (this) { 
			this.empty = false;
			this.notify();
		}
	}
	
}

Add callback server class.