import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

import java.io.*;
import java.util.*;

import net.jxta.j2me.PeerNetwork;
import net.jxta.j2me.Message;
import net.jxta.j2me.Element;

public class MainChat extends MIDlet implements CommandListener, Runnable
{
	private Display display = null;
	
	private PeerNetwork peer;
	private byte[] persistentState = null;
	private boolean tryConnect = false;
	private boolean connected = false;
	private Thread pollThread = null;
	
	private String peerName = null;
	private String relayHost = null;
	private String relayPort = null;
	
	private int messageID;
	private String propaPipeID = "urn:jxta:uuid-" + "59616261646162614E50472050325033" + 
	                                            //"D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D104";
                                                    "D1D1D1D1D1D141D191D191D1D1D1D1D104";
    private String myPipeID = null;
    private long lastPropa = 0;
    private long lastCheck = 0;
    
    private Vector buddyListItemNumber = new Vector();
    private Vector buddyListNames = new Vector();
    private Vector buddyListPipes = new Vector();
    private Vector buddyListTimes = new Vector();
    //private List buddyListDisplay = new List("Online Buddies", List.EXCLUSIVE);
    private ChoiceGroup buddyChoiceGroup = new ChoiceGroup("Online Buddies", Choice.EXCLUSIVE);
    

    private TextBox sendScreen = new TextBox("", null, 256, TextField.ANY);
    private Command cmdSend = new Command("Send", Command.OK, 1);
    private Command cmdBack = new Command("Back", Command.BACK, 1);
    
    
    
// Stuff of the Intro Config Screen
	private Form configForm = null;
	private TextField peerNameTF = null;
	private TextField relayHostTF = null;
	private TextField relayPortTF = null;
	private StringItem title = null;
	private StringItem subTitle = null;
	private Command cmdGoOnline = new Command("Go Online", Command.SCREEN, 1);
	private Command cmdExit = new Command("Exit", Command.EXIT, 6);
	
// Stuff of the Online Screen	
	private Form onlineForm = null;
	//private StringItem onlineTitle = null;
	private Command cmdGoOffline = new Command("Go Offline", Command.SCREEN, 2);
	private Command cmdChat = new Command("Chat", Command.SCREEN, 1);
	
	
	
	public MainChat()
	{
		setupConfigScreen();
		setupSendScreen();
		showOnlineSetup();
		
	}
	
	public void commandAction(Command c, Displayable d)
	{
		if(c == cmdExit) 
		{
            destroyApp(true);
            notifyDestroyed();
            return;
     	}
     	else if(c == cmdGoOnline)
     	{
	     	peerName = peerNameTF.getString();
	     	relayHost = relayHostTF.getString();
	     	relayPort = relayPortTF.getString();
	     	
	     	tryConnect = true;
	     	pollThread = new Thread(this);
	     	pollThread.start();
	     	display.setCurrent(onlineForm);
     	} 
     	else if(c == cmdGoOffline)
     	{
	     	try
	     	{
		     	peer.close(propaPipeID);
		     	peer.close(myPipeID);
	     		display.setCurrent(configForm);
	     	
	     		connected = false;
	     		pollThread = null;
			}
			catch(IOException e)
			{
			}
		}
     	else if(c == cmdChat)
     	{
// 	     	try
// 	     	{
// 		     	System.out.println("chat");
// 				Message imAlive = createP2PMessage(peerName, myPipeID, "hello");
// 				messageID = peer.send(myPipeID, imAlive);
// 				
// 			}
// 			catch(IOException e)
// 			{
// 			}
			int indexOfBuddy = buddyChoiceGroup.getSelectedIndex();
			String sendScreenTitle = "To " + (String)buddyListNames.elementAt(indexOfBuddy);
			sendScreen.setTitle(sendScreenTitle);
			display.setCurrent(sendScreen);
		}
		else if(c == cmdBack)
		{
			display.setCurrent(onlineForm);
		}
		else if(c == cmdSend)
		{
			try
	     	{
		     	System.out.println("chat");
				Message p2pMessage = createP2PMessage(peerName, myPipeID, sendScreen.getString());
				
				int indexOfBuddy = buddyChoiceGroup.getSelectedIndex();
				String pipeSend = (String)buddyListPipes.elementAt(indexOfBuddy);
				messageID = peer.send(pipeSend, p2pMessage);
				
				sendScreen.setString("");
				display.setCurrent(onlineForm);
				
			}
			catch(IOException e)
			{
			}
		}
	}
	
	public void setupSendScreen()
	{
		sendScreen.addCommand(cmdSend);
		sendScreen.addCommand(cmdBack);
		sendScreen.setCommandListener(this);
	}
	public void startApp()
	{
		display = Display.getDisplay(this);
		display.setCurrent(configForm);
	}
	
