%%%----------------------------------------------------------------------------------------------------
%%% Description - This module is spawned for each of the session id generated. This module is called
%%%	from handle_browser_packet and from all the components. This process in-turn spawns two more 
%%%	process called im_message and im_profile. The im_message process is used to send the messages 
%%%	to the client. The im_profile process is used to send the profile information of a particular 
%%%	user when requested by the client.
%%%----------------------------------------------------------------------------------------------------

-module(im_session).

-behaviour(gen_server).
-include("header.hrl").

-export([start/5, call_cast/12]).

-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

%%%----------------------------------------------------------------------------------------------------
%%%	External Function
%%%----------------------------------------------------------------------------------------------------
start(Config_Record, Session_ID, Publisher_ID, Protocol, Domain) ->
    gen_server:start(?MODULE, [Config_Record, Session_ID, Publisher_ID, Protocol, Domain], []).

init([Config_Record, Session_ID, Publisher_ID, Protocol, Domain]) ->
	if
        Config_Record == undefined ->
            Conf_Record = gen_server:call(load_config_record, get_config_record, infinity);
        true ->
            Conf_Record = Config_Record
    end,
    Connection_Map = dict:new(),
	{ok, Box_PID} = im_message_box:start(Session_ID, self(), Publisher_ID, Protocol, Domain),
	{ok, Profile_PID} = im_profile:start(self()),
	process_table:store(Session_ID, self()),
	{A, B, C} = erlang:now(),
	random:seed(A, B, C),
	MSNSessionID = random:uniform(16#FFFFFFFF),
	MSNMessageID = random:uniform(16#FFFFFFFF),
	{ok, #im_session_state{protocol = Protocol, domain = Domain, config_record = Conf_Record, connection_map = Connection_Map, publisher_id = Publisher_ID, remote_ip = "null", box_pid = Box_PID, session_id = Session_ID, used_services = [], profile_pid = Profile_PID, handle_packet_pid = -1, lifetime_ref = -1, msn_messageId = MSNMessageID, msn_sessionId = MSNSessionID, conference_id = 0, conference_details_list = []}}.
	 
handle_call(get_pid, _From, State) -> 
	{reply, {ok, self()}, State};

handle_call(_, _, State) ->
	{reply, "", State}.

%%%----------------------------------------------------------------------------------------------------
%%%	Description - This method is called from the handle_browser_packet module. This method is the 
%%%	entry point for all the client requests
%%%
%%%	Usage - {handle_request, #client_request(), XML Record, socket(), atom(), pid()}
%%%	The 4th parameter is either http or https.
%%%----------------------------------------------------------------------------------------------------
handle_cast({handle_request, Client_Record, Request_Record, Send_Socket, Socket_Type, Handle_Packet_PID}, State) ->
	io:format("im_session: Inside handle_request - Request_Record = ~n~p~n", [Request_Record]),
    #im_session_state{config_record = Config_Record, lifetime_ref = Lifetime_Ref} = State,
    if
        Lifetime_Ref /= -1 ->
            case timer:cancel(Lifetime_Ref) of
                {ok, cancel} ->
                    ?PRINT("Timer Cancelled ~n", []);
                _ ->
                    ?PRINT("Timer Not Cancelled ~n", [])
            end,
            case timer:apply_after(Config_Record#config_record.timeout, gen_server, cast, [self(), commit_suicide]) of
                {ok, Ref} ->
                    ?PRINT("Timer Reset ~n", []),
                    New_State = State#im_session_state{lifetime_ref = Ref, handle_packet_pid = Handle_Packet_PID};
                _ ->
                    New_State = State#im_session_state{lifetime_ref = -1, handle_packet_pid = Handle_Packet_PID}
            end;
        true ->
            case timer:apply_after(Config_Record#config_record.timeout, gen_server, cast, [self(), commit_suicide]) of
                {ok, Ref} ->
                    ?PRINT("Timer Reset ~n", []),
                    New_State = State#im_session_state{lifetime_ref = Ref, handle_packet_pid = Handle_Packet_PID};
                _ ->
                    New_State = State#im_session_state{lifetime_ref = -1, handle_packet_pid = Handle_Packet_PID}
            end
    end,
	{noreply, process_client_request(Client_Record, Request_Record, Send_Socket, Socket_Type, New_State)};

%%%----------------------------------------------------------------------------------------------------
%%%	Description - This method is called when the session idle timeout occurs
%%%----------------------------------------------------------------------------------------------------
handle_cast(commit_suicide, State) ->
    ?PRINT("Inside commit_suicide ~n", []),
    commit_suicide(State),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to send the data to the client.
%%%	Usage - {send_response, string(), socket(), integer(), atom(), string(), string(), pid())
%%%	The 5th parameter is either http or https. The 7th parameter is either "close" or "keep-alive"
%%%----------------------------------------------------------------------------------------------------
handle_cast({send_response, Response, Socket, Socket_Type, Client_Record}, State) ->
	#client_request{publisher_id = Publisher_ID, connection_type = Connection_Type, encoding = Encoding, callback = Handler, debug = Debug} = Client_Record,
	#im_session_state{protocol = Protocol, session_id = Session_ID, handle_packet_pid = Handle_Packet_PID, domain = Domain} = State,
	?PRINT("Inside send_response ~n", []),
	Content = {im_server, [{session, State#im_session_state.session_id}], Response},
	Content_String = protocol_wrapper:convert(Protocol, Content),
	socket:send_data(Session_ID, Protocol, Socket, Socket_Type, Content_String, Encoding, Publisher_ID, Connection_Type, Handle_Packet_PID, Handler, Debug, Domain),
	if
		Connection_Type /= close andalso Protocol == "json" ->
			?PRINT("################################ Send Response Successful (Socket Close)  Socket ~p  ################################ ~n~n", [Socket]),
			socket:close(Socket_Type, Handle_Packet_PID, close, Socket);
		true ->
			nothing
	end,
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to store the poll fd in im_message process, which is used to 
%%%	send the messages from server to client.
%%%	
%%%	Usage - {add_box_message_request, socket(), integer(), integer(), atom(), string(), pid()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_box_message_request, SD, Box_No, Encoding, Socket_Type, Connection_Type, Handle_Packet_PID, Handler, Debug}, State) ->
	#im_session_state{box_pid = Box_PID} = State,
	gen_server:cast(Box_PID, {add_box_message_request, SD, Box_No, Encoding, Socket_Type, Connection_Type, Handle_Packet_PID, Handler, Debug}),
	{noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to store the messages in the im_message process.
%%%	Usage - {add_message_to_box, string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_message_to_box, Message}, State) ->
	#im_session_state{box_pid = Box_PID} = State,
	gen_server:cast(Box_PID, {add_message_to_box, Message, false}),
	{noreply, State};

handle_cast({add_message_to_box, Message, Delete_Session}, State) ->
    #im_session_state{box_pid = Box_PID} = State,
    gen_server:cast(Box_PID, {add_message_to_box, Message, Delete_Session}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to set the status of the components
%%%	Usage - {set_status, integer(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({set_status, Status, Message}, State) ->
    #im_session_state{connection_map = Connection_Map} = State,
    ?PRINT("Setting Status ~n", []),
	Map_List = dict:to_list(Connection_Map),
	lists:foreach(fun({_, PID}) ->
						  gen_server:cast(PID, {set_status, Status, Message})
				  end, Map_List),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method generates the progress message
%%% Usage - {add_progress, boolean(), string(), string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_progress, Failure, Message, User_ID, Code, IM_Type}, State) ->
    #im_session_state{publisher_id = Publisher_ID} = State,
    ?PRINT("Inside Add Progress ~n", []),
    if
        Failure == true ->
            Length = length(Message),
            if
                Length == 0 ->
                    nothing;
                true ->
					Progress_Message = [{response, [{type, "progress"}, {im, IM_Type}, {login, User_ID}, {code, Code}], [Message]}],
                    gen_server:cast(self(), {add_message_to_box, Progress_Message}),
                    case gen_server:call(load_login_form, {get_login_form, false, Publisher_ID}) of
                        {ok, Login_Form} ->
                            gen_server:cast(self(), {add_message_to_box, Login_Form});
                        {error, _} ->
                            nothing
                    end
            end;
        true ->
            Length = length(Message),
            if
                Length == 0 ->
                    nothing;
                true ->
					Progress_Message = [{response, [{type, "progress"}, {im, IM_Type}, {login, User_ID}, {code, Code}], [Message]}],
                    gen_server:cast(self(), {add_message_to_box, Progress_Message})
            end
    end,
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is called when the connection from the third party servers is closed 
%%%	abruptly. This method removes the process associated with that component and sends the fatal 
%%%	message to the client.
%%%
%%% Usage - {add_abrupt_close, string(), string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_abrupt_close, Code, Message, User_ID, IM_Type}, State) ->
	io:format("Inside add_abrupt_close ~n"),
    Message_Length = length(Message),
    if
        Message_Length /= 0 ->
			Close_Message = [{response, [{type, "error"}, {errtype, "fatal"}, {im, IM_Type}, {login, User_ID}, {code, Code}], [Message]}];
        true ->
			Close_Message = [{response, [{type, "error"}, {errtype, "fatal"}, {im, IM_Type}, {login, User_ID}, {code, Code}], ["Disconnected From Server"]}]
    end,
    gen_server:cast(self(), {add_message_to_box, Close_Message}),
    gen_server:cast(self(), {remove_im, IM_Type, User_ID, true}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used when the component processes are needed to be killed because 
%%%	they are no longer required. Also, the entry of the service from the connection map hash table 
%%%	is removed. If all the components are killed, the session process is also killed.
%%%
%%% Usage - {remove_im, string(), string(), boolean()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({remove_im, IM_Type, Login, Failure_Close}, State) ->
	?PRINT("im_session: Inside remove_im ~n", []),
    #im_session_state{connection_map = Connection_Map, session_id = Session_ID, used_services = Used_Services, remote_ip = Remote_IP, publisher_id = Publisher_ID} = State,
	case dict:find(IM_Type, Connection_Map) of 
		{ok, IM_PID} ->
			gen_server:call(IM_PID, {add_update_db, Remote_IP, Publisher_ID, "0", Session_ID}, infinity),
			New_Connection_Map = dict:erase(IM_Type, Connection_Map),
			New_Used_Services = lists:delete(IM_Type, Used_Services),
		    gen_server:cast(IM_PID, kill_connection);
		error ->
			New_Connection_Map = Connection_Map,
			New_Used_Services = lists:delete(IM_Type, Used_Services)
	end,
	if
		Failure_Close == false ->
			Logout_Message = [{logout, [{im, IM_Type}, {login, Login}], []}],
			gen_server:cast(self(), {add_message_to_box, Logout_Message});
		true ->
			nothing
	end,
	if
		length(New_Used_Services) == 0 ->
			gen_server:cast(self(), remove_session);
		true ->
			nothing
	end,
    {noreply, State#im_session_state{connection_map = New_Connection_Map, used_services = New_Used_Services}};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to send the <logout/> tag. The <logout/> tag means that the 
%%%	client needs to be reset. 
%%% Usage - remove_session
%%%----------------------------------------------------------------------------------------------------
handle_cast(remove_session, State) ->
	gen_server:cast(self(), {add_message_to_box, [?IM_LOGOUT_TAG], true}),
	{noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method sends the non fatal error response
%%% Usage - {send_nonfatal_error_response, string(), string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({send_nonfatal_error_response, Code, Message, User_ID, IM_Type}, State) ->
	Error_Message = [{response, [{type, "error"}, {errtype, "nonfatal"}, {im, IM_Type}, {login, User_ID}, {code, Code}], [Message]}],
    gen_server:cast(self(), {add_message_to_box, Error_Message}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to send the buddy list to the client at the time of login.
%%% Usage - {add_data, string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_data, Data, User_ID, IM_Type}, State) ->
	Buddy_String = [{buddies, [{im, IM_Type}, {login, User_ID}], Data}],
    gen_server:cast(self(), {add_message_to_box, Buddy_String}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to send the updated status of a buddy to the client
%%% Usage - {add_status, string(), string(), string(), integer(), string(), string(), string()} 
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_status, From, To, Group, Status, Msg, Blocked, IM_Type}, State) ->
	gen_server:cast(self(), {add_status, From, "", To, Group, Status, Msg, Blocked, IM_Type}),
	{noreply, State};

handle_cast({add_status, From, Alias, To, Group, Status, Msg, Blocked, IM_Type}, State) ->
    ?PRINT("Inside Add Status ~n", []),
	case regexp:gsub(Msg, "\r", "") of 
		{ok, Modified_Msg_1, _} ->
			New_Message_1 = Modified_Msg_1;
		_ ->
			New_Message_1 = Msg
	end,
	case regexp:gsub(New_Message_1, "\n", "") of
        {ok, Modified_Msg_2, _} ->
            Message = Modified_Msg_2;
        _ ->
            Message = New_Message_1
    end,
	Length = length(Message),
    case Status of
        ?IM_OFFLINE ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_OFFLINE_STR
            end,
            Status_String = ?IM_OFFLINE_STATUS_STR;
        ?IM_AVAILABLE ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_ONLINE_STR
            end,
            Status_String = ?IM_ONLINE_STATUS_STR;
        ?IM_BUSY ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_BUSY_STR
            end,
            Status_String = ?IM_BUSY_STATUS_STR;
        ?IM_IDLE ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_IDLE_STR
            end,
            Status_String = ?IM_IDLE_STATUS_STR;
        ?IM_AWAY ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_AWAY_STR
            end,
            Status_String = ?IM_AWAY_STATUS_STR;
        ?IM_BRB ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_BRB_STR
            end,
            Status_String = ?IM_AWAY_STATUS_STR;
        ?IM_ON_PHONE ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_ON_PHONE_STR
            end,
            Status_String = ?IM_AWAY_STATUS_STR;
        ?IM_OUT_FOR_LUNCH ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_OUT_FOR_LUNCH_STR
            end,
            Status_String = ?IM_AWAY_STATUS_STR;
        ?IM_VACATION ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_VACATION_STR
            end,
            Status_String = ?IM_AWAY_STATUS_STR;
        ?IM_NOT_AT_HOME ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_NOT_AT_HOME_STR
            end,
            Status_String = ?IM_AWAY_STATUS_STR;
        ?IM_NOT_AT_OFFICE ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_NOT_AT_OFFICE_STR
            end,
            Status_String = ?IM_AWAY_STATUS_STR;
        ?IM_NOT_AT_DESK ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_NOT_AT_DESK_STR
            end,
            Status_String = ?IM_AWAY_STATUS_STR;
        ?IM_STEPPED_OUT ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_STEPPED_OUT_STR
            end,
            Status_String = ?IM_AWAY_STATUS_STR;
        ?IM_CUSTOM ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = "none"
            end,
            Status_String = ?IM_AWAY_STATUS_STR;
        _ ->
            if
                Length > 0 ->
                    Custom_String = Message;
                true ->
                    Custom_String = ?IM_AWAY_STR
            end,
            Status_String = ?IM_AWAY_STATUS_STR
    end,
    if
        Blocked == true ->
            Blocked_String = "yes";
        true ->
            Blocked_String = "no"
    end,
	Update_String = [{update, [{im, IM_Type}, {login, To}, {group, Group}, {name, From}, {alias, Alias}, {status, Status_String}, {custom, Custom_String}, {blocked, Blocked_String}], []}],
    gen_server:cast(self(), {add_message_to_box, Update_String}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to send the typing indication to the client
%%% Usage - {add_typing_indicator, string(), string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_typing_indicator, From, To, Typing_State, IM_Type}, State) ->
    if
        Typing_State == 1 ->
            Typing_Type = "start";
        true ->
            Typing_Type = "stop"
    end,
	Typing_String = [{typing, [{type, Typing_Type}, {im, IM_Type}, {login, To}, {name, From}], []}],
    gen_server:cast(self(), {add_message_to_box, Typing_String}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to send message to the client
%%% Usage - {add_message, string(), string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_message, From, From_Alias, To, Msg, Time, IM_Type}, State) ->
	#im_session_state{protocol = Protocol} = State,
	case regexp:gsub(Msg, "\r", "") of
        {ok, Modified_Msg_1, _} ->
            New_Message_1 = Modified_Msg_1;
        _ ->
            New_Message_1 = Msg
    end,
    case regexp:gsub(New_Message_1, "\n", "") of
        {ok, Modified_Msg_2, _} ->
            Message = Modified_Msg_2;
        _ ->
            Message = New_Message_1
    end,
	if
		IM_Type == "msn" ->
			Is_Unicode = is_unicode(Message),
			if
				Is_Unicode == true ->
					New_Message = xmerl_ucs:to_utf8(Message);
				true ->
					New_Message = Message
			end;
		true ->
			New_Message = Message
	end,
	if
		Protocol == "json" ->
			Message_String = [{message, [{im, IM_Type}, {login, To}, {name, From}, {alias, From_Alias}, {time, Time}], [find_and_replace:characters([], New_Message)]}];
		true ->
			Message_String = [{message, [{im, IM_Type}, {login, To}, {name, From}, {alias, From_Alias}, {time, Time}], [New_Message]}]
	end,
    gen_server:cast(self(), {add_message_to_box, Message_String}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to send feeds to the client
%%% Usage - {add_feeds, string(), string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_feeds, Type, From, To, Next, Feeds, IM_Type}, State) ->
	Feed_String = [{feeds, [{im, IM_Type}, {login, To}, {name, From}, {type, Type}, {next, Next}], [xmerl_ucs:to_utf8(Feeds)]}],
	gen_server:cast(self(), {add_message_to_box, Feed_String}),
	{noreply, State};


handle_cast({add_chat_history, Login, UID, IM_Type, Chat_Message}, State) ->
	Chat_History = [{chat_history, [{im, IM_Type}, {login, Login}, {uid, UID}], Chat_Message}],
	gen_server:cast(self(), {add_message_to_box, Chat_History}),
	{noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to send the accept information to the client, when a buddy 
%%%	accepts the friendship request sent by the IM Server.
%%% Usage - {add_buddy_confirm, string(), string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_buddy_confirm, From, To, _Message, IM_Type}, State) ->
	Add_Buddy_String = [{buddyapprove, [{im, IM_Type}, {login, To}, {name, From}, {type, "confirm"}], []}],
    gen_server:cast(self(), {add_message_to_box, Add_Buddy_String}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to send the deny information to the client, when a buddy
%%% rejects the friendship request sent by the IM Server.
%%% Usage - {add_buddy_deny, string(), string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_buddy_deny, From, To, _Message, IM_Type}, State) ->
	Add_Buddy_String = [{buddyapprove, [{im, IM_Type}, {login, To}, {name, From}, {type, "deny"}], []}],
    gen_server:cast(self(), {add_message_to_box, Add_Buddy_String}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to send the invalid information to the client, when a 
%%% request like add/remove/block has generated an error on the third party servers.
%%% Usage - {add_buddy_invalid, string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_buddy_invalid, From, To, IM_Type}, State) ->
	Invalid_Buddy_String = [{buddyapprove, [{im, IM_Type}, {login, To}, {name, From}, {type, "invalid"}], []}],
    gen_server:cast(self(), {add_message_to_box, Invalid_Buddy_String}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used when the deletion of a group is not successful. By default, when 
%%%	a group is deleted, the client removes the group without waiting for the successful removal of the 
%%%	group at the server end. So, if the group removal is not successful, the server sends the list of
%%%	buddies that are not removed. to the client. 
%%% Usage - {add_buddy_to_client, string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_buddy_to_client, Data, User_ID, IM_Type}, State) ->
	Add_Buddy_String = [{add_buddies, [{im, IM_Type}, {login, User_ID}], Data}], 
    gen_server:cast(self(), {add_message_to_box, Add_Buddy_String}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used when the renaming of a group is not successful. By default, when
%%% a group is renamed, the client renames the group without waiting for the successful renaming of the
%%% group at the server end. So, if the group renaming is not successful, the server asks the client 
%%%	to change back to the old group.
%%% Usage - {add_rename_group, string(), string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_rename_group, Old_Group, New_Group, User_ID, IM_Type}, State) ->
	Rename_Group_String = [{rename_group, [{im, IM_Type}, {login, User_ID}, {old_group, Old_Group}, {new_group, New_Group}], []}],
	gen_server:cast(self(), {add_message_to_box, Rename_Group_String}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used the addition of a group is not successful. 
%%% Usage - {add_remove_group, string(), string(), string()}
%----------------------------------------------------------------------------------------------------
handle_cast({add_remove_group, Group, User_ID, IM_Type}, State) ->
	Remove_Group_String = [{remove_group, [{im, IM_Type}, {login, User_ID}, {group, Group}], []}],
	gen_server:cast(self(), {add_message_to_box, Remove_Group_String}),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used a contact cannot be moved.
%%% Usage - {add_move_contact, string(), string(), string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_move_contact, Buddy_Name, Old_Group, New_Group, User_ID, IM_Type}, State) ->
	Move_Contact_String = [{move_contact, [{im, IM_Type}, {login, User_ID}, {name, Buddy_Name}, {old_group, Old_Group}, {new_group, New_Group}], []}],
	gen_server:cast(self(), {add_message_to_box, Move_Contact_String}),
    {noreply, State};

%begin file transfer work
handle_cast({add_ask_file_transfer, Buddy_Name, File_Name, Key, User_ID, IM_Type}, State) ->
	Ask_File_Transfer_String = [{file, [{im, IM_Type}, {login, User_ID}, {name, Buddy_Name}, {file_name, File_Name}, {file_size, []}, {key, Key}, {type, "ask"}, {content, []}], []}],
	gen_server:cast(self(), {add_message_to_box, Ask_File_Transfer_String}),
	{noreply, State};

handle_cast({add_receive_file, Buddy_Name, File_Name, User_ID, IM_Type}, State) ->
	%os:cmd("chmod 777 /var/www/file_receive/" ++ File_Name),
	%os:cmd("chown narasimham:narasimham /var/www/file_receive/" ++ File_Name),
	Receive_File_String = [{file, [{im, IM_Type}, {login, User_ID}, {name, Buddy_Name}, {file_name, File_Name}, {file_size, []}, {key, []}, {type, "receive"}], []}],
	gen_server:cast(self(), {add_message_to_box, Receive_File_String}),
    {noreply, State};
%end file transfer work

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to store the statistics information.
%%% Usage - {add_update_db, string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({add_update_db, Login, IM_Type, Connection_Type}, State) ->
    #im_session_state{session_id = Session_ID, publisher_id = Publisher_ID, remote_ip = Remote_IP} = State,
	Session_Query = io_lib:format("insert into session_login_info values('~s', '~s', '~s', '~s')", [Session_ID, IM_Type, Login, time:seconds_from_year_zero()]),
	db_manager:update_db(Session_Query),
	Stats_Query = "call add_stats('" ++ Login ++ "', '" ++ IM_Type ++ "', " ++ Connection_Type ++ ", '" ++ Remote_IP ++ "', '" ++ Publisher_ID ++ "')",
    db_manager:update_db(Stats_Query),
    {noreply, State};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to send referral to Yahoo buddies
%%% Usage - {send_referral, [@buddies()], string(), string(), string(), string(), string(), string(), string(), string(), string()}
%%%----------------------------------------------------------------------------------------------------
handle_cast({send_referral, [HeadBuddy = {buddies, [IM_Type], [_From], [To]}|BuddyTail], Message, URLToBeSent, Customer, Remote_IP, Remote_Host, Refer_URL, Private, Publisher_ID, Referer}, State) ->
	#im_session_state{connection_map = Connection_Map, progress = Progress, progress_rate = Progress_Rate} = State,
    New_Progress = Progress + Progress_Rate,
	case send_referral(HeadBuddy, Message, URLToBeSent, Customer, Remote_IP, Remote_Host, Refer_URL, Private, Publisher_ID, Referer) of 
		{ok, Msg} ->
			case dict:find(IM_Type, Connection_Map) of 
				{ok, PID} ->
					Response = [{referral, [{progress, integer_to_list(round(New_Progress))}], []}],
					gen_server:cast(PID, {send_message, To, ?MSG_CHAT, Msg});
		        error ->
					Progress_Response = [{referral, [{progress, integer_to_list(round(New_Progress))}], []}],
					Response = [{response, [{type, "error"}, {errtype, "client"}, {im, IM_Type}, {code, "104"}], ["Message Send Failure"]}] ++ Progress_Response
		    end;
		_ ->
			Progress_Response = [{referral, [{progress, integer_to_list(round(New_Progress))}], []}],
			Response = [{response, [{type, "error"}, {errtype, "client"}, {im, IM_Type}, {code, "104"}], ["Message Send Failure"]}] ++ Progress_Response
	end,
	gen_server:cast(self(), {add_message_to_box, Response}),
	timer:apply_after(500, ?MODULE, call_cast, [send_referral, BuddyTail, Message, URLToBeSent, Customer, Remote_IP, Remote_Host, Refer_URL, Private, Publisher_ID, Referer, self()]),
	{noreply, State#im_session_state{progress=New_Progress}};

handle_cast({send_referral, [_HeadBuddy|BuddyTail], Message, URLToBeSent, Customer, Remote_IP, Remote_Host, Refer_URL, Private, Publisher_ID, Referer}, State) ->
    gen_server:cast(self(), {send_referral, BuddyTail, Message, URLToBeSent, Customer, Remote_IP, Remote_Host, Refer_URL, Private, Publisher_ID, Referer}),
    {noreply, State};

handle_cast({send_referral, [], _, _, _, _, _, _, _, _, _}, State) ->
    {noreply, State};

%begin conference related code (handling casts from service pids)
%begin narasimham conference handling

handle_cast({add_message_to_conference,ConferenceId,LoginName,MessageFrom,Msg,IM_Type,Service},State) ->
	case lists:keysearch(ConferenceId,1,State#im_session_state.conference_details_list) of
		{value,{_NewConferenceId,HostName,HostService,ServicesList}}	->
			case regexp:gsub(Msg, "\r", "") of
				{ok, Modified_Msg_1, _} ->
					New_Message_1 = Modified_Msg_1;
				_ ->
					New_Message_1 = Msg
			end,
			case regexp:gsub(New_Message_1, "\n", "") of
				{ok, Modified_Msg_2, _} ->
					Message1 = Modified_Msg_2;
				_ ->
					Message1 = New_Message_1
			end,
			if 
				IM_Type == "msn"	->
					Is_Unicode = is_unicode(Message1),
					if
						Is_Unicode == true ->
							Message = xmerl_ucs:to_utf8(Message1);
						true ->
							Message = Message1
					end;
				true	->
					Message = Message1
			end,		
			Connection_Map = State#im_session_state.connection_map,
			%% unify the message to all services here
			TaggedMessage 	= find_and_replace:words(Msg),
			TokenizedMessage= html_tokenise:string2toks(TaggedMessage),
			RawMessage	= lists:flatten(lists:reverse(get_raw_message(TokenizedMessage))),
			UnifiedMessage1 = io_lib:format("&gt;~s",[RawMessage]),
			UnifiedMessage2 = ["&lt;font color=","\"#000000","\"",UnifiedMessage1,"&lt;/font","&gt;"],
			A = lists:flatten(UnifiedMessage2),
			B = element(2, regexp:gsub(lists:sublist(A, 1, 38), "&quot;", "'")),
			UnifiedMsg = str:append(B, lists:sublist(A, 39, length(A))),		
			cast_join_leave_message_to_other_services(ServicesList,IM_Type,LoginName,ConferenceId,UnifiedMsg,Connection_Map),
			case IM_Type == "msn" orelse IM_Type == "yah" orelse IM_Type == "jab" of
			true ->
				case regexp:split(Message, MessageFrom ++ " says:") of
				{ok, [[],Field]} ->
					WebIMClientMsg = Field;
				{ok, [Field1,Field2]} ->
					WebIMClientMsg = Field1 ++ " " ++ Field2;
				_->
					WebIMClientMsg = Message
				end;
			_->
				WebIMClientMsg = Message
			end,
			Message_String = [{conf, [{hostname, HostName}, {hostservice, HostService}, {id, ConferenceId}, {operation, "message"}], 
							   [{conference,[{im, IM_Type}, {login, LoginName}, {service, Service}, {name, MessageFrom}],
								 [{message,[],[WebIMClientMsg]}]}]}],
			gen_server:cast(self(), {add_message_to_box,Message_String});
		false	->
			io:format("im_session: add_message_to_conference clause Conference does not exists with id ~p ~n",[ConferenceId])
	end,
	{noreply, State};

handle_cast({typing_indicator_to_conference,ConferenceId,LoginName,TypingUser,TypingState,IM_Type},State)->
	if
		TypingState == 1 ->
			Typing_Type = "start";
		true ->
			Typing_Type = "stop"
	end,
	Typing_String = [{conference, [{im, IM_Type}, {login, LoginName}, {id, ConferenceId}, {operation, "typing_indicator"}, {time, []}, {name, TypingUser}, {type, Typing_Type}], []}],
    gen_server:cast(self(), {add_message_to_box, Typing_String}),
    {noreply, State};

handle_cast({buddy_joins_conference,ConferenceId,LoginName,UserJoined,IM_Type,Service},StateData)->
	io:format("im_session:  ~n~p~n",[{buddy_joins_conference,ConferenceId,LoginName,UserJoined,IM_Type,Service}]),
	Connection_Map = StateData#im_session_state.connection_map,
	case lists:keysearch(ConferenceId,1,StateData#im_session_state.conference_details_list) of
	{value,{NewConferenceId,HostName,HostService,ServicesList}}	->
		String = [{conf, [{hostname, HostName}, {hostservice, HostService}, {id, NewConferenceId}, {operation, "join"}], [{conference,[{im, IM_Type}, {login, LoginName}, {service, Service}, {name, UserJoined}], []}]}],
		gen_server:cast(self(),{add_message_to_box, String}),
		%% formattiing the message to send to services
		TempMessage1 = io_lib:format("&gt;Buddy ~s says ~s  has joined the conference/conversation ",[HostName,UserJoined]),
		TempMessage2 = ["&lt;font color=","\"#000000","\"",TempMessage1,"&lt;/font","&gt;"],
		A = lists:flatten(TempMessage2),
		B = element(2, regexp:gsub(lists:sublist(A, 1, 38), "&quot;", "'")),
		Message = str:append(B, lists:sublist(A, 39, length(A))),
		
		cast_join_leave_message_to_other_services(ServicesList,IM_Type,LoginName,ConferenceId,Message,Connection_Map),
		%% update the conference_details_list - mean add 1 to the count per particular service where buddy joined
		%% should i inform the newly joined about existing memebers in the conference
		Temp = lists:delete({NewConferenceId,HostName,HostService,ServicesList},StateData#im_session_state.conference_details_list),
		case lists:keysearch(IM_Type,1,ServicesList) of 
		{value,{TypeIM,IMLogin,Count,List}} ->
			Temp2 = lists:delete({TypeIM,IMLogin,Count,List},ServicesList),
			NewServicesList = [{TypeIM,IMLogin,Count + 1, [UserJoined | lists:delete(UserJoined,List)]} | Temp2];
		false	->
			io:format("im_session: MSN/Gtalk buddies have joined the conference ~n"),
			NewServicesList = [{IM_Type,LoginName,1,[UserJoined]} | ServicesList]	
		end,
		NewConference_Details_List = [{NewConferenceId,HostName,HostService,NewServicesList} | Temp],
		NewStateData = StateData#im_session_state{conference_details_list = NewConference_Details_List};
	false	->
		io:format("~n ~n im_session: Remote MSN or GTalk Buddy  initiated the conference i think ~n ~n"),
		Temp = StateData#im_session_state.conference_details_list,
		NewConferenceDetailsList = [{ConferenceId,LoginName,IM_Type,[{IM_Type,LoginName,1,[UserJoined]}]} | Temp],
		String = [{conf,[{hostname, LoginName}, {hostservice, IM_Type}, {id, ConferenceId}, {operation, "join"}], [{conference,[{im, IM_Type}, {login, LoginName}, {service, Service}, {name, UserJoined}], []}]}],
		gen_server:cast(self(),{add_message_to_box, String}),
		NewStateData = StateData#im_session_state{conference_details_list = NewConferenceDetailsList}
	end,
	{noreply,NewStateData};

handle_cast({buddy_leaves_conference,ConferenceId,LoginName,UserLeft,IM_Type,Service}, StateData)->
	case lists:keysearch(ConferenceId,1,StateData#im_session_state.conference_details_list) of
	{value, {NewConferenceId,HostName,HostService,ServicesList}}	->
		String = [{conf,[{hostname, HostName}, {hostservice, HostService}, {id, ConferenceId}, {operation, "leave"}],[{conference,[{im, IM_Type}, {login, LoginName}, {service, Service}, {name, UserLeft}],[]}]}],
		gen_server:cast(self(),{add_message_to_box, String}),
		
		%% formattiing the message to send to services
		TempMessage1 = io_lib:format("&gt;Buddy ~s says ~s  has left the conference/conversation ",[HostName,UserLeft]),
		TempMessage2 = ["&lt;font color=","\"#000000","\"",TempMessage1,"&lt;/font","&gt;"],
		A = lists:flatten(TempMessage2),
		B = element(2, regexp:gsub(lists:sublist(A, 1, 38), "&quot;", "'")),
		Message = str:append(B, lists:sublist(A, 39, length(A))),
		
		Connection_Map = StateData#im_session_state.connection_map,
		cast_join_leave_message_to_other_services(ServicesList,IM_Type,LoginName,ConferenceId,Message,Connection_Map),
		%% update the conference_details_list - mean subtract 1 from the count per particular service where buddy joined
		Temp = lists:delete({NewConferenceId,HostName,HostService,ServicesList},StateData#im_session_state.conference_details_list),
		case lists:keysearch(IM_Type,1,ServicesList) of 
		{value,{TypeIM,IMLogin,Count,Members}} ->
			io:format("buddies leaving the conference........ ~n~n~n~p~n~n~n",[{TypeIM,IMLogin,Count,Members}]),
			Temp2 = lists:delete({TypeIM,IMLogin,Count,Members},ServicesList),
			if
			Count >= 1 -> 
				NewServicesList = [{TypeIM,IMLogin, Count-1, lists:delete(UserLeft,Members)} | Temp2],
				NewConference_Details_List = [{NewConferenceId,HostName,HostService,NewServicesList} | Temp];
			true ->
				io:format("im_session: Mebers count in the conference from service ~p is ~p ~n",[TypeIM,Count]),
				NewServicesList = Temp2,
				NewConference_Details_List = [{NewConferenceId,HostName,HostService,NewServicesList} | Temp]
			end;
		false	->
			NewServicesList = ServicesList,
			NewConference_Details_List = [{NewConferenceId,HostName,HostService,NewServicesList} | Temp]
		end,
		NewStateData = StateData#im_session_state{conference_details_list = NewConference_Details_List};
	false	->
		io:format("~n ~n im_session: Hello check up the cast statement in user_leave_conference cast statement ~n ~n"),
		NewStateData = StateData
	end,
	{noreply,NewStateData};

handle_cast({accept_request,ConferenceId,LoginName,InvitationFrom,IM_Type,Service,Message},StateData)->
	io:format("im_session: got accept_request for conf ~s from service im_~s ~n",[ConferenceId,IM_Type]),
	Message_String = [{conf, [{hostname, LoginName}, {hostservice, IM_Type}, {id, ConferenceId}, {operation, "accept_request"}],
					   [{conference, [{im, IM_Type}, {login, LoginName}, {service, Service}, {name, InvitationFrom}],
						 [{message,[],[Message]}]}]}],
	gen_server:cast(self(), {add_message_to_box,Message_String}),
	{noreply,StateData};

%% no need to send accept notification to client
handle_cast({reject,ConferenceId,LoginName,RejectFrom,IM_Type,Service},StateData)->
	case lists:keysearch(ConferenceId,1,StateData#im_session_state.conference_details_list) of
		{value,{NewConferenceId,HostName,HostService,_ServicesList}}	->
			Message_String = [{conf, [{hostname, HostName}, {hostservice, HostService}, {id, NewConferenceId}, {operation, "reject"}],
							   [{conference,[{im, IM_Type}, {login, LoginName}, {service, Service}, {name, RejectFrom}], 
								 []}]}],
			gen_server:cast(self(), {add_message_to_box,Message_String});
		false	->
			%% reply back to yahoo saying that conference doesn't exist
			io:format("im_session: Can a service cast to a conference that does not exist~n")
	end,
	{noreply,StateData};

%%end conference related code 

handle_cast({commit_suicide, State}, _) ->
	io:format("im_session: commit_suicide~n"),
	{stop, normal, State};

handle_cast(kill_process, State) ->
	io:format("im_session: kill_process~n"),
    {stop, normal, State};

handle_cast(_, State)->
	{noreply, State}.

handle_info({'EXIT', _Pid, _}, State) ->
    {noreply, State};

handle_info(_, State) ->
    {noreply, State}.

terminate(_, State) ->
	#im_session_state{protocol = Protocol, domain = Domain, box_pid = Box_PID, profile_pid = Profile_PID, publisher_id = Publisher_ID, session_id = Session_ID, handle_packet_pid = Handle_Packet_PID} = State,
	Box_State = gen_server:call(Box_PID, get_message_box_state, infinity),
	#im_message_box_state{poll_sd_list = Poll_SD_List} = Box_State,
	if
		Poll_SD_List /= "" ->
			[Poll_Info_Record | _] = Poll_SD_List,
			#poll_info{socket = Poll_SD, encoding = Encoding, socket_type = Socket_Type, handler = Handler, debug = Debug} = Poll_Info_Record,
			spawn(send_login_form, timeout, [Publisher_ID, Poll_SD, true, Encoding, Socket_Type, Protocol, Handle_Packet_PID, Handler, Debug, Domain]);
		true ->
			gen_server:cast(Handle_Packet_PID, kill_process)
	end,
	kill_child_process(State),
	process_table:remove(Session_ID),
    gen_server:cast(Box_PID, kill_process),
    gen_server:cast(Profile_PID, kill_process),
	Query = io_lib:format("delete from session_info where session_id = '~s'", [Session_ID]),
    db_manager:update_db(Query),
	?PRINT("Session Process Killed ~n", []).

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

process_client_request(Client_Record, _, Send_Socket, Socket_Type, State) when Client_Record#client_request.session == "" andalso Client_Record#client_request.request_len == "0" ->
	?PRINT("Request Length = 0 & Session ID = \"\" ~n", []),
	#client_request{connection_type = Connection_Type} = Client_Record,
	#im_session_state{handle_packet_pid = Handle_Packet_PID} = State,
	socket:close(Socket_Type, Handle_Packet_PID, Connection_Type, Send_Socket),
	State;

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the client request. This method is called when the 
%%%	length of the client request is "0". This means that the client is asking for the buddy list again.
%%%	So, the server sends the buddy list again to the client.
%%%
%%% Usage - process_client_request(#client_request(), XML Record, socket(), atom(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_client_request(Client_Record, _, Send_Socket, Socket_Type, State) when Client_Record#client_request.type == "none" andalso Client_Record#client_request.request_len == "0" ->
	#client_request{encoding = Encoding, callback = Handler, debug = Debug} = Client_Record,
	#im_session_state{protocol = Protocol, used_services = Used_Services, handle_packet_pid = Handle_Packet_PID, domain = Domain} = State,
	L1 = length(Used_Services),
	if 
		L1 > 0 ->
			Buddy_List_String = lists:foldl(fun(IM_Type, Buddy_String) ->
													case dict:find(IM_Type, State#im_session_state.connection_map) of 
														{ok, PID} ->
															{List, User_ID} = gen_server:call(PID, get_buddy_list, infinity),
															Buddy_List = [{buddies, [{im, IM_Type}, {login, User_ID}], List}],
															str:append(Buddy_String, Buddy_List);
														_ ->
															Buddy_String
													end end, "", Used_Services),
			New_Buddy_List_String = [{box, [{start, "0"}, {next, "0"}], []}] ++ Buddy_List_String ++ get_conference_details_list(State#im_session_state.conference_details_list),
			gen_server:cast(self(), {send_response, New_Buddy_List_String, Send_Socket, Socket_Type, Client_Record});
		true ->
			spawn(send_login_form, start, [Client_Record, Send_Socket, true, Encoding, Socket_Type, Protocol, Handle_Packet_PID, Handler, Debug, Domain])
	end,
	State;

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the client request.
%%% Usage - process_client_request(#client_request(), XML Record, socket(), atom(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_client_request(Client_Record, Request_Record, Send_Socket, Socket_Type, State) when Client_Record#client_request.type == "none" ->
	Processed_Atleast_One_Record = false,
	handle_request(Request_Record, Client_Record, Processed_Atleast_One_Record, Send_Socket, Socket_Type, State);

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the client request. This method sends the login form
%%%	to the client.
%%% Usage - process_client_request(#client_request(), XML Record, socket(), atom(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_client_request(Client_Record, _, Send_Socket, Socket_Type, State) when Client_Record#client_request.type == "loginform" ->
	#client_request{publisher_id = Publisher_ID, connection_type = Connection_Type} = Client_Record,
	#im_session_state{handle_packet_pid = Handle_Packet_PID} = State,
	case gen_server:call(load_login_form, {get_login_form, false, Publisher_ID}, infinity) of
		{ok, Login_Form} ->
			gen_server:cast(self(), {send_response, Login_Form, Send_Socket, Socket_Type, Client_Record});
		error ->
			socket:close(Socket_Type, Handle_Packet_PID, Connection_Type, Send_Socket)
	end,
	State;

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the client request. This method retrieves the profile
%%%	of a particular buddy.
%%% Usage - process_client_request(#client_request(), XML Record, socket(), atom(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_client_request(Client_Record, _, Send_Socket, Socket_Type, State) when Client_Record#client_request.type == "profile" ->
	#im_session_state{profile_pid = Profile_PID} = State,
	gen_server:cast(Profile_PID, {get_profile, Send_Socket, Socket_Type, Client_Record, State}),
	State;

process_client_request(Client_Record, _, Send_Socket, Socket_Type, State) ->
	?PRINT("Not Handled Now ~n", []),
	#client_request{connection_type = Connection_Type} = Client_Record,
    #im_session_state{handle_packet_pid = Handle_Packet_PID} = State,
	socket:close(Socket_Type, Handle_Packet_PID, Connection_Type, Send_Socket),
	State.

handle_request([], Client_Record, Processed_Atleast_One_Record, Send_Socket, Socket_Type, State) ->
	#client_request{connection_type = Connection_Type} = Client_Record,
	#im_session_state{handle_packet_pid = Handle_Packet_PID} = State,
	if
		Processed_Atleast_One_Record == false ->
			socket:close(Socket_Type, Handle_Packet_PID, Connection_Type, Send_Socket);
		true ->
			nothing
	end,
	State;

handle_request([Request_Record|Next_Record], Client_Record, _, Send_Socket, Socket_Type, State) ->
	New_State= process_request([Request_Record|""], Client_Record, Send_Socket, Socket_Type, State),
	handle_request(Next_Record, Client_Record, true, Send_Socket, Socket_Type, New_State).


process_request([], Client_Record, Send_Socket, Socket_Type, State) ->
	#client_request{connection_type = Connection_Type} = Client_Record,
	#im_session_state{handle_packet_pid = Handle_Packet_PID} = State,
	socket:close(Socket_Type, Handle_Packet_PID, Connection_Type, Send_Socket),
	State;

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the contacts XML request.
%%% Usage - process_request(#contacts(), string(), string(), string(), string(), string(), integer(), socket(), atom(), string(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_request([{contacts, _}], Client_Record, Send_Socket, Socket_Type, State) ->
    #im_session_state{config_record = Config_Record, connection_map = Connection_Map, used_services = Used_Services} = State,
	Response = [{response, [{type, "success"}], []}], 
    #config_record{addr_book_url = Addr_Book_URL} = Config_Record,
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    get_contacts(Used_Services, Connection_Map, Addr_Book_URL),
    State;

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the login XML request
%%% Usage - process_request(#login(), string(), string(), string(), string(), string(), integer(), socket(), atom(), string(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_request([{login, {login, [Type], [Login_Name], [Pass], [Mode], _}}], Client_Record, Send_Socket, Socket_Type, State) when Type == "" orelse Login_Name == "" orelse Pass == "" orelse Mode == "" ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Parameters"]}],
	gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
	State;

process_request([{login, {login, IM_Type, Login_Name, Pass, Mode, _}}], Client_Record, Send_Socket, Socket_Type, State) when IM_Type == ["yah"] orelse IM_Type == ["aim"] orelse IM_Type == ["msn"] orelse IM_Type == ["icq"] orelse IM_Type == ["jab"] orelse IM_Type == ["wim"] orelse IM_Type == ["fbk"] ->
	#client_request{publisher_id = Publisher_ID, encoding = Encoding, remote_ip = Remote_IP} = Client_Record,
	#im_session_state{config_record = Config_Record, connection_map = Connection_Map, used_services = Used_Services, session_id = Session_ID} = State,
	Service = lists:flatten(IM_Type),
	Login = xmerl_ucs:to_utf8(lists:flatten(Login_Name)),
	Prv = Config_Record#config_record.prv,
	Mod = Config_Record#config_record.mod,
	Password_Encrypted = Config_Record#config_record.password_encrypted,
	if 
		Password_Encrypted == "yes" ->
			Decrypted_Password = rsa:decrypt(lists:flatten(Pass), Prv, Mod);
		true ->
			Decrypted_Password = lists:flatten(Pass)
	end,
	case dict:find(Service, Connection_Map) of
		{ok, Old_PID} ->
			gen_server:cast(Old_PID, kill_connection);
		_ ->
			nothing
	end,
	Modified_Connection_Map = dict:erase(Service, Connection_Map),
	Modified_Used_Services = lists:delete(Service, Used_Services),
	case Service of 
		"yah" ->
			Yahoo_Encryption_Server = Config_Record#config_record.yahoo_encryption_server,
			Yahoo_Encryption_Port = Config_Record#config_record.yahoo_encryption_port,
			File_Send_Directory = Config_Record#config_record.file_send_directory,
			File_Receive_Directory = Config_Record#config_record.file_receive_directory,
			case im_yahoo:start(Session_ID, self(), Yahoo_Encryption_Server, Yahoo_Encryption_Port, File_Send_Directory, File_Receive_Directory) of
				{ok, PID} ->
					case catch gen_server:call(PID, {create_connection, Login}, 60000) of
						{ok, Response} ->
							Conn_Map = dict:store("yah", PID, Modified_Connection_Map),
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}), 
							gen_server:call(PID, {login, Login, Decrypted_Password, lists:flatten(Mode)}, infinity),
							State#im_session_state{connection_map = Conn_Map, publisher_id = Publisher_ID, remote_ip = Remote_IP, used_services = str:append(Modified_Used_Services, ["yah"|""])};
						{error, Response} ->
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:cast(PID, kill_connection),
							gen_server:cast(self(), {remove_im, "yah", Login, true}),
							State;
						_ ->
							Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "yah"}, {code, "108"}, {login, Login}], ["Server Connection Failed"]}],
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:cast(PID, kill_connection),
							gen_server:cast(self(), {remove_im, "yah", Login, true}),
							State
					end;
				_ ->
					Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "yah"}, {code, "103"}, {login, Login}], ["Error in IM Server Component"]}],
					gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
					gen_server:cast(self(), {remove_im, "yah", Login, true}),
					State
			end;
		"aim" ->
			case im_aim:start(Session_ID, self()) of
				{ok, PID} ->
					case catch gen_server:call(PID, {create_connection, Login}, 30000) of
						{ok, Response} ->
							Conn_Map = dict:store("aim", PID, Modified_Connection_Map),
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:call(PID, {set_login_details, Login, Decrypted_Password, lists:flatten(Mode)}),
							State#im_session_state{connection_map = Conn_Map, publisher_id = Publisher_ID, remote_ip = Remote_IP, used_services = str:append(Modified_Used_Services, ["aim"|""])};
						{error, Response} ->
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:cast(PID, kill_connection),
							gen_server:cast(self(), {remove_im, "aim", Login, true}),
							State;
						_ ->
							Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "aim"}, {code, "108"}, {login, Login}], ["Server Connection Failed"]}],
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:cast(PID, kill_connection),
							gen_server:cast(self(), {remove_im, "aim", Login, true}),
							State
					end;
				_ ->
					Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "aim"}, {code, "103"}, {login, Login}], ["Error in IM Server Component"]}],
					gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
					gen_server:cast(self(), {remove_im, "aim", Login, true}),
					State
			end;
		"icq" ->
			case im_icq:start(Session_ID, self()) of
				{ok, PID} ->
					case catch gen_server:call(PID, {create_connection, Login, Decrypted_Password}, 120000) of
						{ok, Response} ->
							Conn_Map = dict:store("icq", PID, Modified_Connection_Map),
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:call(PID, {set_login_details, Login, Decrypted_Password, lists:flatten(Mode)}),
							State#im_session_state{connection_map = Conn_Map, publisher_id = Publisher_ID, remote_ip = Remote_IP, used_services = str:append(Modified_Used_Services, ["icq"|""])};
						{error, Response} ->
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:cast(PID, kill_connection),
							gen_server:cast(self(), {remove_im, "icq", Login, true}),
							State;
						_ ->
 							Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "icq"}, {code, "108"}, {login, Login}], ["Server Connection Failed"]}],
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:cast(PID, kill_connection),
							gen_server:cast(self(), {remove_im, "icq", Login, true}),
							State
					end;
				true ->
					Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "icq"}, {code, "103"}, {login, Login}], ["Error in IM Server Component"]}],
					gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
					gen_server:cast(self(), {remove_im, "icq", Login, true}),
					State
			end;
		"msn" ->
			case im_msn:start(self(),Config_Record#config_record.file_send_directory,Config_Record#config_record.file_receive_directory,State#im_session_state.msn_messageId + 2000,State#im_session_state.msn_sessionId + 2000) of
				{ok, PID} ->
					case catch gen_server:call(PID, {connect, Login, Decrypted_Password}, 60000) of
						{ok, Response} ->
							Conn_Map = dict:store("msn", PID, Modified_Connection_Map),
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							State#im_session_state{connection_map = Conn_Map, publisher_id = Publisher_ID, remote_ip = Remote_IP, used_services = str:append(Modified_Used_Services, ["msn"|""]),msn_messageId=State#im_session_state.msn_messageId + 2000,msn_sessionId = State#im_session_state.msn_sessionId + 2000};
						{fail, Response} ->
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:cast(PID, kill_connection),
							gen_server:cast(self(), {remove_im, "msn", Login, true}),
							State;
						_ ->
							Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "msn"}, {code, "108"}, {login, Login}], ["Server Connection Failed"]}],
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:cast(PID, kill_connection),
							gen_server:cast(self(), {remove_im, "msn", Login, true}),
							State
					end;
				_  ->
					Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "msn"}, {code, "103"}, {login, Login}], ["Error in IM Server Component"]}],
					gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
					gen_server:cast(self(), {remove_im, "msn", Login, true}),
					State
			end;
		"fbk" ->
			case im_facebook:start(self()) of
				{ok, PID} ->
					case catch gen_server:call(PID, {login, Login, Decrypted_Password}, 120000) of 
						{ok, Response} ->
							Conn_Map = dict:store("fbk", PID, Modified_Connection_Map),
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							State#im_session_state{connection_map = Conn_Map, publisher_id = Publisher_ID, remote_ip = Remote_IP, used_services = str:append(Modified_Used_Services, ["fbk"|""])};
						{error, Response} ->
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:cast(PID, kill_connection),
							gen_server:cast(self(), {remove_im, "fbk", Login, true}),
							State
					end;
				_ ->
					Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "fbk"}, {code, "103"}, {login, Login}], ["Error in IM Server Component"]}],
					gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
					gen_server:cast(self(), {remove_im, "fbk", Login, true}),
					State
			end;
		"wim" ->
			case find_login_host([], Login) of
				{"", _Domain} ->
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Username"]}],
					gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
					State;
				{_User, ""} ->
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Domain"]}],
					gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
					State;
				{User, Domain} ->
					case im_messenger:start(?WIM_SERVER, Domain, ?JABBER_RESOURCE, self(), State#im_session_state.box_pid, State#im_session_state.session_id, Encoding) of
						{ok, PID} ->
							Conn_Map = dict:store("wim", PID, Modified_Connection_Map),
							case gen_server:call(PID, {connect, lists:flatten(User), Decrypted_Password}, 60000) of
								{ok, Message} ->
									gen_server:cast(self(), {send_response, Message, Send_Socket, Socket_Type, Client_Record}),
									gen_server:cast(PID, {start_authenticating}),
									State#im_session_state{connection_map = Conn_Map, publisher_id = Publisher_ID, remote_ip = Remote_IP, used_services = str:append(Modified_Used_Services, ["wim"|""])};
								{fail, Message} ->
									gen_server:cast(self(), {send_response, Message, Send_Socket, Socket_Type, Client_Record}),
									gen_server:cast(PID, kill_connection),
									gen_server:cast(self(), {remove_im, "wim", Login, true}),
									State;
								_ ->
									Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "wim"}, {code, "108"}, {login, Login}], ["Server Connection Failed"]}],
									gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
									gen_server:cast(PID, kill_connection),
									gen_server:cast(self(), {remove_im, "wim", Login, true}),
									State
							end;
						_Error ->
							Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "wim"}, {code, "103"}, {login, Login}], ["Error in IM Server Component"]}],
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:cast(self(), {remove_im, "wim", Login, true}),
							State
					end
			end;
		"jab" ->
			case find_login_host([], Login) of
				{"", _Domain} ->
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Username"]}],
					gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
					State;
				{_User, ""} ->
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Domain"]}],
					gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
					State;
				{User, Domain} ->
					case im_jabber:start(?GTALK_SERVER, Domain, ?JABBER_RESOURCE, self()) of
						{ok, PID} ->
							Conn_Map = dict:store("jab", PID, Modified_Connection_Map),
							case gen_server:call(PID, {connect, lists:flatten(User), Decrypted_Password}, 60000) of
								{ok, Message} ->
									gen_server:cast(self(), {send_response, Message, Send_Socket, Socket_Type, Client_Record}),
									gen_server:cast(PID, {start_authenticating}),
									State#im_session_state{connection_map = Conn_Map, publisher_id = Publisher_ID, remote_ip = Remote_IP, used_services = str:append(Modified_Used_Services, ["jab"|""])};
								{fail, Message} ->
									gen_server:cast(self(), {send_response, Message, Send_Socket, Socket_Type, Client_Record}),
									gen_server:cast(PID, kill_connection),
									gen_server:cast(self(), {remove_im, "jab", Login, true}),
									State;
								_ ->
									Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "jab"}, {code, "108"}, {login, Login}], ["Server Connection Failed"]}],
									gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
									gen_server:cast(PID, kill_connection),
									gen_server:cast(self(), {remove_im, "jab", Login, true}),
									State
							end;
						_Error ->
							Response = [{response, [{type, "error"}, {errtype, "fatal"}, {im, "jab"}, {code, "103"}, {login, Login}], ["Error in IM Server Component"]}],
							gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
							gen_server:cast(self(), {remove_im, "jab", Login, true}),
							State
					end 
			end
	end;

