// Path: be.iminds.iot.firefly.dashboard.application/src/be/iminds/iot/firefly/dashboard/Actions.java
// public interface Actions {
// 
// 	public String getType();
// 	
// 	public void action(UUID id, String ... params);
// 	
// }
// 
// Path: be.iminds.iot.things.api/src/be/iminds/iot/things/api/Thing.java
// public interface Thing {
// 
//     public final static String ID = "thing.id";
//     public final static String DEVICE = "thing.device";
//     public final static String SERVICE = "thing.service";
//     public final static String GATEWAY = "thing.gateway";
//     public final static String TYPE = "thing.type";
//     
// }
// 
// Path: be.iminds.iot.things.api/src/be/iminds/iot/things/api/camera/Camera.java
// public interface Camera extends Thing {
// 
//     public final static String STATE = "state";
// 
//     public static enum State {
//     	OFF, RECORDING;
//     }
// 
//     public static enum Format {
//     	YUV, RGB, GRAYSCALE, MJPEG;
//     }
// 
//     /**
//      * Get the state of the camera
//      *
//      * @return state of the camera
//      */
//     public State getState();
//     
//     /**
//      * Return boolean if the camera is on
//      */
//     public boolean isOn();
// 
//     /**
//      * Get the width of the frames the camera is fetching
//      *
//      * @return frame width or -1 if not initialized
//      */
//     public int getWidth();
// 
//     /**
//      * Get the height of the frames the camera is fetching
//      *
//      * @return frame height or -1 if not initialized
//      */
//     public int getHeight();
//     
//     /**
//      * Get the current capturing format
//      * 
//      * @return frame format
//      */
//     public Format getFormat();
//     
//     /**
//      * Return the framerate (frames per second) that is aimed for when having a CameraListener
//      * 
//      * @return framerate
//      */
//     public float getFramerate();
//     
//     /**
//      * Set framerate
//      * 
//      * @param f framerate to set
//      */
//     public void setFramerate(float f);
//     
//     /**
//      * Return the latest camera frame when the camera is turned on
//      * @return byte array in the camera's current format
//      */
//     public byte[] getFrame();
//     
//     /**
//      * Turn the camera on
//      */
//     public void start();
// 
//     /**
//      * Turn the camera on with preferred width,height capture ratio
//      *
//      * @param width
//      * @param height
//      */
//     public void start(int width, int height, Format format);
// 
//     /**
//      * Stop capturing
//      */
//     public void stop();
//     
//     /**
//      * Toggle
//      */
//     public void toggle();
// }
// 
// Path: be.iminds.iot.things.api/src/be/iminds/iot/things/api/camera/Camera.java
// public static enum Format {
// 	YUV, RGB, GRAYSCALE, MJPEG;
// }
// 
// Path: be.iminds.iot.things.api/src/be/iminds/iot/things/api/camera/CameraListener.java
// public interface CameraListener {
// 
//     public final static String CAMERA_ID = "be.iminds.iot.thing.camera.id";
//     public final static String CAMERA_FORMAT = "be.iminds.iot.thing.camera.format";
// 
//     public void nextFrame(UUID id, Format format, byte[] data);
// 
// }


