/*
 * Copyright (C) 2010 Teleal GmbH, Switzerland
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.teleal.cling.test.ssdp;

import org.teleal.cling.UpnpService;
import org.teleal.cling.model.Constants;
import org.teleal.cling.model.meta.RemoteDevice;
import org.teleal.cling.model.message.IncomingDatagramMessage;
import org.teleal.cling.model.message.UpnpRequest;
import org.teleal.cling.test.MockUpnpService;
import org.teleal.cling.test.data.SampleData;
import org.teleal.cling.transport.spi.DatagramProcessor;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.InetSocketAddress;


public class NotifyTest {

    @Test
    public void receivedByeBye() throws Exception {

        UpnpService upnpService = new MockUpnpService();

        RemoteDevice rd = SampleData.createRemoteDevice(SampleData.createRemoteDeviceIdentity(120));
        upnpService.getRegistry().addDevice(rd);
        Assert.assertEquals(upnpService.getRegistry().getRemoteDevices(true).size(), 1);

        String source = "NOTIFY * HTTP/1.1\r\n" +
                        "HOST: 239.255.255.250:1900\r\n" +
                        "NT: upnp:rootdevice\r\n" +
                        "NTS: ssdp:byebye\r\n" +
                        "USN: " +rd.getIdentity().getUdn().toString()+"::upnp:rootdevice\r\n\r\n";

        DatagramPacket packet =
                new DatagramPacket(
                        source.getBytes(),
                        source.getBytes().length,
                        new InetSocketAddress(Constants.IPV4_UPNP_MULTICAST_GROUP, Constants.UPNP_MULTICAST_PORT)
                );

        DatagramProcessor processor = upnpService.getConfiguration().getDatagramProcessor();
        IncomingDatagramMessage msg = processor.read(InetAddress.getByName("127.0.0.1"), packet);
        assert msg.getOperation() instanceof UpnpRequest;

        upnpService.getProtocolFactory().createReceivingAsync(msg).run();

        Assert.assertEquals(upnpService.getRegistry().getRemoteDevices(true).size(), 0);
    }

    /* TODO: What about these?
    
    @Test
    public void receivedInvalidMsg() throws Exception {

        Router upnpService = TestModel.createDisabledNetworkRouter();

        UpnpMessage msg = new UpnpMessage(UpnpMessage.Type.GET);
        ReceivingNotificationRequest prot = new ReceivingNotificationRequest(upnpService, msg) {
            @Override
            protected boolean isRootDeviceMessage() {
                throw new IllegalStateException("This should not be called if the message is GET");
            }
        };
        prot.run();
    }
    */



    /*
    
    protected Router createRegistryMatchingRouter() throws Exception {

        Router upnpService = new Router() {

            @Override
            public UpnpMessage sendStream(UpnpMessage msg) {
                // The end result of this test: A GET request for the device descriptor must arrive here
                Assert.assertEquals(msg.getType(), (UpnpMessage.Type.GET));
                Assert.assertEquals(msg.getUri().toString(), TestModel.getDeviceDescriptorURL().toString());

                // Send the mock response back
                UpnpMessage response = new UpnpMessage(UpnpMessage.Type.RESPONSE, msg.getUri());
                response.getHeaders().add(UpnpHeader.CONTENT_TYPE, new ContentTypeHeaderValue());
                response.setBody(TestModel.getSampleDeviceDescriptorUDA10());
                return response;
            }

        };

        // Execute Notify protocol in this thread so we get the exception in the test method
        upnpService.setAsyncProtocolExecutor(
                new Executor() {
                    public void execute(Runnable runnable) {
                        runnable.run();
                    }
                }
        );

        // Listen to registry events, this is the actual test condition that is important
        upnpService.getRegistry().addDeviceLifecycleListener(
                new DeviceLifecycleListener() {
                    public void deviceAdded(Registry registry, Device device) {
                        assert device instanceof LocalDevice;
                        assert device.isLocal();
                        TestModel.assertTestDataMatch((LocalDevice)device);
                        Assert.assertEquals(device.getMaxAge(), new Integer(2000));
                        throw new TestConditionMatched();
                    }
                    public void deviceUpdated(Registry registry, Device device) {
                    }
                    public void deviceRemoved(Registry registry, Device device) {
                    }
                }
        );

        return upnpService;
    }

    @Test(expectedExceptions = TestConditionMatched.class)
    public void receivedRootAliveRaw() throws Exception {

        Router upnpService = createRegistryMatchingRouter();
        LocalDevice device = (LocalDevice)TestModel.getLocalDevice();

        String source = "NOTIFY * HTTP/1.1\n" +
                        "HOST: 239.255.255.250:1900\n" +
                        "CACHE-CONTROL: max-age=2000\n" +
                        "LOCATION: "+device.getDescriptorURL().toString()+"\n" +
                        "NT: upnp:rootdevice\n" +
                        "NTS: ssdp:alive\n" +
                        "SERVER: foo/1 UPnP/1.0 bar/2\n" +
                        "USN: " +device.getUdn().toString()+"::upnp:rootdevice\n\n";

        DatagramPacket packet =
                new DatagramPacket(
                        source.getBytes(),
                        source.getBytes().length,
                        new InetSocketAddress(Constants.IPV4_UPNP_MULTICAST_GROUP, Constants.UPNP_MULTICAST_PORT)
                );

        DatagramProcessor processor = new DatagramProcessorImpl();
        UpnpMessage msg = processor.read(packet);
        Assert.assertEquals(msg.getType(), (UpnpMessage.Type.NOTIFY));

        upnpService.received(msg);
    }

    @Test(expectedExceptions = TestConditionMatched.class)
    public void receivedRootAlivePrepared() throws Exception {

        Router upnpService = createRegistryMatchingRouter();

        LocalDevice device = (LocalDevice)TestModel.getLocalDevice();

        UpnpMessage msg = new UpnpMessage(
                UpnpMessage.Type.NOTIFY,
                InetAddress.getByName(Constants.IPV4_UPNP_MULTICAST_GROUP),
                Constants.UPNP_MULTICAST_PORT
        );

        msg.getHeaders().add(UpnpHeader.HOST, new HostHeaderValue(Constants.IPV4_UPNP_MULTICAST_GROUP, Constants.UPNP_MULTICAST_PORT));
        msg.getHeaders().add(UpnpHeader.MAX_AGE, new MaxAgeHeaderValue(2000));
        msg.getHeaders().add(UpnpHeader.LOCATION, new LocationHeaderValue(device.getDescriptorURL()));
        msg.getHeaders().add(UpnpHeader.NT, new RootDeviceNTHeaderValue());
        msg.getHeaders().add(UpnpHeader.NTS, new NTSHeaderValue(NotificationType.ALIVE));
        msg.getHeaders().add(UpnpHeader.SERVER, new ServerHeaderValue());
        msg.getHeaders().add(UpnpHeader.USN, new RootDeviceUSNHeaderValue(device.getUdn()));

        upnpService.received(msg);
    }

    protected static class TestConditionMatched extends RuntimeException {}
    */

}