process_request([{login, {login, _, _, _, _, _}}], Client_Record, Send_Socket, Socket_Type, State) ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["This Service Not Handled"]}],
	gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    State;

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the poll XML request
%%% Usage - process_request(#request(), string(), string(), string(), string(), string(), integer(), socket(), atom(), string(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_request([{request, {request, [Type], [Box_No], _}}], Client_Record, Send_Socket, Socket_Type, State) when Type == "" orelse Box_No == "" ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Parameter"]}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    State;

process_request([{request, {request, ["poll"], Box_No, _}}], Client_Record, Send_Socket, Socket_Type, State) ->
	#client_request{encoding = Encoding, connection_type = Connection_Type, callback = Handler, debug = Debug} = Client_Record,
	?PRINT("Handling Poll Request ~n", []),
	#im_session_state{handle_packet_pid = Handle_Packet_PID} = State,
	gen_server:cast(self(), {add_box_message_request, Send_Socket, list_to_integer(lists:flatten(Box_No)), Encoding, Socket_Type, Connection_Type, Handle_Packet_PID, Handler, Debug}),
	State;

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the typing XML request.
%%% Usage - process_request(#typing(), string(), string(), string(), string(), string(), integer(), socket(), atom(), string(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_request([{typing, {typing, [IM_Type], [Login], [Buddy_Name], [Type]}}], Client_Record, Send_Socket, Socket_Type, State) when IM_Type == "" orelse Login == "" orelse Buddy_Name == "" orelse Type == "" ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Parameter"]}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    State;

process_request([{typing, {typing, IM, _, Buddy_Name, Type}}], Client_Record, Send_Socket, Socket_Type, State) ->
    #im_session_state{connection_map = Connection_Map} = State,
	Name = xmerl_ucs:to_utf8(lists:flatten(Buddy_Name)),
	Service = lists:flatten(IM),
	case dict:find(Service, Connection_Map) of
    	{ok, PID} ->
        	gen_server:cast(PID, {send_typing_indication, lists:flatten(Name), lists:flatten(Type)}),
			Response = [{response, [{type, "success"}], []}], 
            gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record});
        error ->
			Response = [{response, [{type, "error"}, {errtype, "client"}], ["Typing indication send failure"]}],
            gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record})
    end,
	State;

