package com.openxc;

import java.io.File;
import java.io.IOException;

import java.lang.InterruptedException;

import java.net.URISyntaxException;
import java.net.URI;

import org.apache.commons.io.FileUtils;

import com.openxc.measurements.EngineSpeed;
import com.openxc.measurements.SteeringWheelAngle;
import com.openxc.measurements.VehicleMeasurement;
import com.openxc.measurements.VehicleSpeed;
import com.openxc.measurements.UnrecognizedMeasurementTypeException;

import com.openxc.remote.NoValueException;
import com.openxc.remote.RemoteVehicleServiceException;
import com.openxc.remote.sources.trace.TraceVehicleDataSource;

import com.openxc.VehicleService;

import android.content.Intent;

import android.test.ServiceTestCase;

import android.test.suitebuilder.annotation.MediumTest;

import junit.framework.Assert;

public class BoundVehicleServiceTest extends ServiceTestCase<VehicleService> {
    VehicleService service;
    VehicleSpeed speedReceived;
    SteeringWheelAngle steeringAngleReceived;
    URI traceUri;

    VehicleSpeed.Listener speedListener = new VehicleSpeed.Listener() {
        public void receive(VehicleMeasurement measurement) {
            speedReceived = (VehicleSpeed) measurement;
        }
    };

    SteeringWheelAngle.Listener steeringWheelListener =
            new SteeringWheelAngle.Listener() {
        public void receive(VehicleMeasurement measurement) {
            steeringAngleReceived = (SteeringWheelAngle) measurement;
        }
    };

    public BoundVehicleServiceTest() {
        super(VehicleService.class);
    }

    private void copyTraces() {
        try {
            traceUri = new URI("file:///sdcard/com.openxc/trace.json");
        } catch(URISyntaxException e) {
            Assert.fail("Couldn't construct resource URIs: " + e);
        }

        try {
            FileUtils.copyInputStreamToFile(
                    getContext().getResources().openRawResource(
                        R.raw.tracejson), new File(traceUri));
        } catch(IOException e) {}
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        copyTraces();

        speedReceived = null;
        steeringAngleReceived = null;

        Intent startIntent = new Intent();
        startIntent.setClass(getContext(), VehicleService.class);
        service = ((VehicleService.VehicleServiceBinder)
                bindService(startIntent)).getService();
        service.waitUntilBound();
        service.setDataSource(TraceVehicleDataSource.class.getName(),
                traceUri.toString());
    }

    private void checkReceivedMeasurement(VehicleMeasurement measurement) {
        assertNotNull(measurement);
    }

    @MediumTest
    public void testGetNoData() throws UnrecognizedMeasurementTypeException {
        try {
            service.get(EngineSpeed.class);
        } catch(NoValueException e) {
            return;
        }
        Assert.fail("Expected a NoValueException");
    }

    @MediumTest
    public void testAddListener() throws RemoteVehicleServiceException,
            UnrecognizedMeasurementTypeException {
        service.addListener(VehicleSpeed.class, speedListener);
        // let some measurements flow through the system
        pause(100);
        checkReceivedMeasurement(speedReceived);
    }

    @MediumTest
    public void testAddListenersTwoMeasurements()
            throws RemoteVehicleServiceException,
            UnrecognizedMeasurementTypeException {
        service.addListener(VehicleSpeed.class, speedListener);
        service.addListener(SteeringWheelAngle.class, steeringWheelListener);
        // let some measurements flow through the system
        pause(100);
        checkReceivedMeasurement(speedReceived);
        checkReceivedMeasurement(steeringAngleReceived);
    }

    @MediumTest
    public void testRemoveListener() throws RemoteVehicleServiceException,
            UnrecognizedMeasurementTypeException {
        service.addListener(VehicleSpeed.class, speedListener);
        // let some measurements flow through the system
        pause(100);
        service.removeListener(VehicleSpeed.class, speedListener);
        speedReceived = null;
        pause(100);
        assertNull(speedReceived);
    }

    @MediumTest
    public void testRemoveWithoutListening()
            throws RemoteVehicleServiceException {
        service.removeListener(VehicleSpeed.class, speedListener);
        assertNull(speedReceived);
    }

    @MediumTest
    public void testRemoveOneMeasurementListener()
            throws RemoteVehicleServiceException,
            UnrecognizedMeasurementTypeException {
        service.addListener(VehicleSpeed.class, speedListener);
        service.addListener(SteeringWheelAngle.class, steeringWheelListener);
        pause(100);
        service.removeListener(VehicleSpeed.class, speedListener);
        speedReceived = null;
        pause(100);
        assertNull(speedReceived);
    }

    private void pause(int millis) {
        try {
            Thread.sleep(millis);
        } catch(InterruptedException e) {}
    }
}


@@ -555,32 +555,79 @@
 rviceException;%0A
+import com.openxc.remote.RemoteVehicleService;%0A
 import com.openx
@@ -2256,16 +2256,246 @@
  null;%0A%0A
+        // if the service is already running (and thus may have old data%0A        // cached), kill it.%0A        getContext().stopService(new Intent(getContext(),%0A                    RemoteVehicleService.class));%0A        pause(200);%0A
         

Kill RVS to flush the cache before running tests.