	public void destroyApp(boolean unconditional)
	{
	}
	
	public void pauseApp()
	{
	}
	
	public void setupConfigScreen()
	{
		
		configForm = new Form("Configuration");
		
		peerNameTF = new TextField("Peer Name: ", "anonymous", 256, TextField.ANY);
		relayHostTF = new TextField("Relay Host: ", "127.0.0.1", 256, TextField.ANY);
		relayPortTF = new TextField("Relay Port: ", "9700", 256, TextField.NUMERIC);
		
		title = new StringItem("Mobile JXME Chat", null, Item.PLAIN);
		subTitle = new StringItem("Enter Configuration Details", null, Item.PLAIN);
		
		configForm.append(title);
		configForm.append(subTitle);
		configForm.append(peerNameTF);
		configForm.append(relayHostTF);
		configForm.append(relayPortTF);
		
		configForm.addCommand(cmdGoOnline);
		configForm.addCommand(cmdExit);
		
		configForm.setCommandListener(this);
	}
	
	public void showOnlineSetup()
	{
		onlineForm = new Form("JXME CHAT-Online Peers");
		//onlineTitle = new StringItem("Online Peers", null, Item.PLAIN);
		//onlineForm.append(onlineTitle);
		onlineForm.append(buddyChoiceGroup);
		
		
		onlineForm.addCommand(cmdGoOffline);
		onlineForm.addCommand(cmdChat);
		onlineForm.setCommandListener(this);
	}
	
	public void connect()
	{
		try
		{
			peer = PeerNetwork.createInstance(peerName);
			persistentState = peer.connect("http://" + relayHost + ":" + relayPort, null);

			// create propa pipe
			messageID = peer.create(PeerNetwork.PIPE, "PropaPipe", propaPipeID, "JxtaPropagate" );
			Message msg = peer.poll(5000);
            processMessage(msg, messageID, "success");
			peer.listen(propaPipeID);
			msg = peer.poll(5000);
            processMessage(msg, messageID, "success");

			connected = true;
		}
		catch(IOException ie)
		{
		}
	}
	
	public void run()
	{
		if(tryConnect)
		{
			connect();
		}
		
		while(true)
		{
			myPipeID = createPipe(peerName);
			if(myPipeID != null)
			{
				try
				{
					peer.listen(myPipeID);
					Message msg = peer.poll(5000);
		            processMessage(msg, messageID, "success");
			    } 
			    catch (IOException ie) 
			    {
			        ie.printStackTrace ();
			    }
				break;
			}
		}
		System.out.println("mypipe");
// 		try
// 		{
// 			messageID = peer.create(PeerNetwork.PIPE, "PropaPipe", propaPipeID, "JxtaPropagate" );
// 			peer.listen(propaPipeID);
// 		}
// 		catch(IOException ie)
// 		{
// 		}
	
		while(connected && poll())
		{
			try
			{
				long time = System.currentTimeMillis();
				if (time - lastPropa > 5000)
				{
					lastPropa = time;
					Message imAlive = createImAliveMessage(peerName, myPipeID);
					messageID = peer.send(propaPipeID, imAlive);
					System.out.println(">>> propa message sent");
					
					for(int i = buddyListTimes.size() - 1; i >= 0; i-- )
					{
						if((time - (((Long)buddyListTimes.elementAt(i)).longValue())) > 9333)
						{
							int itemNum = ((Integer)buddyListItemNumber.elementAt(i)).intValue();
// 							onlineForm.delete(itemNum);
							buddyChoiceGroup.delete(itemNum);
							buddyListItemNumber.removeElementAt(i);
							buddyListNames.removeElementAt(i);
							buddyListPipes.removeElementAt(i);
							buddyListTimes.removeElementAt(i);
						}
					}
				}
//				Message msg = peer.poll(1);
//	            processMessage(msg, messageID, "success");
			}
			catch(IOException ie)
			{
			}
		}
		//msg = peerNetwork.poll(1000);
		
	}
	