%%%----------------------------------------------------------------------------------------------------
%%%   Description - This method is used to process the message XML request.
%%%   Usage - process_request(#message(), string(), string(), string(), string(), string(), integer(), socket(), atom(), string(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_request([{message, {message, [IM_Type], [Login], [Buddy_Name], _}}], Client_Record, Send_Socket, Socket_Type, State) when IM_Type == "" orelse Login == "" orelse Buddy_Name == "" ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Parameters"]}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    State;

process_request([{message, {message, IM, _, Buddy_Name, Msg}}], Client_Record, Send_Socket, Socket_Type, State) ->
    #im_session_state{connection_map = Connection_Map} = State,
	Service = lists:flatten(IM),
	Name = xmerl_ucs:to_utf8(lists:flatten(Buddy_Name)),
	A = lists:flatten(Msg),
	if 
		length(A) >= 38 ->
			B = element(2, regexp:gsub(lists:sublist(A, 1, 38), "&quot;", "'")),
			Message = str:append(B, lists:sublist(A, 39, length(A)));
		true ->
			Message = A
	end,
	case dict:find(Service, Connection_Map) of
       	{ok, PID} ->
            gen_server:cast(PID, {send_message, Name, ?MSG_CHAT, Message}),
			Response = [{response, [{type, "success"}], []}], 
            gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record});
        error ->
			Response = [{response, [{type, "error"}, {errtype, "client"}], ["Message Send Failure"]}],
            gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record})
    end,
	State;