import java.io.IOException;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import javax.servlet.AsyncContext;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
import osgi.enroute.http.capabilities.RequireHttpImplementation;
import aQute.lib.collections.MultiMap;
import be.iminds.iot.firefly.dashboard.Actions;
import be.iminds.iot.things.api.Thing;
import be.iminds.iot.things.api.camera.Camera;
import be.iminds.iot.things.api.camera.Camera.Format;
import be.iminds.iot.things.api.camera.CameraListener;
		response.setContentType("multipart/x-mixed-replace;boundary=next");

		// check if there is already a stream for this client
		String client = request.getRemoteHost()+":"+request.getRemotePort();
		CameraStream stream = streamsByClient.get(client);
		if(stream==null){
			stream = new CameraStream(id, client);
			synchronized(streamsByCameraId){
				streamsByCameraId.add(id, stream);
				streamsByClient.put(client, stream);
			}
		}
		
		stream.updateRequest(request);

		// if not yet a stream for this id, register CameraListener service
		if(!listenerRegistrations.containsKey(id)){
			Dictionary<String, Object> properties = new Hashtable<>();
			properties.put("aiolos.unique", true);
			properties.put("be.iminds.iot.thing.camera.id", id.toString());
			ServiceRegistration r = context.registerService(CameraListener.class, this, properties);
			listenerRegistrations.put(id, r);
		}
		

	}
	
	@Reference(cardinality=ReferenceCardinality.MULTIPLE,
			policy=ReferencePolicy.DYNAMIC)
	public void addCamera(Camera c, Map<String, Object> properties){
// Path: be.iminds.iot.firefly.dashboard.application/src/be/iminds/iot/firefly/dashboard/Actions.java
// public interface Actions {
// 
// 	public String getType();
// 	
// 	public void action(UUID id, String ... params);
// 	
// }
// 
// Path: be.iminds.iot.things.api/src/be/iminds/iot/things/api/Thing.java
// public interface Thing {
// 
//     public final static String ID = "thing.id";
//     public final static String DEVICE = "thing.device";
//     public final static String SERVICE = "thing.service";
//     public final static String GATEWAY = "thing.gateway";
//     public final static String TYPE = "thing.type";
//     
// }
// 
// Path: be.iminds.iot.things.api/src/be/iminds/iot/things/api/camera/Camera.java
// public interface Camera extends Thing {
// 
//     public final static String STATE = "state";
// 
//     public static enum State {
//     	OFF, RECORDING;
//     }
// 
//     public static enum Format {
//     	YUV, RGB, GRAYSCALE, MJPEG;
//     }
// 
//     /**
//      * Get the state of the camera
//      *
//      * @return state of the camera
//      */
//     public State getState();
//     
//     /**
//      * Return boolean if the camera is on
//      */
//     public boolean isOn();
// 
//     /**
//      * Get the width of the frames the camera is fetching
//      *
//      * @return frame width or -1 if not initialized
//      */
//     public int getWidth();
// 
//     /**
//      * Get the height of the frames the camera is fetching
//      *
//      * @return frame height or -1 if not initialized
//      */
//     public int getHeight();
//     
//     /**
//      * Get the current capturing format
//      * 
//      * @return frame format
//      */
//     public Format getFormat();
//     
//     /**
//      * Return the framerate (frames per second) that is aimed for when having a CameraListener
//      * 
//      * @return framerate
//      */
//     public float getFramerate();
//     
//     /**
//      * Set framerate
//      * 
//      * @param f framerate to set
//      */
//     public void setFramerate(float f);
//     
//     /**
//      * Return the latest camera frame when the camera is turned on
//      * @return byte array in the camera's current format
//      */
//     public byte[] getFrame();
//     
//     /**
//      * Turn the camera on
//      */
//     public void start();
// 
//     /**
//      * Turn the camera on with preferred width,height capture ratio
//      *
//      * @param width
//      * @param height
//      */
//     public void start(int width, int height, Format format);
// 
//     /**
//      * Stop capturing
//      */
//     public void stop();
//     
//     /**
//      * Toggle
//      */
//     public void toggle();
// }
// 
// Path: be.iminds.iot.things.api/src/be/iminds/iot/things/api/camera/Camera.java
// public static enum Format {
// 	YUV, RGB, GRAYSCALE, MJPEG;
// }
// 
// Path: be.iminds.iot.things.api/src/be/iminds/iot/things/api/camera/CameraListener.java
// public interface CameraListener {
// 
//     public final static String CAMERA_ID = "be.iminds.iot.thing.camera.id";
//     public final static String CAMERA_FORMAT = "be.iminds.iot.thing.camera.format";
// 
//     public void nextFrame(UUID id, Format format, byte[] data);
// 
// }


// Path: be.iminds.iot.firefly.dashboard.application/src/be/iminds/iot/firefly/dashboard/actions/CameraActions.java
import java.io.IOException;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import javax.servlet.AsyncContext;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
import osgi.enroute.http.capabilities.RequireHttpImplementation;
import aQute.lib.collections.MultiMap;
import be.iminds.iot.firefly.dashboard.Actions;
import be.iminds.iot.things.api.Thing;
import be.iminds.iot.things.api.camera.Camera;
import be.iminds.iot.things.api.camera.Camera.Format;
import be.iminds.iot.things.api.camera.CameraListener;

		response.setContentType("multipart/x-mixed-replace;boundary=next");

		// check if there is already a stream for this client
		String client = request.getRemoteHost()+":"+request.getRemotePort();
		CameraStream stream = streamsByClient.get(client);
		if(stream==null){
			stream = new CameraStream(id, client);
			synchronized(streamsByCameraId){
				streamsByCameraId.add(id, stream);
				streamsByClient.put(client, stream);
			}
		}
		
		stream.updateRequest(request);

		// if not yet a stream for this id, register CameraListener service
		if(!listenerRegistrations.containsKey(id)){
			Dictionary<String, Object> properties = new Hashtable<>();
			properties.put("aiolos.unique", true);
			properties.put("be.iminds.iot.thing.camera.id", id.toString());
			ServiceRegistration r = context.registerService(CameraListener.class, this, properties);
			listenerRegistrations.put(id, r);
		}
		

	}
	
	@Reference(cardinality=ReferenceCardinality.MULTIPLE,
			policy=ReferencePolicy.DYNAMIC)
	public void addCamera(Camera c, Map<String, Object> properties){
		UUID id = UUID.fromString((String)properties.get(Thing.ID));