	private boolean poll()
	{
		String buddyName = null;
		String buddyPipe = null;
		String P2PName = null;
		String P2PMessage = null;
	
		Message msg = null;
		try
		{
			msg = peer.poll(1000);
		}
		catch(IOException ex)
		{
		}
		
// 		if (msg == null) 
// 		{
//             return false;
//      }
		if (msg != null)
		{
			try
			{
				for(int j=0; j < msg.getElementCount(); j++)
				{
	                Element e = msg.getElement(j);
	                System.out.println(j + ": " + e.getName() + " = " + new String(e.getData()));
	                if(e.getName().equals("ALIVE"))
	                {
		                buddyName = new String(e.getData());
	                }
	                else if(e.getName().equals("myPipeID"))
	                {
		                buddyPipe = new String(e.getData());
	                }
	                else if(e.getName().equals("P2P"))
	                {
		                P2PName = new String(e.getData());
	                }
	                else if(e.getName().equals("P2PMessage"))
	                {
		                P2PMessage = new String(e.getData());
	                }
				}
			}
			catch(NumberFormatException ne)
			{
			}
			
			// for propa message
			if (buddyName != null)
			{
				System.out.println("+++++++++++++++++++++");
				System.out.println(buddyName);
				System.out.println(buddyPipe);
				System.out.println("+++++++++++++++++++++");
				
				
				Long time2 = new Long(System.currentTimeMillis());
				if(!buddyListNames.contains(buddyName))
				{

					//StringItem si = new StringItem(buddyName,null);
// 					int itemNum = onlineForm.append(si);
					int itemNum = buddyChoiceGroup.append(buddyName, null);
					Integer itemNum2 = new Integer(itemNum);
					buddyListItemNumber.addElement(itemNum2);
					//buddyListDisplay.append( buddyName, null);
					buddyListNames.addElement(buddyName);
					buddyListPipes.addElement(buddyPipe);
					buddyListTimes.addElement(time2);
				}
				else
				{
					int vectorIndex = buddyListNames.indexOf(buddyName);
					buddyListTimes.removeElementAt(vectorIndex);
					buddyListTimes.insertElementAt(time2, vectorIndex);
				}
				
// 				long time3 = System.currentTimeMillis();
// 				if (time3 - lastCheck > 5000)
// 				{
// 					lastCheck = time3;
// 					
// 				}
				
// 				StringItem si = new StringItem(buddyName,null);
// 				onlineForm.append(si);
				// add to list
			}
			// for P2P message
			else if (P2PName != null) // 
			{
				System.out.println("+++++++++++++++++++++");
				System.out.println("P2P MESSAGE");
				System.out.println(P2PName);
				System.out.println(buddyPipe);
				System.out.println(P2PMessage);
				System.out.println("+++++++++++++++++++++");
	
				Alert alert = new Alert("From " + P2PName, P2PMessage, null, AlertType.INFO);
				alert.setTimeout(Alert.FOREVER);
				display.setCurrent(alert);
			}
		}
        return true;
	}
	
	public Message createImAliveMessage(String pName, String myPipeID)
	{
			
        Element[] elements = new Element[2];		
        elements[0] = new Element("ALIVE", pName.getBytes(), null, null);
        elements[1] = new Element("myPipeID", myPipeID.getBytes(), null, null);
        Message message = new Message (elements);

        return message;
	}
    
	public Message createP2PMessage(String pName, String myPipeID, String msgText)
	{
			
        Element[] elements = new Element[3];		
        elements[0] = new Element("P2P", pName.getBytes(), null, null);
        elements[1] = new Element("myPipeID", myPipeID.getBytes(), null, null);
        elements[2] = new Element("P2PMessage", msgText.getBytes(), null, null);
        Message message = new Message (elements);

        return message;
	}
    
	public String createPipe(String pipeName)
    {
        String pipeId = null;	
        try 
        {
            int messageID = peer.create(PeerNetwork.PIPE, pipeName, null, PeerNetwork.UNICAST_PIPE);
            System.out.println(">>> create pipe request ... " + messageID);
            Message msg = peer.poll(5000);
            pipeId = processMessage(msg, messageID, "success");
            System.out.println(">>> create pipe request succeed, id : "+ pipeId );
        } 
        catch (IOException ie) 
        {
            ie.printStackTrace ();
        }
        return pipeId;
		
    }
    private String processMessage(Message msg, int reqId, String successCriterion)
    {
        int requestIdentifierInResponse = 0;
        String searchedResourceIdentifier = null;
        String responseString = null;
        try
        {
            for (int j=0; j < msg.getElementCount(); j++) 
            {
                Element e = msg.getElement(j);
                if ((e.getNameSpace()).equals("proxy")) 
                {
                    if ((e.getName()).equals("requestId"))
                        requestIdentifierInResponse = Integer.parseInt(new String(e.getData()));
                    else if ((e.getName()).equals("response"))
                        responseString = new String (e.getData());
                    else if ((e.getName()).equals("id"))
                        searchedResourceIdentifier = new String (e.getData());
                }
            }
            if (requestIdentifierInResponse == reqId) 
            {
                if (responseString.equals (successCriterion)) 
                {
                    if (searchedResourceIdentifier != null)
                    {
                        return searchedResourceIdentifier;	
                	}
                    else
                    {
	                    return responseString;
                    }
                }
            }
        }
        catch(NumberFormatException ne)
        {
            ne.printStackTrace();
        }
        return null;
    }
	
}