process_request([{fbk_fun, {fbk_fun, [IM_Type], [Login], _, [Type]}}], Client_Record, Send_Socket, Socket_Type, State) when IM_Type == "" orelse Login == "" orelse Type == "" ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Parameters"]}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    State;

process_request([{fbk_fun, {fbk_fun, [IM_Type], _, [Buddy_Name], [Type]}}], Client_Record, Send_Socket, Socket_Type, State) when IM_Type == "fbk" ->
	#im_session_state{connection_map = Connection_Map} = State,
	case dict:find(IM_Type, Connection_Map) of 
		{ok, PID} ->
			case Type of 
				"notification" ->
					gen_server:cast(PID, get_notification),
					Response = [{response, [{type, "success"}], []}];
				"livefeed" ->
					gen_server:cast(PID, get_livefeed),
					Response = [{response, [{type, "success"}], []}];
				"inbox" ->
					gen_server:cast(PID, get_mails),
					Response = [{response, [{type, "success"}], []}];
				"wallfeed" ->
					gen_server:cast(PID, {get_wall_feeds, Buddy_Name}),
					Response = [{response, [{type, "success"}], []}];
				"chathistory" ->
					gen_server:cast(PID, {get_chat_history, Buddy_Name}),
					Response = [{response, [{type, "success"}], []}];
				"poke" ->
					if
						Buddy_Name /= "" ->
							gen_server:cast(PID, {send_poke, Buddy_Name}),
							Response = [{response, [{type, "success"}], []}];
						true ->
							Response = [{response, [{type, "error"}, {errtype, "client"}], ["Poke Send Failure"]}]
					end;
				_ ->
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["Unknown Message Type"]}]
			end,
            gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record});
        error ->
			Response = [{response, [{type, "error"}, {errtype, "client"}], ["Message Send Failure"]}],
            gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record})
    end,
	State;

