public class RESTConversationManager extends Resource {

	private double[] distances = { 0.02, 0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 20,
			50, 100, 250, 500 };

	public RESTConversationManager() {
		super("RESTConversations");
	}

	public Status addNewConversation(Conversation conversation)
			throws ClientProtocolException, IOException, JSONException,
			ParseException {
		// group insertion
		HashMap<String, Object> hM = new HashMap<String, Object>();
		hM.put("thread", conversation.getThread().getThreadName());
		hM.put("conversation", conversation.getConversationName());

		if (conversation.getCallee() != null) {
			hM.put("calleeNumber", conversation.getCallee().size());
			for (int i = 0; i < conversation.getCallee().size(); i++) {
				hM.put("callee" + (i + 1) + "username", conversation
						.getCallee().get(i));
			}
		}

		Response r = this.post("insert", hM);
		// 201 = HTTP status code for conversation inserted
		if (r.getStatus() == 201) {
			conversation.setId(Integer.parseInt(r.getResult().getString("id")));
			conversation.setDate(r.getResult().getString("date"));
			return new Status(true, "Conversation added successfully");
		} else {
			return new Status(false, "" + r.getResult());
		}
	}

	public Status createSpatialConversation(Conversation conversation,
			double distance) throws ClientProtocolException, IOException,
			JSONException, ParseException {
		HashMap<String, Object> hM = new HashMap<String, Object>();
		hM.put("thread", conversation.getThread().getThreadName());
		hM.put("conversation", conversation.getConversationName());
		hM.put("distance", distance);

		Response r = this.post("createSpatialConversation", hM);
		// 201 = HTTP status code for conversation inserted
		if (r.getStatus() == 201) {
			conversation.setId(Integer.parseInt(r.getResult().getString("id")));
			conversation.setDate(r.getResult().getString("date"));
			JSONObject callee = r.getResult().getJSONObject("callees");

			List<String> callees = new ArrayList<String>();
			for (int i = 0; i < callee.length(); i++) {
				callees.add(callee.getString("" + i));
			}
			conversation.addAllCallee(callees);

			return new Status(true, "Conversation added successfully");
		} else {
			return new Status(false, "" + r.getResult());
		}
	}

	public List<ConversationThread> retrieveAll() throws JSONException,
			ClientProtocolException, IOException, ParseException {
		Response r = this.get("retrieveAll");
		List<ConversationThread> myThreads = new ArrayList<ConversationThread>();
		if (r.getStatus() == 200) {
			for (Iterator iterator = r.getResult().keys(); iterator.hasNext();) {
				String key = "" + iterator.next();
				JSONObject keyObj = r.getResult().getJSONObject(key);
				myThreads.add(new ConversationThread(keyObj, key));
			}
			return myThreads;
		} else if (r.getStatus() == 201) {
			return myThreads;
		}
		return null;
	}

	public Status updateTime(Conversation conversation)
			throws ClientProtocolException, IOException, JSONException,
			ParseException {
		Map<String, Object> h = new HashMap<String, Object>();
		h.put("id", conversation.getId());

		Response r = this.put("updateTime", h);
		if (r.getStatus() == 201) {
			conversation.setDate(r.getResult().getString("date"));
			return new Status(true, "Time updated successfully");
		} else {
			return new Status(false, r.getResult().getString("result"));
		}
	}

	public float[][] distanceFromContact() throws JSONException,
			ClientProtocolException, IOException {
		Response r = this.get("distanceFromContact");
		Log.e("GPS", "Message: " + r.getResult());
		Log.e("GPS", "Status: " + r.getStatus());
		if (r.getStatus() != 200) {
			return null;
		}
		float[][] values = new float[distances.length][2];
		// scan the data for the name of the groups
		int i = 0;

		for (int h = 0; h < distances.length; h++) {
			values[h][0] = (float) distances[h];
			values[h][1] = 0;
		}
		// empty
		if (r.getStatus() == 201)
			return values;
		if (r.getStatus() != 200)
			return null;
		for (Iterator iterator = r.getResult().keys(); iterator.hasNext();) {
			String distance = "" + iterator.next();
			// retrieve the JSON object and instantiates a new Group with it
			String number = r.getResult().getString(distance);
			i = getDistancesIndex(Double.parseDouble(distance));
			if (i == -1)
				Log.e("INDEX", "-1   Value searched:  "
						+ Double.parseDouble(distance));
			if (i < distances.length) {
				Log.e("MARCO", "" + i + "/ MAX = " + distances.length);
				values[i][0] = (float) distances[i];
				values[i][1] = (float) Integer.parseInt(number);
			}

		}
		for (int j = 1; j < distances.length; j++) {
			values[j][1] = values[j][1] + values[j - 1][1];
		}
		return values;
	}

	public double getDistancesValue(int index) {
		if (index >= distances.length)
			return -1;
		return distances[index];
	}

