/**
 * Listen for state changes in clocks
 */

package client;

import service.*;
import xmltypes.*;

import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.Document;
import java.awt.*;

import org.cybergarage.upnp.*;
import org.cybergarage.upnp.device.*;
import org.cybergarage.upnp.control.*;
import org.cybergarage.http.*;
import org.cybergarage.upnp.ssdp.*;
import org.cybergarage.upnp.event.*;

import java.net.URL;
import java.net.HttpURLConnection;

public class UI extends JFrame implements EventListener, NotifyListener 
{
    private ControlPoint ctrlPoint = new ControlPoint();
    private DeviceList knownDevices = new DeviceList();
    private StateVariable timeVar;

    private FlowLayout layout = new FlowLayout();
    private Container contentPane = getContentPane();

    public static void main(String[] args) {
	UI client = new UI();
    }

    public UI()
    {
	UPnP.setEnable(UPnP.USE_ONLY_IPV4_ADDR);

	org.cybergarage.util.Debug.on();

	ctrlPoint.addNotifyListener(this);
	ctrlPoint.addEventListener(this);
	ctrlPoint.start();

	contentPane.setLayout(layout);
	setSize(200, 200);
	setVisible(true);
    }

    public void eventNotifyReceived(String uuid, long seq, 
				    String varName, String value) {
	System.out.println("UUID: \"" +  uuid + "\"");
	System.out.println("Name: \"" +  varName + "\"");
	System.out.println("Value: \"" +  value + "\"");
    }


    public void deviceNotifyReceived(SSDPPacket ssdpPacket) { 
	if ( ! ssdpPacket.getNTS().equals("ssdp:alive")) {
	    return;
	}

	/* This code cleaned up to avoid repeating
	 * service finds, but no changes of relevance
	 * to UI
	 */

	/* We can get multiple packets for one device from multiple
	 * UDP packets sent in case one is lost. Also, we get
	 * rebroadcasts every few minutes. This is tedious
	 */

	Device dev = getDeviceFromPacket(ssdpPacket);
	if (dev == null) {
	    // This can happen if the packet describes a service, 
	    // a device, but not a ROOT device
	    return;
	}

	// process the packet if it is for a new device
	if (isNewDevice(dev)) {
	    if (dev.getDeviceType().equals("urn:schemas-upnp-org:device:clock:1")) {
		// Change start
		// The presentation URL is relative e.g. /presentation
		String presentationURL = dev.getPresentationURL();
		System.out.println("Presentation url is \"" + 
				   presentationURL + "\"");
		// the URLBase is the http://hostname
		String urlBase = dev.getURLBase();
		System.out.println("Adding new device " + dev);
		System.out.println("From packet " + ssdpPacket);
		addClock(/* urlBase + */ presentationURL);
		// Change end
	    }
	} else {
	    System.out.println("Seen this device before " + dev);
	}
    } 

    /* New code, just cleans up old stuff
     * No changes for UI
     */
    private Device getDeviceFromPacket(SSDPPacket packet) {
	DeviceList devList = ctrlPoint.getDeviceList();
	for (int n = 0; n < devList.size(); n++) {
	    Device dev = devList.getDevice(n);
	    if (dev.getSSDPPacket() == packet) {
		return dev;
	    }
	}
	// this will happen for services/embedded devices etc
	System.out.println("No device found for packet " + packet);
	return null;
    }

    /* New code, just cleans up old stuff
     * No changes for UI
     */
    private boolean isNewDevice(Device dev) {
	System.out.println("UDN " + dev.getUDN());

	for (int n = 0; n < knownDevices.size(); n++) {
	    if (dev.getUDN().equals(knownDevices.getDevice(n).getUDN())) {
		return false;
	    }
	}
	knownDevices.add(dev);
	return true;
    }

    // Change start has to get UI from device and display it
    // Display is done here in a JEditPane
    private void addClock(String url) {
	// get HTML page from URL, put it in a component and add it to this
	System.out.println("URL is " + url);

	/* OR: use Runtime.exec() to start IE,Netscape, etc
	 * and pass it the URL
	 */

	/* JEditorPane DOES handle forms properly after all!
	 */
	final JEditorPane pane = new JEditorPane();
	try {
	    pane.setPage(url);
	    pane.setEditable(false); // or we can't follow hyperlinks
	    System.out.println("New page contents " + pane.getText());
	    contentPane.add(pane);
	} catch(IOException e) {
	    e.printStackTrace();
	}

	// listen for hyperlink events
	pane.addHyperlinkListener(new HyperlinkListener() {
	        // user over/clicking Refresh hyperlink
		public void hyperlinkUpdate(HyperlinkEvent e) {
		    java.net.URL url = e.getURL();

		    // Turn caching off! 
		    // Due to a bug in  JEditorPane, this doesn't work
		    HttpURLConnection uc = null;
		    try {
			uc = (HttpURLConnection)url.openConnection();
		    } catch(IOException ioe) {
			ioe.printStackTrace();
			return;
		    }
		    uc.setUseCaches(false);

		    if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
			try {
			    // url was clicked on - we should reload the page

			    // WORKAROUND for JEditorPane bug always caching
			    // url even if it's contents have changed, or
			    // Expires has happened or Cache-Control set to
			    // "no-cache", etc
			    // Clear the internal URL object in this control
			    // TO PREVENT URL CACHING...
			    Document doc = pane.getDocument();
			    doc.putProperty(Document.StreamDescriptionProperty,null);
			    // Sun know of this bug, and just promise to fix the doco :-(

			    // now reload it
			    pane.setPage(url);
			} catch(IOException ioe) {
			    ioe.printStackTrace();
			}
		    }
		}
	    }
	 );
    }
    // Change end
}