%begin conference
%Handling Conference Record
% check the semantics of conf records
% add the conference record if required
% seperate the record using service and send them to their corresponding service pids

%[{conference_message,["lakshmi@hotmail.com"],["msn"],["lakshmi123"],["message"],["Hello are u parsing it well...so on"]}]

process_request([{conference, {conference, [IM_Type], [Login], [Conf_ID], [Code], _, _}}], Client_Record, Send_Socket, Socket_Type, State) when IM_Type == "" orelse Login == "" orelse Conf_ID == "" orelse Code == "" ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Parameters"]}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    State;

process_request([{conference, [HostName], [HostService], [ConfId], ["message"], Msg}], Client_Record, Send_Socket, Socket_Type, State) ->
	%% find the conference details and cast the message to all service pids	
    A = lists:flatten(Msg),
    if
        length(A) >= 38 ->
            B = element(2, regexp:gsub(lists:sublist(A, 1, 38), "&quot;", "'")),
            Message = str:append(B, lists:sublist(A, 39, length(A)));
        true ->
            Message = A
    end,
	case lists:keysearch(ConfId,1,State#im_session_state.conference_details_list) of
	{value,{ConferenceId,HostName,HostService,ServicesList}}	->
		io:format("...............process_request() - ~n~p~n",[{ConferenceId,HostName,HostService,ServicesList}]),
		Response = [{response, [{type, "success"}], []}],
		cast_message_to_all_services(ServicesList, ConferenceId, Message, Client_Record, Send_Socket, Socket_Type, State);
		%%({conference,[IM],[Login],[ConferenceID],[Operation],Message,BuddyList}
	false	->
		Response = [{response, [{type, "error"}, {errtype, "nonfatal"}], ["No Conference exists with this Id"]}]
	end,
	gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
	State;

process_request([{conference, [HostName], [HostService], [ConfId], [Operation], ConfServiceDetails}], Client_Record, Send_Socket, Socket_Type, State) ->
    #im_session_state{connection_map = Connection_Map} = State,
	case Operation of	
		"initiate"	->
			io:format("im_session: into Iniate conference clause ConfServiceDetails = ~p ~n",[ConfServiceDetails]),
			%% Generate conference Id, add conf_details = [{id,hostname,hostservice,servicesList}],
			%% Cast this information to all services existing in serviceList
			ConferenceId	= State#im_session_state.conference_id + 1,
			%% NewConferenceId = "conference" ++ integer_to_list(ConferenceId),
			NewConferenceId = string:sub_string(os:cmd("uuid -F STR"),1,36),
			ServicesList = cast_initiate_request_to_all_service_pids(ConfServiceDetails,NewConferenceId, Client_Record,Send_Socket,Socket_Type,State),
			io:format("im_session: sent request to all the services ~n"),
			Conference_Details_List = State#im_session_state.conference_details_list,
			NewConference_Details_List = [{NewConferenceId,HostName,HostService,ServicesList} | Conference_Details_List],
			Response = [{response, [{type, "success"}], []}],
			NewStateData= State#im_session_state{conference_id=ConferenceId,conference_details_list=NewConference_Details_List};
		"invite"	->
			io:format("im_session: into Invite conference clause ConfServiceDetails= ~p ~n",[ConfServiceDetails]),
			case lists:keysearch(ConfId,1,State#im_session_state.conference_details_list) of
			{value,{NewConferenceId,NewHostName,NewHostService,ServicesList}}	->
				NewServicesList = cast_invite_request_to_all_service_pids(ConfServiceDetails,NewConferenceId,ServicesList, Client_Record,Send_Socket,Socket_Type,State),
				ConfServiceDetailsList = State#im_session_state.conference_details_list,
				Temp	= lists:delete({NewConferenceId,NewHostName,NewHostService,ServicesList},ConfServiceDetailsList),
				NewConference_Details_List = [{NewConferenceId,NewHostName,NewHostService,NewServicesList} | Temp],
				Response = [{response, [{type, "success"}], []}],
				NewStateData = State#im_session_state{conference_details_list = NewConference_Details_List};
			false	->
				if length(ConfId) == 36 ->
					Response = [{response, [{type, "success"}], []}],
					ServicesList = cast_initiate_request_to_all_service_pids(ConfServiceDetails, ConfId, Client_Record,Send_Socket,Socket_Type,State),
					NewConference_Details_List = [{ConfId, HostName, HostService, ServicesList} | State#im_session_state.conference_details_list],
					NewStateData = State#im_session_state{conference_details_list = NewConference_Details_List};
				true ->
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["Conference: No such conf exists"]}],
					NewStateData = State
				end
			end;
		"leaveeeeeeeeeeeeee"		->%or exit?
			io:format("im_session:  Entering into conference leave clause ConfServiceDetails = ~p ~n",[ConfServiceDetails]),
			case lists:keysearch(ConfId,1,State#im_session_state.conference_details_list) of
			{value,{NewConferenceId,NewHostName,NewHostService,ServicesList}}	->
				ConfServiceDetailsList = State#im_session_state.conference_details_list,
				Temp	= lists:delete({NewConferenceId,NewHostName,NewHostService,ServicesList},ConfServiceDetailsList),
				Length  = lists:flatlength(ConfServiceDetails),
				if
				Length == 1 ->
					[{[ConfDService],[_ConfDServiceLogin],_ConfDList}] = ConfServiceDetails,
					io:format("entered if clause Length = 1 ConfDService = ~p ~n ServicesList = ~p ~n",[ConfDService, ServicesList]),
					case lists:keysearch(ConfDService,1,ServicesList) of
					{value,{ServiceID,ServiceLogin,Count,Members}} ->
						io:format("cast to the remaining services saying Members of a Service are leaving the conference ~n"),
						case dict:find(ServiceID, Connection_Map) of
						{ok,Service_PID} ->
							gen_server:cast(Service_PID,{conference,[ServiceID],[ServiceLogin],[NewConferenceId],["leave"],[],Members});
						_->
							io:format(" leave clause 000 ~n"),
							nothing
						end,
						case lists:delete({ServiceID,ServiceLogin,Count,Members},ServicesList) of
						[] ->
							NewConference_Details_List = Temp;
						NewServicesList ->
							NewConference_Details_List = [{NewConferenceId,HostName,HostService,NewServicesList} | Temp],
							%% cast the leave messge to remaining service buddies in conference
							TempMessage1 = io_lib:format("&gt;All the following ~s buddies left conference/conversation...~p ",[NewHostService,Members]),
							TempMessage2 = ["&lt;font color=","\"#000000","\"",TempMessage1,"&lt;/font","&gt;"],
							A = lists:flatten(TempMessage2),
							B = element(2, regexp:gsub(lists:sublist(A, 1, 38), "&quot;", "'")),
							LeaveMessage = str:append(B, lists:sublist(A, 39, length(A))),
							cast_message_to_all_services(NewServicesList,ConfId,LeaveMessage, Client_Record, Send_Socket, Socket_Type, State)
						end,
						NewStateData = State#im_session_state{conference_details_list = NewConference_Details_List},
						Response = [{response, [{type, "success"}], []}];
					false ->
						io:format(" leave clause 111 ~n"),
						NewStateData = State,
						Response = [{response, [{type, "error"}, {errtype, "client"}], ["Conference " ++ ConfId ++ " does not have this " ++ ConfDService ++ " service buddies"]}]
					end;
				true ->% ifs else part
					io:format(" leave clause 222 ~n"),
					NewStateData = State,
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["More than one service in leave op"]}]
				end;				
			false	->
				NewStateData = State,
				Response = [{response, [{type, "error"}, {errtype, "client"}], ["No conference exists with this ID"]}]
			end;
		"leave" -> %"exit"	->
			io:format("im_session: cast leave message to all the services in that conference ~n"),
			ConfServiceDetailsList = State#im_session_state.conference_details_list,
			case lists:keysearch(ConfId, 1, ConfServiceDetailsList) of
			{value,{NewConferenceId,HostName,HostService,ServicesList}}	->
				cast_leave_operation_to_all_services(ServicesList,NewConferenceId,Connection_Map),
				Temp = lists:delete({NewConferenceId,HostName,HostService,ServicesList},ConfServiceDetailsList),
				NewStateData = State#im_session_state{conference_details_list = Temp},
				Response = [{response, [{type, "success"}], []}];
			false	->
				NewStateData = State,
				Response = [{response, [{type, "error"}, {errtype, "client"}], ["No Such conference exists to Close"]}]
			end;
		"accept"	->
			io:format("im_session:  Entering into conference accept clause ConfServiceDetails = ~p ~n",[ConfServiceDetails]),
			case dict:find(HostService,Connection_Map) of
				{ok,Service_PID} ->
					case ConfServiceDetails of
						[{_IM,_Login,BuddyList}] -> 
							Response = [{response, [{type, "success"}], []}],
							gen_server:cast(Service_PID,{conference,[HostService],[HostName],[ConfId],[Operation],[],BuddyList}),
							%% add the conf record in conference_details_list
							Temp = State#im_session_state.conference_details_list,
							NewConference_Details_List = [{ConfId,HostName,HostService,[{HostService,HostName,0,[]}]} | Temp],
							NewStateData = State#im_session_state{conference_details_list=NewConference_Details_List};
						_->
							NewStateData = State,
							Response = [{response, [{type, "error"}, {errtype, "client"}], ["Conference: syntax error"]}]
					end;			
				error	->
					NewStateData = State,
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["Service " ++ HostService ++ " is not logged in"]}]
			end;
		"reject"	->
			io:format("im_session: Entered into conference reject clause ~n"),
			case dict:find(HostService,Connection_Map) of
				{ok,Service_PID} ->
					case ConfServiceDetails of
						[{_IM,_Login,BuddyList}] -> 
							Response = [{response, [{type, "success"}], []}],
							gen_server:cast(Service_PID,{conference,[HostService],[HostName],[ConfId],[Operation],[],BuddyList});
						_->
							Response = [{response, [{type, "error"}, {errtype, "client"}], ["Conference: syntax error"]}]
					end;
				error	->
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["Service " ++ HostService ++ " is not logged in"]}]
			end,
			NewStateData = State;
		_->	
			Response = [{response, [{type, "error"}, {errtype, "client"}], ["Unknown CONF Operation"]}],
			NewStateData = State
	end,
	gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
	NewStateData;

