/******************************************************************
 *
 *	CyberUPnP for Java
 *
 *	Copyright (C) Satoshi Konno 2002
 *
 *	File : ClockDevice.java
 *
 ******************************************************************/

package device;

import service.*;
import xmltypes.*;

import java.io.*;

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

public class ClockDevice extends Device implements ActionListener, QueryListener, NotifyListener 
{
    private final static String DESCRIPTION_FILE_NAME = "description/description.xml";
    private final static String PRESENTATION_URI = "clock/presentation";

    private ControlPoint ctrlPoint = new ControlPoint();
    
    private Timer timer;
    private Service timerService;

    private Device lastDeviceSeen;

    public ClockDevice() throws InvalidDescriptionException
    {
	super(new File(DESCRIPTION_FILE_NAME));

	
	UPnP.setEnable(UPnP.USE_ONLY_IPV4_ADDR);

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

	ctrlPoint.addNotifyListener(this);
	ctrlPoint.start();
	
	Action getTimeAction = getAction("GetTime");
	getTimeAction.setActionListener(this);
	
	Action setTimeAction = getAction("SetTime");
	setTimeAction.setActionListener(this);
	
	Action timeValidAction = getAction("TimeValid");
	timeValidAction.setActionListener(this);
	
	ServiceList serviceList = getServiceList();
	// there should only be a timer service
	timerService = serviceList.getService(0);
	timerService.setQueryListener(this);
	
	setLeaseTime(60);
    }

    public void setTimer(Timer t) {
	timer = t;
	System.out.println("Timer " + timer + " service " + timerService);
	// *****************************************
	// This is the only line that really changed
	// *****************************************
	// Change start
	timer.setService(timerService);
	// Change end
	System.out.println("Our timer service is " + t);
    }
    
    ////////////////////////////////////////////////
    // ActionListener
    ////////////////////////////////////////////////
    
    public boolean actionControlReceived(Action action)
    {
	String actionName = action.getName();
	if (actionName.equals("GetTime") == true) {
	    System.out.println("GetTime action control");

	    Time now = timer.getTime();
	    Argument timeArg = action.getArgument("CurrentTime");
	    timeArg.setValue(now.toString());
	    return true;
	}
	if (actionName.equals("SetTime") == true) {
	    System.out.println("SetTime action control");
	    Argument timeArg = action.getArgument("NewTime");
	    String newTime = timeArg.getValue();
	    timer.setTime(new Time(newTime));
	    System.out.println("SetTime action to " + newTime);
	    return true;
	}
	if (actionName.equals("TimeValid") == true) {
	    System.out.println("TimeValid action control");
	    boolean timeValid = timer.isValidTime();

	    Argument timeArg = action.getArgument("Valid");
	    timeArg.setValue("" + timeValid);
	    return true;
	}
	return false;
    }
    
    ////////////////////////////////////////////////
    // QueryListener
    ////////////////////////////////////////////////

    // Change start    
    public boolean queryControlReceived(StateVariable stateVar)
    {
	System.out.println("query control");
	if (stateVar.getName().equals("Time")) {
	    stateVar.setValue(getTime().toString());
	    return true;
	} else if (stateVar.getName().equals("TimeValid")) {
	    stateVar.setValue("" + isValidTime());
	    return true;
	}
	return false;
    }
    // Change end
    
    ////////////////////////////////////////////////
    // HttpRequestListner
    ////////////////////////////////////////////////

    public void httpRequestRecieved(HTTPRequest httpReq)
    {
	System.out.println("HTTP request: " + httpReq);
	
	String uri = httpReq.getURI();
	if (uri.startsWith(PRESENTATION_URI) == false) {
	    super.httpRequestRecieved(httpReq);
	    return;
	}
    }

    public void setTime(Time time) {
	System.out.println("setTime in clock device to " + time);
	timer.setTime(time);
    }

    public Time getTime() {
	return timer.getTime();
    }

    public boolean isValidTime() {
	return timer.isValidTime();
    }

    public void deviceNotifyReceived(SSDPPacket ssdpPacket) { 

	System.out.println("New SSDPPacket, all " + ssdpPacket);
	/* There doesn;t seem to be a simple way of getting the new
	 * device from the packet, even though CyberLink creates a
	 * new device from it - and adds it to a list. Looks like we
	 * have to get the whole list and search through it for the
	 * device created by this packet :-(
	 */
	DeviceList devList = ctrlPoint.getDeviceList();
	Device dev = null;
	System.out.println("Devices: " + devList.size());
	for (int n = 0; n < devList.size(); n++) {
	    if (devList.getDevice(n).getSSDPPacket() == ssdpPacket) {
		System.out.println("Found the new device matching SSDP packet");
		dev = devList.getDevice(n);
		break;
	    }
	}
	if (dev == null) {
	    // couldn't find it? That shouldn't happen...
	    return;
	}

	ServiceList timerServices = new ServiceList();

	if (dev.getDeviceType().equals("urn:schemas-upnp-org:device:clock:1")) {
	    ServiceList services = dev.getServiceList();
	    for (int m = 0; m < services.size(); m++) {
		Service svc = services.getService(m);
		if (svc.getServiceType().equals("urn:schemas-upnp-org:service:timer:1")) {
		    timerServices.add(svc);
		}
	    }
	}

	tryClockValidation(timerServices);
    } 

    private ServiceList getTimerServices() {
	ServiceList timerServices = new ServiceList();

	DeviceList devList = ctrlPoint.getDeviceList();
	System.out.println("Devices: " + devList.size());
	for (int n = 0; n < devList.size(); n++) {
	    Device dev = devList.getDevice(n);
	    if (dev.getDeviceType().equals("urn:schemas-upnp-org:device:clock:1")) {
		ServiceList services = dev.getServiceList();
		for (int m = 0; m < services.size(); m++) {
		    Service svc = services.getService(m);
		    if (svc.getServiceType().equals("urn:schemas-upnp-org:service:timer:1")) {
			timerServices.add(svc);
		    }
		}
	    }
	}
	return timerServices;
    }

    private void tryClockValidation(ServiceList services) {
	org.cybergarage.util.Debug.on();
	for (int n = 0; n < services.size(); n++) {
	    Service svc = (Service) services.elementAt(n);

	    System.out.println("Checking service " + svc);
	    Action validAction = svc.getAction("TimeValid");
	    if (validAction.postControlAction()) {
		System.out.println("Checking TimeValid succeeded");
		Argument arg = validAction.getArgument("Valid");
		String value = arg.getValue();
		System.out.println("valid time? " + value);
		if (isValidTime() && value.equals("false")) {
		    // other clock needs to be set
		    Action setTimeAction = svc.getAction("SetTime");
		    setTimeAction.setArgumentValue("NewTime",
						    getTime().toString());
		    setTimeAction.postControlAction();
		} else if (! isValidTime() && value.equals("true")) {
		    Action getTimeAction = svc.getAction("GetTime");
		    if ( ! getTimeAction.postControlAction()) {
			System.out.println("GetTime post action failed");
		    }

		    Argument arg2 = getTimeAction.getArgument("CurrentTime");
		    Object val = arg2.getValue();
		    System.out.println("Arg type " +  val.getClass());
		    System.out.println("setTime in clock validation to " + arg2.getValue());
		    setTime(new Time(arg2.getValue()));
		}
	    }
	}
    }
}