	public int getDistancesIndex(double value) {
		for (int i = 0; i < distances.length; i++)
			if (distances[i] == value)
				return i;
		return -1;
	}

	public int returnIndex(int value) {
		if (value == 0) {
			return 0;
		} else if (value == 100) {
			return distances.length - 1;
		}

		float percentage = 100 / (distances.length - 1);
		int index = (int) Math.ceil(value / percentage) - 1;
		if (index >= distances.length) {
			return distances.length - 1;
		}

		return index;
	}

	public Status updatePosition(Location loc) throws ClientProtocolException,
			IOException, JSONException {
		HashMap<String, Object> hM = new HashMap<String, Object>();
		double latitude = loc.getLatitude();
		double longitude = loc.getLongitude();
		hM.put("latitude", latitude);
		hM.put("longitude", longitude);

		Response r = this.put("updatePosition", hM);
		if (r.getStatus() == 201) {
			return new Status(true, "Position updated successfully");
		} else {
			return new Status(false, "" + r.getResult());
		}
	}

} public class NebulaSIPConstants {
	public static final String NOTIFY_PRESENCE = "NOTIFY_PRESENCE_EVENT";
	public static final String NOTIFY_INVITE = "NOTIFY_INVITE_EVENT";
	public static final String NOTIFY_BYE = "NOTIFY_BYE_EVENT";
	public static final String SUBSCRIBE_NOTIFY_CALLID = "nebula_subscribe_notify";

	public static final String PIDF_NS_VALUE = "urn:ietf:params:xml:ns:pidf";
	public static final String PRESENCE_ELEMENT = "presence";
	public static final String TUPLE_ELEMENT = "tuple";
	public static final String NOTE_ELEMENT = "note";
	public static final String ENTITY_ATTRIBUTE = "entity";

	public static final String PRESENCE_ONLINE = "Online";
	public static final String PRESENCE_BUSY = "Busy";
	public static final String PRESENCE_AWAY = "Away";
	public static final String PRESENCE_OFFLINE = "Offline";

	public static final String THREAD_PARAMETER = "thread";
	public static final String CONVERSATION_PARAMETER = "conv";
	public static final String OLD_CONVERSATION_PARAMETER = "newvalue";

	public static final int REGISTER_FAILURE = 0;
	public static final int REGISTER_SUCCESSFUL = 1;
	public static final int REGISTER_SIPEXCEPTION = 12;
	public static final int SUBSCRIBE_FAILURE = 2;
	public static final int SUBSCRIBE_SUCCESSFUL = 3;
	public static final int PUBLISH_FAILURE = 4;
	public static final int PUBLISH_SUCCESSFUL = 5;
	public static final int BYE_FAILURE = 6;
	public static final int BYE_SUCCESS = 7;
	public static final int CALL_FAILURE = 8;
	public static final int CALL_SUCCESS = 9;
	public static final int REFER_FAILURE = 10;
	public static final int REFER_SUCCESS = 11;
} public class SIPManager {

	public static int doLogin(String userName, String password) {
		try {
			SIPHandler sip = NebulaApplication.getInstance().getMySIPHandler();
			MyIdentity myIdentity = NebulaApplication.getInstance()
					.getMyIdentity();
			myIdentity.setMyUserName(userName);
			myIdentity.setMyPassword(password);

			Status response = sip.sendRegister();
			if (response.isSuccess() == true) {
				return REGISTER_SUCCESSFUL;
			} else {
				myIdentity.setMyUserName("");
				myIdentity.setMyPassword("");
				throw new Exception(response.getMessage());
			}
		} catch (Exception e) {
			Log.e("nebula", "SIPManager: " + e.getMessage());
			if (e.getMessage().equals("12")) {// bite me :/
				return REGISTER_SIPEXCEPTION;
			}
			return REGISTER_FAILURE;
		}
	}

	public static int doSubscribe(String toUserName, String toDomain) {
		try {
			SIPHandler sip = NebulaApplication.getInstance().getMySIPHandler();
			Status response = sip.sendSubscribe(toUserName, toDomain);
			if (response.isSuccess() == true) {
				return SUBSCRIBE_SUCCESSFUL;
			} else {
				throw new Exception("Subscribe didn't succeed");
			}
		} catch (Exception e) {
			Log.e("nebula", "sipManager.doSubscribe:" + e.getMessage());
			return SUBSCRIBE_FAILURE;
		}
	}

	public static int doPublish(String status) {
		try {
			SIPHandler sip = NebulaApplication.getInstance().getMySIPHandler();
			Status response = sip.sendPublish(status, 3600);
			if (response.isSuccess() == true) {
				return PUBLISH_SUCCESSFUL;
			} else {
				throw new Exception("Publish didn't succeed");
			}
		} catch (Exception e) {
			Log.e("nebula", "sipManager.doPublish:" + e.getMessage());
			return PUBLISH_FAILURE;
		}
	}

	// contact- prajwol, michel
	public static int doCall(ConversationThread thread,
			Conversation conversation) {
		try {
			Log.e("nebula", "SIPManager.doCall:" + conversation.getRcl());
			SIPHandler sip = NebulaApplication.getInstance().getMySIPHandler();
			Status response = sip.sendInvite(thread, conversation);
			if (response.isSuccess() == true) {
				NebulaApplication.getInstance().establishRTP(
						SIPUtils.retrieveIP(response.getMessage()),
						SIPUtils.retrievePort(response.getMessage()));
				return CALL_SUCCESS;
			} else {
				throw new Exception("Call didn't succeed");
			}
		} catch (Exception e) {
			Log.e("nebula", "SIPManager.doCall:" + e.getMessage());
			return CALL_FAILURE;
		}
	}

	public static int doEndCalls() {
		try {
			SIPHandler sip = NebulaApplication.getInstance().getMySIPHandler();
			Status response = sip.sendByeToAll();
			if (!response.isSuccess()) {
				Log.e("nebula", "SIPManager.doLogout: bye error "
						+ response.getMessage());
			}
			return BYE_SUCCESS;
		} catch (Exception e) {
			Log.e("nebula", "sipManager.doLogout: " + e.getMessage());
			return BYE_FAILURE;
		}

	}

	public static int doLogout() {
		try {
			// doPublish("Offline");
			SIPHandler sip = NebulaApplication.getInstance().getMySIPHandler();
			Status response = sip.sendByeToAll();
			if (!response.isSuccess()) {
				Log.e("nebula", "SIPManager.doLogout: bye error "
						+ response.getMessage());
			}
			sip.sendRegister(0);
			return BYE_SUCCESS;
		} catch (Exception e) {
			Log.e("nebula", "sipManager.doLogout: " + e.getMessage());
			return BYE_FAILURE;
		}
	}

	public static int doRefer(String referSIPUser, String referSIPDomain,
			String threadId, Conversation oldConversation,
			Conversation newConversation) {
		try {
			SIPHandler sip = NebulaApplication.getInstance().getMySIPHandler();
			Status resp = sip.sendRefer(referSIPUser, referSIPDomain, threadId,
					oldConversation, newConversation);
			if (resp.isSuccess() == true) {
				return REFER_SUCCESS;
			} else {
				throw new Exception("REFER did not succeed. "
						+ resp.getMessage());
			}
		} catch (Exception e) {
			Log.e("nebula", "SIPMmanager.doRefer: " + e.getMessage());
			return REFER_FAILURE;
		}
	}
} public class NebulaApplication extends Application implements
		NebulaEventHandler {

	private static NebulaApplication singleton;
	private MyIdentity myIdentity = null;

	private SIPHandler mySIPHandler = null;

	private boolean isRTPInitialized = false;
	private RTPSession myRTPClient = null;
	private RTPSender myRTPSender = null;
	private RTPReceiver myRTPReceiver = null;

	private NebulaLocalDB myLocalDB = null;

	private LocationManager mlocManager;
	private NebulaLocationListener mlocListener;
	private final long MILLIS_FREQUENCY_UPDATE = 5000;
	private final long METERS_DISTANCE_UPDATE = 10;

	public static NebulaApplication getInstance() {
		return singleton;
	}

	@Override
	public final void onCreate() {
		super.onCreate();
		singleton = this;

		myIdentity = new MyIdentity();
		myLocalDB = new NebulaLocalDB(this);

		try {
			myIdentity.loadConfiguration();
			mySIPHandler = new SIPHandler(this);

			bindService(new Intent(NebulaApplication.this, RTPSender.class),
					senderConnection, Context.BIND_AUTO_CREATE);
			Log.v("nebula", "nebulaAPP: " + "sender service started");
			startService(new Intent(NebulaApplication.this, RTPSender.class));

			// Instantiate RTP Client
			myRTPClient = new RTPSession(new DatagramSocket(myIdentity
					.getMyRTPPort()), new DatagramSocket(myIdentity
					.getMyRTPPort() + 1));
			myRTPClient.payloadType(8);

			myRTPReceiver = new RTPReceiver(myRTPClient);

			mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
			mlocListener = new NebulaLocationListener(this
					.getApplicationContext());
			mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
					MILLIS_FREQUENCY_UPDATE, METERS_DISTANCE_UPDATE,
					mlocListener);
		} catch (Exception e) {
			// TODO Handle gracefully
			Log.e("nebula", "nebulaApp: " + e.getMessage());
			System.exit(-1);
		}
	}

	public void processEvent(Object... params) {
		String eventName = params[0].toString();
		if (eventName.equals(NebulaSIPConstants.NOTIFY_PRESENCE)) {
			sendBroadcast(new Intent(params[0].toString()).putExtra("params",
					params));
		} else if (eventName.equals(NebulaSIPConstants.NOTIFY_INVITE)) {
			String threadId = (String) params[3];
			String convId = (String) params[4];
			String requestRCL = (String) params[5];

			ConversationThread thread;
			boolean shouldEstablishRTP = false;

			if (myIdentity.existsThread(threadId)) {
				thread = myIdentity.getThreadById(threadId);

				if (!thread.existsConversation(convId)) {
					thread.addConversation(convId, requestRCL);
					shouldEstablishRTP = false;
				} else {
					shouldEstablishRTP = true;
				}
			} else {
				thread = myIdentity.createThread(threadId);
				thread.addConversation(convId, requestRCL);
				shouldEstablishRTP = true;
			}

			if (shouldEstablishRTP == true) {
				establishRTP(params[1].toString(), Integer.valueOf(
						params[2].toString()).intValue());
			}

			sendBroadcast(new Intent(params[0].toString()));
		} else if (eventName.equals(NebulaSIPConstants.NOTIFY_BYE)) {
			String callId = (String) params[1];
			mySIPHandler.removeCallById(callId);
			terminateRTP(callId);
		}
	}

	public void reloadMyGroups() {
		RESTGroupManager rG = new RESTGroupManager();
		try {
			myIdentity.setMyGroups(rG.retrieveAllGroupsMembers());
			renewMyPresenceSubscriptions();
		} catch (Exception e) {
			// do nothing here since the old group is preserved
			Log.e("nebula", e.getMessage());
		}
	}

	public void reloadConversation() {
		RESTConversationManager rC = new RESTConversationManager();

		try {
			myIdentity.setMyThreads(rC.retrieveAll());
		} catch (Exception e) {
			// do nothing here since the old conversation is preserved
			Log.e("nebula", e.getMessage());
		}
	}

	private void renewMyPresenceSubscriptions() {
		for (Group individualGroup : myIdentity.getMyGroups()) {
			for (Profile individualProfile : individualGroup.getContacts()) {
				SIPManager.doSubscribe(individualProfile.getUsername(),
						myIdentity.getMySIPDomain());
			}
		}
	}

	public void establishRTP(String destAddressRTP, int destPortRTP) {
		if (!isRTPInitialized) {
			isRTPInitialized = true;
			myRTPSender.setRtpSender(myRTPClient);
			myRTPSender.startRecordingAndSending();

			myRTPClient.RTPSessionRegister(myRTPReceiver, null, null);
			myRTPReceiver.startPlaying();
		}

		// Log.v("nebula", "nebulaApp: desc ip/prt = " + destAddressRTP + "/"
		// + destPortRTP);
		Participant p = new Participant(destAddressRTP, destPortRTP,
				destPortRTP + 1);
		int participants = myRTPSender.numberOfReceivers();
		myRTPClient.addParticipant(p);

		while (participants == myRTPSender.numberOfReceivers()) {
		}

		new Thread() {
			public void run() {
				try {
					MediaPlayer mp = MediaPlayer.create(singleton, R.raw.beep);
					for (int i = 0; i < 2; i++) {
						if (mp != null) {
							mp.start();
							mp.reset();
							mp = MediaPlayer.create(singleton, R.raw.beep);
						}
					}
					mp.release();
				} catch (Exception e) {
					// do nothing here :P
				}
			}
		}.start();
	}
	
	public void muteMe(){
		myRTPReceiver.stopPlaying();
	}
	
	public void unMuteMe(){
		myRTPReceiver.startPlaying();
	}

	private void terminateRTP(String callId) {
		// TODO:: handle this
	}

	private ServiceConnection senderConnection = new ServiceConnection() {
		public void onServiceConnected(ComponentName name, IBinder binder) {
			myRTPSender = ((SenderBinder) binder).getService();
			Log.v("nebula", "Sender Connected!");
		}

		public void onServiceDisconnected(ComponentName name) {
			myRTPSender = null;
			Log.v("nebula", "Sender Disconnected!");
		}
	};

	public NebulaLocalDB getMyLocalDB() {
		return myLocalDB;
	}

	public MyIdentity getMyIdentity() {
		return myIdentity;
	}

	public void setMyIdentity(MyIdentity myIdentity) {
		this.myIdentity = myIdentity;
	}

	public SIPHandler getMySIPHandler() {
		return mySIPHandler;
	}
}
 public class Conversation {
	private int id;
	private Date date;
	private List<String> callee;
	private String conversationName;
	private String callId = "";

	private ConversationThread thread;
	private MyIdentity myIdentity = NebulaApplication.getInstance()
			.getMyIdentity();

	public Conversation(JSONObject convObj, String conversationName)
			throws JSONException, ParseException {
		this.callee = new ArrayList<String>();
		this.id = convObj.getInt("id");
		this.conversationName = conversationName;
		this.setDate(convObj.getString("date"));

		JSONObject calleeElement = convObj.getJSONObject("callees");
		for (int i = 0; i < calleeElement.length(); i++) {
			JSONObject user = calleeElement.getJSONObject("" + i);
			callee.add(user.getString("username"));
		}
	}

	public Conversation(String conversationName) {
		this.conversationName = conversationName;
		this.date = new Date();
		this.callee = new ArrayList<String>();
	}

	public Conversation(String conversationName, String rcl) {
		this(conversationName);

		List<String> rclList = new ArrayList<String>();
		String[] splitArray = rcl.split(",");
		for (String split : splitArray) {
			rclList.add(split);
		}

		addAllCallee(rclList);
	}

	public Conversation(String conversationName, List<String> callee) {
		this(conversationName);
		addAllCallee(callee);
	}

	public void addAllCallee(List<String> callee) {
		for (String member : callee) {
			this.addCalle(member);
		}
	}

	public boolean addCalle(String member) {
		if (callee.contains(member)) {
			return false;
		}
		return callee.add(member);
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getConversationName() {
		return conversationName;
	}

	public List<String> getCallee() {
		return callee;
	}

	public void setConversationName(String conversationName) {
		this.conversationName = conversationName;
	}

	public Date getDate() {
		return date;
	}

	public String getRcl() {
		return getRcl(true);
	}

	public String getRcl(boolean appendDomain) {
		StringBuilder res = new StringBuilder("");
		for (String member : callee) {
			if (!res.toString().equals("")) {
				res.append(",");
			}

			res.append(member);

			if (appendDomain) {
				res.append("@" + myIdentity.getMySIPDomain());
			}
		}
		return res.toString();
	}

	public void setDate(Date date) {
		this.date = date;
	}

	public String getDateToString() {
		Format format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		return (String) format.format(date);
	}

	public void setDate(String dat) throws ParseException,
			java.text.ParseException {
		Format formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
		this.date = (Date) formatter.parseObject(dat);
	}

	public ConversationThread getThread() {
		return thread;
	}

	public void setThread(ConversationThread thread) {
		this.thread = thread;
	}

	public String getCallId() {
		return callId;
	}

	public void setCallId(String callId) {
		this.callId = callId;
	}

	public String toString() {
		return this.thread.getThreadName() + conversationName;
	}
} public class ConversationThread {
	private String threadName;	
	private List<Conversation> myConversations = new ArrayList<Conversation>();

	

	public ConversationThread() {
		this.threadName = NebulaApplication.getInstance().getMyIdentity().createNewThreadId();
	}

	public ConversationThread(String threadName) {
		this.threadName = threadName;
	}

	public ConversationThread(JSONObject keyObj, String key) throws JSONException, ParseException {
		this.threadName = key;
		this.myConversations = new ArrayList<Conversation>();

		for (Iterator iterator = keyObj.keys(); iterator.hasNext();) {
			String actualConv = "" + iterator.next();
			JSONObject conversationObj = keyObj.getJSONObject(actualConv);			
			addConversation(new Conversation(conversationObj, actualConv));
		}
	}

	public Conversation addConversation(String newConversationId, String rcl) {
		Conversation newConversation = new Conversation(newConversationId, rcl);
		newConversation.setThread(this);
		myConversations.add(newConversation);
		return newConversation;
	}
	
	public Conversation addConversation(List<String> members) {
		return addConversation(new Conversation(NebulaApplication.getInstance().getMyIdentity().createNewConversationId(),
				members));
	}

	public Conversation addConversation(Conversation conv) {
		conv.setThread(this);
		myConversations.add(conv);
		return conv;
	}

	public Conversation getConversationByName(String name) throws Exception {
		for (Conversation curConversation : myConversations) {
			if (curConversation.getConversationName().equals(name)) {
				return curConversation;
			}
		}
		return null;
	}

	public boolean existsConversation(String conversationName) {
		for (Conversation conv : myConversations) {
			if (conv.getConversationName().equals(conversationName)) {
				return true;
			}
		}
		return false;
	}

	public String getThreadName() {
		return threadName;
	}

	public List<Conversation> getMyConversations() {
		return myConversations;
	}
} public class Group {
	private int id;
	private String groupName;
	private String groupStatus;
	private List<Profile> contacts = new ArrayList<Profile>();

	public Group() {
		this.groupName = "";
		this.id = 0;
		this.groupStatus = "";
		this.contacts = new ArrayList<Profile>();
	}
	
	public Group(int id, String groupName,  String groupStatus) {
		this();
		this.id = id;
		this.groupName = groupName;
		this.groupStatus = groupStatus;
		this.contacts = new ArrayList<Profile>();
	}
	
	public Group(JSONObject groupObj, String groupName) throws JSONException {
		this.groupName = groupName;
		this.id = groupObj.getInt("id");
		this.groupStatus = groupObj.getString("status");
		this.contacts = new ArrayList<Profile>();

		int profilesCount = groupObj.length() - 2; // :P there are two keys more
		for (int i = 0; i < profilesCount; i++) {
			JSONObject profileObj = groupObj.getJSONObject("" + i);
			this.contacts.add(new Profile(profileObj));
		}		
	}

	public String getGroupName() {
		return groupName;
	}

	public void setGroupName(String groupName) {
		this.groupName = groupName;
	}

	public String getGroupStatus() {
		return groupStatus;
	}

	public void setGroupStatus(String groupStatus) {
		this.groupStatus = groupStatus;
	}

	public List<Profile> getContacts() {
		return contacts;
	}

	public void setContacts(List<Profile> contacts) {
		this.contacts = contacts;
	}

	public void setId(int id) {
		this.id = id;
	}

	public int getId() {
		return id;
	}
	
	public String toString(){
		return this.groupName;
	}
}
 public class MyIdentity {
	private String myIP;
	private int mySIPPort;
	private int myRTPPort;
	private String myUserName;
	private String myPassword;
	private String mySIPDomain;

	private String sipServerIP;
	private Integer sipServerPort;
	private String sipServerName;
	private String mcuName;

	private String restServerIP;

	private String myStatus = "Online";// TODO:: update this

	private boolean mute = false;
	private String sipETag = "";

	private int seqNo = 0;
	private Calendar calendar = Calendar.getInstance();
	private SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
			"yyyyMMddhhmmss");

	private Conversation currentConversation = null;
	private List<Group> myGroups = new ArrayList<Group>();
	private List<ConversationThread> myThreads = new ArrayList<ConversationThread>();

	public void loadConfiguration() throws Exception {
		myIP = Utils.getLocalIpAddress();
		mySIPPort = Utils.getNextRandomPort();
		myRTPPort = Utils.getNextRandomPort();

		// TODO: externalize this
		mySIPDomain = "192.16.124.211";
		sipServerIP = "192.16.124.211";
		sipServerPort = 5060;
		sipServerName = "Opensips";
		mcuName = "plm";

		restServerIP = "http://192.16.124.211/REST";
	}

	/*
	 * contact nina
	 */
	public ConversationThread getThreadById(String threadId) {
		for (ConversationThread thread : myThreads) {
			if (thread.getThreadName().equals(threadId)) {
				return thread;
			}
		}
		return null;
	}

	public boolean existsThread(String threadId) {
		for (ConversationThread thread : myThreads) {
			if (thread.getThreadName().equals(threadId)) {
				return true;
			}
		}
		return false;
	}

	/*
	 * is used when creating thread in the process of invite
	 */
	public ConversationThread createThread() {
		ConversationThread newThread = new ConversationThread();
		myThreads.add(newThread);
		return newThread;
	}

	/*
	 * is used when importing thread created by the others
	 */
	public ConversationThread createThread(String threadId) {
		ConversationThread newThread = new ConversationThread(threadId);
		myThreads.add(newThread);
		return newThread;
	}

	public String createNewConversationId() {
		return myUserName + seqNo++;
	}

	public String createNewThreadId() {
		return myUserName + simpleDateFormat.format(calendar.getTime());
	}

	public String getMySIPURI() {
		return "sip:" + myUserName + "@" + mySIPDomain;
	}

	public String getMyIP() {
		return myIP;
	}

	public void setMyIP(String myIP) {
		this.myIP = myIP;
	}

	public int getMySIPPort() {
		return mySIPPort;
	}

	public void setMySIPPort(int mySIPPort) {
		this.mySIPPort = mySIPPort;
	}

	public int getMyRTPPort() {
		return myRTPPort;
	}

	public void setMyRTPPort(int myRTPPort) {
		this.myRTPPort = myRTPPort;
	}

	public String getMyUserName() {
		return myUserName;
	}

	public void setMyUserName(String myUserName) {
		this.myUserName = myUserName;
	}

	public String getMyPassword() {
		return myPassword;
	}

	public void setMyPassword(String myPassword) {
		this.myPassword = myPassword;
	}

	public String getMySIPDomain() {
		return mySIPDomain;
	}

	public void setMySIPDomain(String mySIPDomain) {
		this.mySIPDomain = mySIPDomain;
	}

	public String getSipServerIP() {
		return sipServerIP;
	}

	public void setSipServerIP(String sipServerIP) {
		this.sipServerIP = sipServerIP;
	}

	public Integer getSipServerPort() {
		return sipServerPort;
	}

	public void setSipServerPort(Integer sipServerPort) {
		this.sipServerPort = sipServerPort;
	}

	public String getSipServerName() {
		return sipServerName;
	}

	public void setSipServerName(String sipServerName) {
		this.sipServerName = sipServerName;
	}

	public String getMcuName() {
		return mcuName;
	}

	public void setMcuName(String mcuName) {
		this.mcuName = mcuName;
	}

	public List<Group> getMyGroups() {
		return myGroups;
	}

	public void setMyGroups(List<Group> myGroups) {
		this.myGroups = myGroups;
	}

	public String getRestServerIP() {
		return restServerIP;
	}

	public void setRestServerIP(String restServerIP) {
		this.restServerIP = restServerIP;
	}

	public String getMyStatus() {
		return myStatus;
	}

	public void setMyStatus(String myStatus) {
		this.myStatus = myStatus;
	}

	public String getSipETag() {
		return sipETag;
	}

	public void setSipETag(String sipETag) {
		this.sipETag = sipETag;
	}

	public int getSeqNo() {
		return seqNo;
	}

	public List<ConversationThread> getMyThreads() {
		return myThreads;
	}

	public void setMyThreads(List<ConversationThread> myThreads) {
		this.myThreads = myThreads;
	}

	public void setMute(boolean mute) {
		this.mute = mute;
	}

	public boolean isMute() {
		return mute;
	}

	public boolean threadExists(String threadName) {
		for (ConversationThread ct : myThreads) {
			if (ct.getThreadName().equals(threadName))
				return true;
		}
		return false;
	}

	public void setCurrentConversation(Conversation currentConversation) {
		this.currentConversation = currentConversation;
	}

	public Conversation getCurrentConversation() {
		return currentConversation;
	}

}
 public class Profile {

	private int id;
	private String username;
	private String domain;
	private String fullName;
	private String status;
	private String phoneNumber;
	private String sipURI;
	private String address;
	private String password;
	private String email_address;

	public Profile() {
		id = 0;
		username = "";
		domain = "";
		fullName = "";
		status = "";
		phoneNumber = "";
		sipURI = "";
		address = "";
		password = "";
		email_address = "";
	}

	public Profile(int id, String username,  String fullName,
			 String password, String emailAddress) {
		this();
		this.id = id;
		this.username = username;
		this.domain = "";
		this.fullName = fullName;
		this.phoneNumber = "";
		this.sipURI = "";
		this.address = "";
		this.password = password;
		this.email_address = emailAddress;
	}
	
	public Profile(JSONObject jsonObject) throws JSONException {
		this.id = jsonObject.getInt("id");
		this.address = jsonObject.getString("address");
		this.domain = jsonObject.getString("domain");
		this.email_address = jsonObject.getString("email_address");
		this.fullName = jsonObject.getString("fullName");
		this.phoneNumber = jsonObject.getString("phoneNumber");
		this.status = jsonObject.getString("status");
		this.username = jsonObject.getString("username");
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getDomain() {
		return domain;
	}

	public void setDomain(String domain) {
		this.domain = domain;
	}

	public String getFullName() {
		return fullName;
	}

	public void setFullName(String fullName) {
		this.fullName = fullName;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public String getPhoneNumber() {
		return phoneNumber;
	}

	public void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
	}

	public String getSipURI() {
		return sipURI;
	}

	public void setSipURI(String sipURI) {
		this.sipURI = sipURI;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getEmail_address() {
		return email_address;
	}

	public void setEmail_address(String email_address) {
		this.email_address = email_address;
	}
	
	public String toString(){
		return this.username;
	}
}
 public class Status {
	private boolean isSuccess;
	private String message;
	
	public Status(boolean isSuccess, String message) {
		super();
		this.isSuccess = isSuccess;
		this.message = message;
	}
	
	public boolean isSuccess() {
		return isSuccess;
	}

	public void setSuccess(boolean isSuccess) {
		this.isSuccess = isSuccess;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
} public class ContactRow {
	private String status;
	private String userName;
	private boolean isChecked;

	public ContactRow(String userName) {
		this("Offline", userName, false);
	}

	public ContactRow(String status, String userName, boolean isChecked) {
		super();
		this.status = status;
		this.userName = userName;
		this.isChecked = isChecked;
	}

	public String toString() {
		return this.userName;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public boolean isChecked() {
		return isChecked;
	}

	public void setChecked(boolean isChecked) {
		this.isChecked = isChecked;
	}
}
 public class ConversationRow implements Comparable<ConversationRow> {
	private boolean isChecked;
	private List<ContactRow> members;
	private Conversation conversation;

	public ConversationRow(Conversation conv) {
		this.conversation = conv;
		
		members=new ArrayList<ContactRow>();
		for (String callee : conv.getCallee()) {
			members.add(new ContactRow(callee));
		}
	}

	public int compareTo(ConversationRow other) {
		return -conversation.getDate().compareTo(other.getConversation().getDate());
	}

	public boolean isChecked() {
		return isChecked;
	}

	public void setChecked(boolean isChecked) {
		this.isChecked = isChecked;
	}

	public Conversation getConversation() {
		return conversation;
	}

	public void setConversation(Conversation conversation) {
		this.conversation = conversation;
	}

	public List<ContactRow> getMembers() {
		return members;
	}

	public void setMembers(List<ContactRow> members) {
		this.members = members;
	}
}
 public class ConversationTabExpandableListAdapter extends
		BaseExpandableListAdapter {
	private Map<String, Integer> iconHolder;
	private List<ConversationRow> conversations;
	private List<List<ContactRow>> members;

	private LayoutInflater inflater;

	public ConversationTabExpandableListAdapter(Context context,
			List<ConversationRow> conversations) {
		this.conversations = conversations;
		this.inflater = LayoutInflater.from(context);

		this.iconHolder = new HashMap<String, Integer>();
		this.iconHolder.put(NebulaSIPConstants.PRESENCE_ONLINE, R.drawable.green);
		this.iconHolder.put(NebulaSIPConstants.PRESENCE_BUSY, R.drawable.red);
		this.iconHolder.put(NebulaSIPConstants.PRESENCE_OFFLINE, R.drawable.white);
		this.iconHolder.put(NebulaSIPConstants.PRESENCE_AWAY, R.drawable.orange);
	}

	public View getGroupView(int groupPosition, boolean isExpanded,
			View convertView, ViewGroup parent) {
		View v = convertView;

		if (v == null) {
			v = inflater.inflate(R.layout.conversation_row, parent, false);
		}

		ConversationRow currentConversationRow = (ConversationRow) conversations
				.get(groupPosition);
		Conversation currentConversation = currentConversationRow.getConversation();

		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd - HH:mm:ss");
		String conversationName = dateFormat.format(currentConversation.getDate());

//		v.setTag(currentConversation);

		TextView threadName = (TextView) v
				.findViewById(R.id.tvConversationName);
		threadName.setText(conversationName);
		// threadName.setTag(conversation);
		// threadName.setOnLongClickListener(ConversationTab.getInstance());

		if (currentConversation.equals(NebulaApplication.getInstance().getMyIdentity()
				.getCurrentConversation())) {
			threadName.setBackgroundColor(Color.rgb(0x35, 0x6A, 0xA0));
		} else {
			threadName.setBackgroundColor(Color.TRANSPARENT);
		}

		Button b = (Button) v.findViewById(R.id.bInviteMembers);
		b.setTag(currentConversation);
		return v;
	}

	public View getChildView(int groupPosition, int childPosition,
			boolean isLastChild, View convertView, ViewGroup parent) {
		View v = convertView;

		if (v == null) {
			v = inflater.inflate(R.layout.member_row, parent, false);
		}

		ContactRow currentRow = conversations.get(groupPosition).getMembers()
				.get(childPosition);

		ImageView presence = (ImageView) v.findViewById(R.id.ivPresence);
		presence.setImageResource(iconHolder.get(currentRow.getStatus()));

		TextView userName = (TextView) v.findViewById(R.id.tvMemberName);
		userName.setText(currentRow.getUserName());

		return v;
	}

	public int getChildrenCount(int groupPosition) {
		return conversations.get(groupPosition).getMembers().size();
	}

	public Object getGroup(int groupPosition) {
		return conversations.get(groupPosition);
	}

	public int getGroupCount() {
		return conversations.size();
	}

	public long getGroupId(int groupPosition) {
		return (long) (groupPosition * 1024); // To be consistent with
		// getChildId
	}

	public boolean hasStableIds() {
		return true;
	}

	public boolean isChildSelectable(int groupPosition, int childPosition) {
		return true;
	}

	public void onGroupCollapsed(int groupPosition) {
	}

	public void onGroupExpanded(int groupPosition) {
	}

	public void setConversations(List<ConversationRow> conversations) {
		this.conversations = conversations;
	}

	public void setMembers(List<List<ContactRow>> members) {
		this.members = members;
	}

	public List<ConversationRow> getConversations() {
		return conversations;
	}

	public List<List<ContactRow>> getMembers() {
		return members;
	}

	public Object getChild(int groupPosition, int childPosition) {
		return members.get(groupPosition).get(childPosition);
	}

	public long getChildId(int groupPosition, int childPosition) {
		return (long) (groupPosition * 1024 + childPosition);
	}
}

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.nebula.R;
import org.nebula.R.drawable;
import org.nebula.client.rest.RESTConversationManager;
import org.nebula.client.sip.NebulaSIPConstants;
import org.nebula.client.sip.SIPManager;
import org.nebula.main.NebulaApplication;
import org.nebula.models.Conversation;
import org.nebula.models.ConversationThread;
import org.nebula.models.Group;
import org.nebula.models.MyIdentity;
import org.nebula.models.Profile;
import org.nebula.models.Status;
import org.nebula.ui.ContactRow;
import org.nebula.ui.ConversationRow;
import org.nebula.ui.ConversationTabExpandableListAdapter;
import android.app.AlertDialog;
import android.app.ExpandableListActivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.DialogInterface.OnClickListener;
import android.media.AudioManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.BaseExpandableListAdapter;
import android.widget.Toast;

/*
 * author: saad, michel
 */
package org.nebula.activities;




public class ConversationTab extends ExpandableListActivity implements
		OnClickListener {
	public static final String NOTIFY_MUTE = "NOTIFY_MUTE";
	public static final String NOTIFY_UNMUTE = "NOTIFY_UNMUTE";


	private List<ConversationRow> conversations = new ArrayList<ConversationRow>();