process_request([{conference, {conference, IM, Login, ConferenceID, ["initiate"], Msg, BuddyList}}], Client_Record, Send_Socket, Socket_Type, State) ->
    #im_session_state{connection_map = Connection_Map} = State,
	Service = lists:flatten(IM),
	%Name = xmerl_ucs:to_utf8(lists:flatten(Buddy_Name)),
	A = lists:flatten(Msg),
	if 
		length(A) >= 38 ->
			B = element(2, regexp:gsub(lists:sublist(A, 1, 38), "&quot;", "'")),
			Message = str:append(B, lists:sublist(A, 39, length(A)));
		true ->
			Message = A
	end,
	Message,
	case dict:find(Service, Connection_Map) of
		{ok,Service_PID} ->
			gen_server:cast(Service_PID,{conference, IM, Login, ConferenceID, ["initiate"], Message, BuddyList}),
			?PRINT("im_session: initiate conference packet Sending Conference Packet to corresponding service buddy ~n", []),
			Response = [{response, [{type, "success"}], []}],
			gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record});
		_-> 
			Response = [{response, [{type, "error"}, {errtype, "client"}], ["Conference: Communication Failure"]}],
			gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record})
	end,
	State;

process_request([{conference, {conference, IM, Login, ConferenceID, Operation, Msg, BuddyList}}], Client_Record, Send_Socket, Socket_Type, State) ->
    #im_session_state{connection_map = Connection_Map} = State,
	Service = lists:flatten(IM),
	%%Name = xmerl_ucs:to_utf8(lists:flatten(Buddy_Name)),
	A = lists:flatten(Msg),
	if 
		length(A) >= 38 ->
			B = element(2, regexp:gsub(lists:sublist(A, 1, 38), "&quot;", "'")),
			Message = str:append(B, lists:sublist(A, 39, length(A)));
		true ->
			Message = A
	end,
	Message,
	?PRINT("Sending Conference Packet to corresponding service buddy ~n", []),
	case dict:find(Service, Connection_Map) of
		{ok,Service_PID} ->
			gen_server:cast(Service_PID,{conference, IM, Login, ConferenceID, Operation, Message, BuddyList}),
			Response = [{response, [{type, "success"}], []}],
			gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record});
		_-> 
			Response = [{response, [{type, "error"}, {errtype, "client"}], ["Conference: Communication Failure"]}],
			gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record})
	end,
	State;

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the status XML request.
%%% Usage - process_request(#message(), string(), string(), string(), string(), string(), integer(), socket(), atom(), string(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_request([{status, {status, [Code], [Message]}}], Client_Record, Send_Socket, Socket_Type, State) when Code == "" orelse Message == "" ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Parameters"]}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    State;

process_request([{status, {status, Code, Message}}], Client_Record, Send_Socket, Socket_Type, State) ->
	gen_server:cast(self(), {set_status, list_to_integer(lists:flatten(Code)), lists:flatten(Message)}),
	Response = [{response, [{type, "success"}], []}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
	State;

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the friendship XML request which allows to add, remove
%%%	and block a contact.
%%% Usage - process_request(#message(), string(), string(), string(), string(), string(), integer(), socket(), atom(), string(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_request([{friendship, {friendship, [IM_Type], [Login], [Name], _, [Type], _}}], Client_Record, Send_Socket, Socket_Type, State) when IM_Type == "" orelse Login == "" orelse Name == "" orelse Type == "" ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Parameters"]}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    State;

process_request([{friendship, {friendship, IM, Login, Name, [""], Type, Message}}], Client_Record, Send_Socket, Socket_Type, State) ->
	handle_friendship(lists:flatten(IM), lists:flatten(Login), lists:flatten(Name), "Friends", lists:flatten(Type), lists:flatten(Message), Client_Record, Send_Socket, Socket_Type, State),
	State;

process_request([{friendship, {friendship, IM, Login, Name, Group, Type, Message}}], Client_Record, Send_Socket, Socket_Type, State) ->
    handle_friendship(lists:flatten(IM), lists:flatten(Login), lists:flatten(Name), lists:flatten(Group), lists:flatten(Type), lists:flatten(Message), Client_Record, Send_Socket, Socket_Type, State),
    State;

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the group XML request which is used to rename, remove
%%%	and add a group. Also it allows to move a contact from one group to another.
%%% Usage - process_request(#message(), string(), string(), string(), string(), string(), integer(), socket(), atom(), string(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_request([{group, {group, [IM_Type], [Login], _, _, _}}], Client_Record, Send_Socket, Socket_Type, State) when IM_Type == "" orelse Login == "" ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Parameters"]}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    State;

process_request([{group, {group, IM, _Login, _Type, _Old_Group_Name, _Contact, _New_Group_Name}}], Client_Record, Send_Socket, Socket_Type, State) ->
    #im_session_state{connection_map = Connection_Map, used_services = Used_Services} = State,
	Type = lists:flatten(_Type),
	Contact = xmerl_ucs:to_utf8(lists:flatten(_Contact)),	
	Old_Group_Name = xmerl_ucs:to_utf8(lists:flatten(_Old_Group_Name)),
	New_Group_Name = xmerl_ucs:to_utf8(lists:flatten(_New_Group_Name)),
    Service = lists:flatten(IM),
	case Type of 
	    "rename" ->
			rename_group(Used_Services, Connection_Map, Old_Group_Name, New_Group_Name),
			Response = [{response, [{type, "success"}], []}],
            gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record});
		"remove" ->
			remove_group(Used_Services, Connection_Map, Old_Group_Name),
			Response = [{response, [{type, "success"}], []}],
            gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record});
		"add" ->
			case dict:find(Service, Connection_Map) of
		        {ok, IM_PID} ->
		            gen_server:cast(IM_PID, {add_group, Old_Group_Name}),
					Response = [{response, [{type, "success"}], []}],
		            gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record});
        		error ->
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["Add Group Request Failed"]}],
		            gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record})	
		    end;
		"movecontact" ->
			case dict:find(Service, Connection_Map) of
                {ok, IM_PID} ->
					gen_server:cast(IM_PID, {move_contact, Contact, Old_Group_Name, New_Group_Name}),
					Response = [{response, [{type, "success"}], []}],
                    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record});
                error ->
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["Move Contact Request Failed"]}],
                    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record})
            end;
		_ ->
			Response = [{response, [{type, "error"}, {errtype, "client"}], ["Group Request Failed"]}],
            gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record})
	end,
	State;

