package com.rayo.server.test;
import java.net.URI;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.media.mscontrol.MediaObject;
import javax.media.mscontrol.join.Joinable.Direction;
import javax.media.mscontrol.join.JoinableStream;
import javax.media.mscontrol.join.JoinableStream.StreamType;
import javax.media.mscontrol.mediagroup.MediaGroup;
import org.apache.log4j.Logger;
import com.voxeo.moho.ApplicationContext;
import com.voxeo.moho.Call;
import com.voxeo.moho.CallableEndpoint;
import com.voxeo.moho.Endpoint;
import com.voxeo.moho.IncomingCall;
import com.voxeo.moho.Joint;
import com.voxeo.moho.MediaException;
import com.voxeo.moho.MediaService;
import com.voxeo.moho.Participant;
import com.voxeo.moho.SignalException;
import com.voxeo.moho.Unjoint;
import com.voxeo.moho.common.event.AutowiredEventListener;
import com.voxeo.moho.common.event.AutowiredEventTarget;
import com.voxeo.moho.common.event.EventDispatcher;
import com.voxeo.moho.common.event.MohoCallCompleteEvent;
import com.voxeo.moho.common.event.MohoEarlyMediaEvent;
import com.voxeo.moho.common.event.MohoJoinCompleteEvent;
import com.voxeo.moho.common.util.Utils;
import com.voxeo.moho.event.AcceptableEvent;
import com.voxeo.moho.event.CallCompleteEvent;
import com.voxeo.moho.event.CallEvent;
import com.voxeo.moho.event.EarlyMediaEvent;
import com.voxeo.moho.event.Event;
import com.voxeo.moho.event.EventSource;
import com.voxeo.moho.event.JoinCompleteEvent.Cause;
import com.voxeo.moho.event.Observer;
import com.voxeo.moho.event.RequestEvent;
import com.voxeo.moho.event.ResponseEvent;
import com.voxeo.moho.media.Input;
import com.voxeo.moho.media.Output;
import com.voxeo.moho.media.Prompt;
import com.voxeo.moho.media.Recording;
import com.voxeo.moho.media.input.InputCommand;
import com.voxeo.moho.media.output.OutputCommand;
import com.voxeo.moho.media.record.RecordCommand;
import com.voxeo.moho.utils.EventListener;
public class MockCall implements IncomingCall {
private static final Logger log = Logger.getLogger(MockCall.class);
private URI to;
private URI from;
private String id;
private State state = State.ACCEPTED;
private Map<String, List<String>> headers = new HashMap<String, List<String>>();
private ApplicationContext applicationContext;
protected EventDispatcher _dispatcher = new EventDispatcher(Executors.newFixedThreadPool(10));
protected Map<String, String> _states = new ConcurrentHashMap<String, String>();
protected ConcurrentHashMap<Observer, AutowiredEventListener> _observers = new ConcurrentHashMap<Observer, AutowiredEventListener>();
// attribute store
private Map<String, Object> _attributes = new ConcurrentHashMap<String, Object>();
private MediaService<Call> mediaService;
public MockCall() {
this.id = UUID.randomUUID().toString();
}
@Override
public JoinableStream[] getJoinableStreams() {
throw new UnsupportedOperationException();
}
@Override
public Endpoint getAddress() {
return new SimpleEndpoint(to);
}
@Override
public Joint join(Participant other, JoinType type, Direction direction) {
return new SimpleJoint(new MohoJoinCompleteEvent(this, this, Cause.JOINED, true));
}
@Override
public Unjoint unjoin(Participant other) {
return null;
}
@Override
public Participant[] getParticipants() {
return new Participant[] {};
}
@Override
public boolean isHold() {
return false;
}
@Override
public boolean isMute() {
return false;
}
@Override
public Participant[] getParticipants(Direction direction) {
return new Participant[] {};
}
@Override
public void disconnect() {
dispatch(new MohoCallCompleteEvent(this, com.voxeo.moho.event.CallCompleteEvent.Cause.NEAR_END_DISCONNECT));
}
@Override
public MediaObject getMediaObject() {
throw new UnsupportedOperationException();
}
@Override
public String getApplicationState() {
return _states.get(AutowiredEventTarget.DEFAULT_FSM);
}
@Override
public String getApplicationState(String FSM) {
return _states.get(FSM);
}
@Override
public void setApplicationState(String state) {
_states.put(AutowiredEventTarget.DEFAULT_FSM, state);
}
@Override
public void setApplicationState(String FSM, String state) {
_states.put(FSM, state);
}
@Override
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void addListener(final EventListener<?> listener) {
if (listener != null) {
_dispatcher.addListener(Event.class, listener);
}
}
public void addListeners(final EventListener<?>... listeners) {
if (listeners != null) {
for (final EventListener<?> listener : listeners) {
this.addListener(listener);
}
}
}
public <E extends Event<?>, T extends EventListener<E>> void addListener(final Class<E> type, final T listener) {
if (listener != null) {
_dispatcher.addListener(type, listener);
}
}
@Override
public void removeObserver(final Observer listener) {
final AutowiredEventListener autowiredEventListener = _observers.remove(listener);
if (autowiredEventListener != null) {
_dispatcher.removeListener(autowiredEventListener);
}
}
@Override
public <S extends EventSource, T extends Event<S>> Future<T> dispatch(final T event, final Runnable afterExec) {
return _dispatcher.fire(event, true, afterExec);
}
public <S extends EventSource, T extends Event<S>> Future<T> internalDispatch(final T event) {
return _dispatcher.fire(event, true, null);
}
@Override
public <S extends EventSource, T extends Event<S>> Future<T> dispatch(final T event) {
Future<T> retval = null;
if (!(event instanceof CallEvent) && !(event instanceof RequestEvent) && !(event instanceof ResponseEvent)) {
retval = this.internalDispatch(event);
}
else {
final Runnable acceptor = new Runnable() {
@Override
public void run() {
if (event instanceof EarlyMediaEvent) {
if (!((MohoEarlyMediaEvent) event).isProcessed()) {
try {
((EarlyMediaEvent) event).reject(null);
}
catch (final SignalException e) {
log.warn(e);
}
}
}
else if (event instanceof AcceptableEvent) {
if (!((AcceptableEvent) event).isAccepted() && !((AcceptableEvent) event).isRejected()) {
try {
((AcceptableEvent) event).accept();
}
catch (final SignalException e) {
log.warn(e);
}
}
}
}
};
retval = this.dispatch(event, acceptor);
}
return retval;
}
@Override
public String getId() {
return id;
}
@Override
public Object getAttribute(final String name) {
if (name == null) {
return null;
}
return _attributes.get(name);
}
@Override
public Map<String, Object> getAttributeMap() {
return new HashMap<String, Object>(_attributes);
}
@Override
public void setAttribute(final String name, final Object value) {
if (value == null) {
_attributes.remove(name);
} else {
_attributes.put(name, value);
}
}
@Override
public void reject(Reason reason, Map<String, String> headers) throws SignalException {
switch (reason) {
case BUSY:
internalDispatch(new MohoCallCompleteEvent(this, CallCompleteEvent.Cause.FORBIDDEN));
break;
case DECLINE:
internalDispatch(new MohoCallCompleteEvent(this, CallCompleteEvent.Cause.DECLINE));
break;
case ERROR:
internalDispatch(new MohoCallCompleteEvent(this, CallCompleteEvent.Cause.ERROR));
break;
case FORBIDEN:
internalDispatch(new MohoCallCompleteEvent(this, CallCompleteEvent.Cause.FORBIDDEN));
break;
}
}
@Override
public void redirect(Endpoint other, Map<String, String> headers) throws SignalException, IllegalArgumentException {
}
@Override
public void accept(Map<String, String> headers) throws SignalException, IllegalStateException {}
@Override
public Joint join() {
return new SimpleJoint(new MohoJoinCompleteEvent(this, this, Cause.JOINED, true));
}
@Override
public Joint join(Direction direction) {
return new SimpleJoint(new MohoJoinCompleteEvent(this, this, Cause.JOINED, true));
}
@Override
public Joint join(CallableEndpoint other, JoinType type, Direction direction) {
return new SimpleJoint(new MohoJoinCompleteEvent(this, this, Cause.JOINED, true));
}
@Override
public Joint join(CallableEndpoint other, JoinType type, Direction direction, Map<String, String> headers) {
return new SimpleJoint(new MohoJoinCompleteEvent(this, this, Cause.JOINED, true));
}
protected MediaService<Call> getMediaService(boolean reinvite) {
return mediaService;
}
public MediaService<Call> getMediaService() {
return mediaService;
}
@Override
public State getCallState() {
return state;
}
@Override
public Call[] getPeers() {
return new Call[] {};
}
@Override
public void mute() {}
@Override
public void unmute() {}
@Override
public void hold() {}
@Override
public void unhold() {}
@Override
public void hangup(Map<String, String> headers) {
dispatch(new MohoCallCompleteEvent(this, com.voxeo.moho.event.CallCompleteEvent.Cause.NEAR_END_DISCONNECT));
}
@Override
public String getHeader(String name) {
return headers.get(name) != null ? headers.get(name).get(0) : null;
}
@Override
public ListIterator<String> getHeaders(String name) {
return headers.get(name) != null ? headers.get(name).listIterator() : null;
}
@Override
public Iterator<String> getHeaderNames() {
return headers.keySet().iterator();
}
@Override
public Endpoint getInvitor() {
return new SimpleEndpoint(from);
}
@Override
public CallableEndpoint getInvitee() {
return new SimpleEndpoint(to);
}
@Override
public void acceptWithEarlyMedia(Map<String, String> headers) throws SignalException, MediaException, IllegalStateException {
}
@Override
public void answer(Map<String, String> headers) throws SignalException {
}
public void setTo(URI to) {
this.to = to;
}
public URI getTo() {
return to;
}
public void setMediaService(MediaService mediaService) {
this.mediaService = mediaService;
}
@Override
public JoinableStream getJoinableStream(StreamType value) {
throw new UnsupportedOperationException();
}
public void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void setHeaders(Map<String, List<String>> headers) {
if (headers != null) {
this.headers = headers;
}
}
public Map<String, List<String>> getHeaders() {
return headers;
}
public void setFrom(URI from) {
this.from = from;
}
public URI getFrom() {
return from;
}
@Override
public void hangup() {}
@Override
public void addObserver(Observer... observers) {
for(Observer observer : observers) {
if (observer != null) {
if (observer instanceof EventListener) {
@SuppressWarnings("rawtypes")
EventListener l = (EventListener) observer;
@SuppressWarnings("rawtypes")
Class claz = Utils.getGenericType(observer);
if (claz == null) {
claz = Event.class;
}
_dispatcher.addListener(claz, l);
} else {
final AutowiredEventListener autowire = new AutowiredEventListener(observer);
if (_observers.putIfAbsent(observer, autowire) == null) {
_dispatcher.addListener(Event.class, autowire);
}
}
}
}
}
@Override
public Output<Call> output(String text) throws MediaException {
return mediaService.output(text);
}
@Override
public Output<Call> output(URI media) throws MediaException {
return mediaService.output(media);
}
@Override
public Output<Call> output(OutputCommand output) throws MediaException {
return mediaService.output(output);
}
@Override
public Prompt<Call> prompt(String text, String grammar, int repeat) throws MediaException {
return mediaService.prompt(text, grammar, repeat);
}
@Override
public Prompt<Call> prompt(URI media, String grammar, int repeat) throws MediaException {
return mediaService.prompt(media, grammar, repeat);
}
@Override
public Prompt<Call> prompt(OutputCommand output, InputCommand input, int repeat) throws MediaException {
return mediaService.prompt(output, input, repeat);
}
@Override
public Input<Call> input(String grammar) throws MediaException {
return mediaService.input(grammar);
}
@Override
public Input<Call> input(InputCommand input) throws MediaException {
return mediaService.input(input);
}
@Override
public Recording<Call> record(URI recording) throws MediaException {
return mediaService.record(recording);
}
@Override
public Recording<Call> record(RecordCommand command) throws MediaException {
return mediaService.record(command);
}
@Override
public MediaGroup getMediaGroup() {
return null;
}
@Override
public Call getSource() {
return null;
}
@Override
public boolean isAccepted() {
return false;
}
@Override
public boolean isRejected() {
return false;
}
@Override
public void accept() throws SignalException {}
@Override
public void reject(Reason reason) throws SignalException {}
@Override
public boolean isRedirected() {
return false;
}
@Override
public void redirect(Endpoint other) throws SignalException {}
@Override
public boolean isAcceptedWithEarlyMedia() {
return false;
}
@Override
public void acceptWithEarlyMedia() throws SignalException, MediaException {}
@Override
public void acceptWithEarlyMedia(Observer... observer) throws SignalException, MediaException {}
@Override
public void accept(Observer... observer) throws SignalException {}
@Override
public void answer() throws SignalException, MediaException {}
@Override
public void answer(Observer... observer) throws SignalException, MediaException {}
@Override
public void proxyTo(boolean recordRoute, boolean parallel, Endpoint... destinations) throws SignalException {}
@Override
public boolean isProxied() {
return false;
}
@Override
public void proxyTo(boolean recordRoute, boolean parallel,
Map<String, String> headers, Endpoint... destinations) {
}
@Override
public String getRemoteAddress() {
return null;
}
@Override
public void setAsync(boolean async) {
}
@Override
public boolean isAsync() {
return false;
}
@Override
public Joint join(Participant other, JoinType type, boolean force,
Direction direction) {
return null;
}
@Override
public JoinType getJoinType(Participant participant) {
return null;
}
public Joint join(Participant other, JoinType type, boolean force, Direction direction, boolean dtmfPassThough) {
return null;
}
public MediaGroup getMediaGroup(boolean create) {
return null;
}
@Override
public Joint join(JoinType type, boolean force, Direction direction, Map<String, String> headers,
boolean dtmfPassThrough, CallableEndpoint... others) {
return null;
}
@Override
public Joint join(JoinType type, boolean force, Direction direction, boolean dtmfPassThrough, Call... others) {
return null;
}
@Override
public Direction getDirection(Participant participant) {
return null;
}
}