process_request([{file, {file, [IM_Type], [Login], [Name], [File_Name], _, _, [Type]}}], Client_Record, Send_Socket, Socket_Type, State) when IM_Type == "" orelse Login == "" orelse Name == "" orelse File_Name == "" orelse Type == "" ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Parameters"]}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    State;

process_request([{file, {file, IM, _Login, Name, _File_Name, _, _Key, _Type}}], Client_Record, Send_Socket, Socket_Type, State) ->
	#im_session_state{config_record = Config_Record, connection_map = Connection_Map} = State,
	#config_record{file_send_directory = File_Send_Directory, file_receive_directory = File_Receive_Directory} = Config_Record,
    Service = lists:flatten(IM),
	Buddy_Name = xmerl_ucs:to_utf8(lists:flatten(Name)),
	File_Name = lists:flatten(_File_Name),
	Type = lists:flatten(_Type),
	Key = lists:flatten(_Key),
	case dict:find(Service, Connection_Map) of 
	{ok, IM_PID} ->
			case Type of
				"send" ->
					io:format("im_session: cast {send_file, ~s, ~s, ~s, ~s }~n ~n",[Buddy_Name,File_Send_Directory,File_Name,key]),
					gen_server:cast(IM_PID, {send_file, Buddy_Name, File_Send_Directory, File_Name,Key}),%no need for Key
					Response = [{response, [{type, "success"}], []}];
				"accept" ->
					gen_server:cast(IM_PID, {accept_file, Buddy_Name, File_Receive_Directory, File_Name, Key}),
					Response = [{response, [{type, "success"}], []}];
				"deny" ->
					gen_server:cast(IM_PID,{deny_file, Buddy_Name, File_Receive_Directory, File_Name, Key}),
					Response = [{response, [{type, "success"}], []}];
				_ ->
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["File Transfer Failed"]}]
			end;
		error ->
			Response = [{response, [{type, "error"}, {errtype, "client"}], ["File Transfer Failed"]}]
	end,
	gen_server:cast(self(),{send_response, Response, Send_Socket, Socket_Type, Client_Record}),
	State;

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the referral XML request.
%%% Usage - process_request(#message(), string(), string(), string(), string(), string(), integer(), socket(), atom(), string(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_request([{referral, {referral, [Refer_URL], [URLToBeSent], [Customer], [Private], [{message, Message} | Buddies ]}}], Client_Record, Send_Socket, Socket_Type, State) ->
	#client_request{publisher_id = Publisher_ID, remote_host = Remote_Host, remote_ip = Remote_IP, referer = Referer} = Client_Record,
    Progress_Rate = 100 / length(Buddies),
	Response = [{referral, [{progress, "0"}], []}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    gen_server:cast(self(), {send_referral, Buddies, Message, URLToBeSent, Customer, Remote_IP, Remote_Host, Refer_URL, Private, Publisher_ID, Referer}),
    State#im_session_state{progress = 0, progress_rate = Progress_Rate};

%%%----------------------------------------------------------------------------------------------------
%%% Description - This method is used to process the logout XML request.
%%% Usage - process_request(#message(), string(), string(), string(), string(), string(), integer(), socket(), atom(), string(), #im_session_state())
%%%----------------------------------------------------------------------------------------------------
process_request([{logout, {logout, [IM_Type], _}}], Client_Record, Send_Socket, Socket_Type, State) when IM_Type == "" ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["Missing Parameters"]}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    State;

process_request([{logout, {logout, IM, Login_Name}}], Client_Record, Send_Socket, Socket_Type, State) ->
    #im_session_state{connection_map = Connection_Map, used_services = Used_Services} = State,
    Service = lists:flatten(IM),	
	Login = xmerl_ucs:to_utf8(lists:flatten(Login_Name)),
	Response = [{response, [{type, "success"}], []}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
	if
		Service == "all" ->
			handle_logout(Used_Services, "", Connection_Map),
			State;
		true ->
			handle_logout([Service|""], Login, Connection_Map),
			NewConference_Details_List = handle_conference_logout(Service, State#im_session_state.conference_details_list),
			State#im_session_state{conference_details_list = NewConference_Details_List}
	end;

process_request(_, Client_Record, Send_Socket, Socket_Type, State) ->
	Response = [{response, [{type, "error"}, {errtype, "client"}], ["Invalid Message"]}],
    gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
    State.

handle_logout([], _, _) ->
	nothing;

handle_logout([IM_Type|B], Login, Connection_Map) ->
	if 
		IM_Type == "yah" orelse IM_Type == "aim" orelse IM_Type == "icq" orelse IM_Type == "fbk" ->
			case dict:find(IM_Type, Connection_Map) of
				{ok, PID} ->
					gen_server:call(PID, logout, infinity);
				error ->
					nothing
			end,
			gen_server:cast(self(), {remove_im, IM_Type, Login, false});
		IM_Type == "jab" orelse IM_Type == "wim" ->
			case dict:find(IM_Type, Connection_Map) of
				{ok, PID} ->
					gen_server:cast(PID, logout);
				error ->
					nothing
			end,
			gen_server:cast(self(), {remove_im, IM_Type, Login, false});
		IM_Type == "msn" ->
			case dict:find(IM_Type, Connection_Map) of
                {ok, PID} ->
                    gen_server:cast(PID, disconnect);
                error ->
                    nothing
            end,
            gen_server:cast(self(), {remove_im, "msn", Login, false});
		true ->
			nothing
	end,
	handle_logout(B, Login, Connection_Map).

handle_friendship(Service, _, Buddy_Name, Group_Name, Type, Message, Client_Record, Send_Socket, Socket_Type, State) ->
	?PRINT("Inside Handle Friendship ~n", []),
    #im_session_state{connection_map = Connection_Map} = State,
	Group = xmerl_ucs:to_utf8(Group_Name),
    Name = xmerl_ucs:to_utf8(Buddy_Name),

	case dict:find(Service, Connection_Map) of
		{ok, PID} ->
			case Type of
				"remove" ->
					gen_server:cast(PID, {remove_buddy, Name, Group}),
					Response = [{response, [{type, "success"}], []}];
				"block" ->
					gen_server:cast(PID, {block_buddy, Name, Group}),
					Response = [{response, [{type, "success"}], []}];
				"unblock" ->
					gen_server:cast(PID, {unblock_buddy, Name}),
					Response = [{response, [{type, "success"}], []}];
				"authorize" ->
					gen_server:cast(PID, {authorize_buddy_request, Name, Group}),
					Response = [{response, [{type, "success"}], []}];
				"deny" ->
					gen_server:cast(PID, {deny_buddy_request, Name}),
					Response = [{response, [{type, "success"}], []}];
				"add" ->
					if 
						Service == "yah" ->
							Return = gen_server:call(PID, {check_block_list, {Name}}, infinity),
                            if
                                Return == false ->
                                    gen_server:cast(PID, {add_buddy, Name, Group, Message, true}),
									Response = [{response, [{type, "success"}], []}];
                                true ->
									Response = [{response, [{type, "error"}, {errtype, "client"}], ["Frienship Request Failure"]}]
                            end;
						Service == "msn" orelse Service == "jab" ->
							gen_server:cast(PID, {add_buddy, Name, Group}),
							Response = [{response, [{type, "success"}], []}];
						Service == "aim" orelse Service == "icq" ->
							Return = gen_server:call(PID, {check_block_list, Name}, infinity),
                            if
                                Return == false ->
                                    gen_server:cast(PID, {add_buddy, Name, Group}),
									Response = [{response, [{type, "success"}], []}];
                                true ->
									Response = [{response, [{type, "error"}, {errtype, "client"}], ["Frienship Request Failure"]}]
                            end;
						true ->
							Response = [{response, [{type, "error"}, {errtype, "client"}], ["Frienship Request Failure"]}]
					end;
				_ ->
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["Frienship Request Failure"]}]
			end;
		_ ->
			Response = [{response, [{type, "error"}, {errtype, "client"}], ["Frienship Request Failure"]}]
	end,
	gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}).

find_login_host(A, []) ->
    {A, ""};

find_login_host(A, [B|C]) ->
    if
        B == "@" orelse B == 64 ->
            {A, C};
        true ->
            D = [B|""],
            find_login_host(str:append(A, D), C)
    end.

send_referral({buddies, [Service], [From], [To]}, MessageList, URLToBeSent, Customer, Remote_IP, Remote_Host, Refer_URL, Private, _, Referer) ->
    [LastMessage | TailMessage] = lists:reverse(MessageList),
    {N1, N2, N3} = now(),
    Ticket = integer_to_list(N1) ++ integer_to_list(N2) ++ integer_to_list(N3),
	ReferralMesg = io_lib:format("~s%0A~s", [LastMessage, URLToBeSent ++ Ticket]),
    case Service of
    	"jab"->
	        Msg = lists:flatten(["&lt;font color='#000000'&gt;", lists:reverse(TailMessage), ReferralMesg, "&lt;/font&gt;"]);
		"msn" -> 
			Msg = lists:flatten(["&lt;font color='#000000'&gt;", lists:reverse(TailMessage), ReferralMesg, "&lt;/font&gt;"]);
		_ ->
	        Msg = lists:flatten([lists:reverse(TailMessage), ReferralMesg])
    end,
	Query = io_lib:format("call add_referral('~s', '~s', '~s', '~s', '~s', '~s', '~s', '~s', '~s', '~s');", [Ticket, Customer, Remote_IP, Remote_Host, From, To, Service, Refer_URL, Private, Referer]),
	case gen_event:call(db_manager, db_referral, {add_referral, Query}, infinity) of
	    ok ->
			{ok, Msg};
        _ ->
			error
    end;

send_referral(_, _, _, _, _, _, _, _, _, _) ->
	"&lt;font color='#000000'&gt;&lt;/font&gt;".

%% Intermediate Function for Timer
call_cast(Request, BuddyTail, Message, URLToBeSent, Customer, Remote_IP, Remote_Host, Refer_URL, Private, Publisher_ID, Referer, ProcessID) ->
	gen_server:cast(ProcessID, {Request, BuddyTail, Message, URLToBeSent, Customer, Remote_IP, Remote_Host, Refer_URL, Private, Publisher_ID, Referer}).


%----------------------------------------------------------------------------------------------------
%   Description - This method is used to determine whether a string is in unicode format.
%----------------------------------------------------------------------------------------------------
is_unicode([]) ->
    false;

is_unicode([A|B]) ->
	if
		A > 255 ->
			true;
	    true ->
	        is_unicode(B)
	end.
	
rename_group([], _, _, _) ->
	ok;

rename_group([A|B], Connection_Map, Old_Group_Name, New_Group_Name) ->
	case dict:find(A, Connection_Map) of
	    {ok, IM_PID} ->
			gen_server:cast(IM_PID, {rename_group, Old_Group_Name, New_Group_Name});
		error ->
			nothing
	end,
	rename_group(B, Connection_Map, Old_Group_Name, New_Group_Name).

remove_group([], _, _) ->
	ok;

remove_group([A|B], Connection_Map, Group_Name) ->
    case dict:find(A, Connection_Map) of
        {ok, IM_PID} ->
            gen_server:cast(IM_PID, {remove_group, Group_Name});
        error ->
            nothing
    end,	
	remove_group(B, Connection_Map, Group_Name).

get_contacts([], _, _) ->
        ok;

get_contacts([A|B], Connection_Map, Addr_Book_URL) ->
	case dict:find(A, Connection_Map) of
	    {ok, IM_PID} ->
	        gen_server:cast(IM_PID, {get_contacts, Addr_Book_URL});
        error ->
            nothing
    end,
    get_contacts(B, Connection_Map, Addr_Book_URL).

kill_child_process(State) ->
	#im_session_state{session_id = Session_ID, connection_map = Connection_Map, used_services = Used_Services, remote_ip = Remote_IP, publisher_id = Publisher_ID} = State,
    if
        length(Used_Services) == 0 ->
			nothing;
        true ->
            [IM_Type|_] = Used_Services,
            case dict:find(IM_Type, Connection_Map) of
                {ok, IM_PID} ->
                    gen_server:call(IM_PID, {add_update_db, Remote_IP, Publisher_ID, "0", Session_ID}, infinity),
                    New_Connection_Map = dict:erase(IM_Type, Connection_Map),
                    New_Used_Services = lists:delete(IM_Type, Used_Services),
                    gen_server:cast(IM_PID, kill_connection);
                error ->
                    New_Connection_Map = Connection_Map,
                    New_Used_Services = lists:delete(IM_Type, Used_Services)
            end,
            kill_child_process(State#im_session_state{connection_map = New_Connection_Map, used_services = New_Used_Services})
    end.

commit_suicide(State) ->
    #im_session_state{session_id = Session_ID, connection_map = Connection_Map, used_services = Used_Services, remote_ip = Remote_IP, publisher_id = Publisher_ID} = State,
    if
        length(Used_Services) == 0 ->
            gen_server:cast(self(), {commit_suicide, State});
        true ->
            [IM_Type|_] = Used_Services,
            case dict:find(IM_Type, Connection_Map) of
                {ok, IM_PID} ->
					gen_server:call(IM_PID, {add_update_db, Remote_IP, Publisher_ID, "0", Session_ID}, infinity),
                    New_Connection_Map = dict:erase(IM_Type, Connection_Map),
                    New_Used_Services = lists:delete(IM_Type, Used_Services),
                    gen_server:cast(IM_PID, kill_connection);
                error ->
                    New_Connection_Map = Connection_Map,
                    New_Used_Services = lists:delete(IM_Type, Used_Services)
            end,
            commit_suicide(State#im_session_state{connection_map = New_Connection_Map, used_services = New_Used_Services})
    end.

get_conference_details_list([]) ->
	[];

get_conference_details_list([{ConferenceId, HostName, HostService, ServicesList} | Rest]) ->
	ServicesString = get_conf_service_wide_list(ServicesList),
	Conf_Details = [{conf, [{hostname, HostName}, {hostservice, HostService}, {id, ConferenceId}, {operation, "refresh"}], ServicesString}],
	Conf_Details ++ get_conference_details_list(Rest).

get_conf_service_wide_list([])->
	[];

get_conf_service_wide_list([ {Service, Login, _Count, BuddyList} | REST]) ->
	BuddyListString = get_conf_buddy_list(Service, Login, BuddyList),
	BuddyListString ++ get_conf_service_wide_list(REST).

get_conf_buddy_list(_Service, _Login, []) ->
	[];

get_conf_buddy_list(Service, Login, [Buddy | Rest]) ->
	String = [{conference, [{im, Service}, {login, Login}, {service, Service}, {name, Buddy}], []}],
	String ++ get_conf_buddy_list(Service, Login, Rest).

cast_leave_operation_to_all_services([{Service,Login,_Count,_Members} | ServicesList],ConfId,Connection_Map) ->
	case dict:find(Service,Connection_Map) of
		{ok,Service_PID}	->
			gen_server:cast(Service_PID,{conference,[Service],[Login],[ConfId],["leave"],[],[]});
		error	->
			io:format("im_session: %%%%%%%% Service PID is missing Is he logged out already ~n ")
	end,
	cast_leave_operation_to_all_services(ServicesList,ConfId,Connection_Map);

cast_leave_operation_to_all_services([],_ConfId,_Connection_Map)	->
	ok.

cast_message_to_all_services([ Head | Rest], ConferenceId, Message, Client_Record, Send_Socket, Socket_Type, State) ->
	{IM,IMLogin,Count,_BuddyList} = Head,
	#im_session_state{connection_map = Connection_Map} = State,
	if
		Count > 0 	->
			case dict:find(IM, Connection_Map) of
				{ok,Service_PID} ->
					io:format("im_session: Sending message packet to corresponding im_~s ~n", [IM]),
					gen_server:cast(Service_PID,{conference,[IM],[IMLogin],[ConferenceId],["message"],Message,[]});
				_->
					Response = [{response, [{type, "error"}, {errtype, "client"}], ["Conference:" ++ IM ++ " Service not logged in "]}],
					gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record})
			end;
		true ->	
			ok
	end,
	cast_message_to_all_services(Rest,ConferenceId,Message, Client_Record,Send_Socket,Socket_Type,State);

cast_message_to_all_services([],_ConferenceId,_Message,_Config_Record, _Send_Socket, _Socket_Type, _State) ->
	success.

cast_initiate_request_to_all_service_pids([ConfServiceDetails | Rest],NewConferenceId,Client_Record, Send_Socket,Socket_Type,State) ->
    #im_session_state{connection_map = Connection_Map} = State,
	{[IM],[Login],BuddyList} = ConfServiceDetails,
	case dict:find(IM, Connection_Map) of
	{ok,Service_PID} ->
		gen_server:cast(Service_PID,{conference,[IM],[Login],[NewConferenceId],["initiate"],[],BuddyList}),
		?PRINT("im_session: Sending initiate conference packet to corresponding service buddy ~n", []);
	_-> 
		Response = [{response, [{type, "error"}, {errtype, "client"}], ["Conference: No user logged in with this " ++ IM ++ " service "]}],
		gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record})
	end,
	[{IM,Login,0,[]} | cast_initiate_request_to_all_service_pids(Rest,NewConferenceId, Client_Record,Send_Socket,Socket_Type,State)];

cast_initiate_request_to_all_service_pids([],_NewConferenceId,_Client_Recod,_Send_Socket,_Socket_Type,_State) ->
	io:format("empty confdetails~n"),
	[].

cast_invite_request_to_all_service_pids([ConfServiceDetails | Rest],NewConferenceId,ServicesList,Client_Record, Send_Socket,Socket_Type,State) ->
	#im_session_state{connection_map = Connection_Map} = State,
	{[IM],[Login],BuddyList} = ConfServiceDetails,
	case dict:find(IM, Connection_Map) of
		{ok,Service_PID} ->
			gen_server:cast(Service_PID,{conference,[IM],[Login],[NewConferenceId],["invite"],[],BuddyList}),
			case lists:keysearch(IM,1,ServicesList)	of
				{value,{_ServiceID,_ServiceLogin,_Count,_Members}}	->
					NewServicesList	= ServicesList;%{ServiceID,ServiceLogin,Count,Members};
				false ->
					NewServicesList = [{IM,Login,0,[]} | ServicesList]
			end,
			cast_invite_request_to_all_service_pids(Rest,NewConferenceId,NewServicesList,Client_Record, Send_Socket,Socket_Type,State);
		_->
			Response = [{response, [{type, "error"}, {errtype, "client"}], ["Conference: No user logged in with this " ++ IM ++ " service "]}],
			gen_server:cast(self(), {send_response, Response, Send_Socket, Socket_Type, Client_Record}),
			cast_invite_request_to_all_service_pids(Rest,NewConferenceId,ServicesList,Client_Record,Send_Socket,Socket_Type,State)
	end;
cast_invite_request_to_all_service_pids([],_NewConferenceId,ServicesList,_Client_Record,_Send_Socket,_Socket_Type,_State) ->
	ServicesList.	

cast_join_leave_message_to_other_services([First | ServicesList],IM_Type,LoginName,ConferenceId,Message,Connection_Map) ->
	{IM,Login,Count,_Members} = First,
	case dict:find(IM,Connection_Map) of
		{ok,ServicePid}	->
			if
				IM /= IM_Type andalso Count > 0 ->
					gen_server:cast(ServicePid,{conference,[IM],[Login],[ConferenceId],["message"],Message,[]});
				true ->
					nothing
			end;
		error ->
			nothing
   	end,
	cast_join_leave_message_to_other_services(ServicesList,IM_Type,LoginName,ConferenceId,Message,Connection_Map);

cast_join_leave_message_to_other_services([],_IM_Type,_LoginName,_ConferenceId,_Message,_Connection_Map) ->
	ok.

handle_conference_logout(_ServiceType, []) ->
	[];
handle_conference_logout(ServiceType, [ ConfDetails | Conference_Details_List]) ->
	io:format("########### ~nhandle_conference_logout() ~n~p~n###########~n",[ConfDetails]),
	{ConferenceId, HostName, HostService, ServicesList} = ConfDetails,
	case lists:keysearch(ServiceType, 1, ServicesList) of
	{value, ServiceDetails} ->
		case lists:delete(ServiceDetails, ServicesList) of
		[] ->
			handle_conference_logout(ServiceType, Conference_Details_List);
		NewServicesList ->
			[{ConferenceId,HostName,HostService,NewServicesList} | handle_conference_logout(ServiceType, Conference_Details_List) ]
		end;
	_->
		[ ConfDetails | handle_conference_logout(ServiceType, Conference_Details_List)]
	end.

get_raw_message([{raw,Message} | Rest]) ->
	[Message,get_raw_message(Rest)];

get_raw_message([])->
	[];

get_raw_message([_Head | Rest])->
	get_raw_message(Rest).


