1 Xmpp4Js.Lang.namespace( "Xmpp4Js.Chat" );
  2 
  3 /**
  4  * Automatically registers events on connection.
  5  * @class Manages chat conversations for a given connection.
  6  * @constructor
  7  * @param {Xmpp4Js.JabberConnection} con The connection object to associate with.
  8  */
  9 Xmpp4Js.Chat.ChatManager = function(con) {
 10     /** @private @type Xmpp4Js.JabberConnection */
 11     this.con = con;
 12     /** @private @type Map */
 13     this.threads = {};
 14     /** An array of Chat objects. @private @type Xmpp4Js.Chat.Chat */
 15     this.chats = [];
 16     
 17     this.addEvents({
 18         /**
 19         * Fires when a chat has been created. Does not include the message,
 20         * but gives GUI managers an opportunity to setup a listener before
 21         * the first messageReceived is called on the chat object.
 22         * 
 23         * @event chatStarted
 24         * @param chat {Xmpp4Js.Chat.Chat} The chat that was created
 25         */
 26         "chatStarted" : true,
 27         
 28         
 29         /**
 30         * Fires when a chat message was received (including first).
 31         * It is safe to assume that chatStarted will be invoked before this.
 32         * 
 33         * @event messageReceived
 34         * @param {Xmpp4Js.Chat.Chat} chat the chat window
 35         * @param {Xmpp4Js.Packet.Message} message The incoming message
 36         */
 37         "messageReceived" : true, 
 38         
 39         /**
 40         * Fires when a chat is closed. At this point it only happens locally, with
 41         * a call to close(). If a new chat from the same user or with the same threadId
 42         * comes, it will be considered a new conversation and the chatStarted event
 43         * will be fired.
 44         */
 45         "chatClosed" : true
 46     });	
 47     
 48     this._registerEvents();
 49 }
 50 
 51 /**
 52  * Options able to be set.
 53  */
 54 Xmpp4Js.Chat.ChatManager.prototype = {
 55     options : {
 56         /** 
 57          * only applies to finding chats. internally they're still stored (option may change) 
 58          * @type boolean
 59          */
 60         ignoreResource: false,
 61         /** 
 62          * only applies to finding chats. internally they're still stored (option may change)
 63          * @type boolean
 64          */
 65         ignoreThread: false
 66     },
 67 
 68     /**
 69      * Register a packet listener on the connection associated with this ChatManager.
 70      * @private
 71      */
 72     _registerEvents : function() {
 73         this.con.addPacketListener( function(stanza) {			
 74             this._handleMessageReceived( stanza );
 75         }.bind(this), new Xmpp4Js.PacketFilter.PacketClassFilter( Xmpp4Js.Packet.Message ));		
 76     },
 77 
 78     /**
 79      * Handles raising events including chatStarted and messageReceived. 
 80      * Only watches for normal and chat message types.
 81      * @param {Xmpp4Js.Packet.Message} messagePacket The message packet
 82      * @private
 83      */
 84     _handleMessageReceived : function( messagePacket ) {
 85 
 86         if( messagePacket.getType() != "" && messagePacket.getType() != "normal" && messagePacket.getType() != "chat" ) {
 87             return;
 88         }
 89 
 90         var chat = null;
 91         var jid = messagePacket.getFromJid();
 92         var thread = messagePacket.getThread();
 93 
 94         try {
 95             chat = this.findBestChat( jid, thread );	
 96         } catch(e) {
 97             // couldn't find chat exception...
 98             // TODO check
 99             chat = this.createChat( jid, thread );
100         }
101 
102         this.fireEvent( "messageReceived", chat, messagePacket );
103         chat.fireEvent( "messageReceived", chat, messagePacket );
104     },
105 
106     /**
107      * Creates a new chat and returns it, and fires the chatStarted event.
108      *
109      * @param {Jid} jid
110      * @param {Function} listener
111      * @param (String) thread
112      * @return Xmpp4Js.Chat.Chat
113      */
114     createChat : function (jid, thread, listener) {
115         var chat = new Xmpp4Js.Chat.Chat( this, jid, thread );
116         this.threads[ chat.getThread() ] = chat;
117         this.chats.push( chat );
118 
119         this.fireEvent("chatStarted", chat);
120 
121         if( listener instanceof Function ) {
122             chat.on( "messageReceived", listener );
123         }
124 
125         return chat;
126     },
127     
128     /**
129      * Closes a given chat, and sends events. The chat will no longer be
130      * available from getUserChat or getThreadChat. If a new chat from the 
131      * same user or with the same threadId comes, it will be considered a 
132      * new conversation and the chatStarted event will be fired.
133      *
134      * @param {Xmpp4Js.Chat.Chat} chat The chat object to close
135      */
136     closeChat : function(chat) {
137         // assumes that the chat only exists once
138         for( var i = 0; i < this.chats.length; i++ ) {
139             if( chat == this.chats[i] ) {
140                 this.chats = this.chats.slice( i, i );
141                 break;
142             }
143         }
144         
145         delete this.threads[ chat.getThread() ];
146         
147         chat.fireEvent( "close", chat );
148         this.fireEvent( "chatClosed", chat);
149     },
150 
151     /**
152      * Returns a chat by thread ID
153      * @param {String} thread
154      * @return Xmpp4Js.Chat.Chat
155      */
156     getThreadChat : function (thread) {
157         return this.threads[ thread ];
158     },
159 
160     /**
161      * Gets a chat by Jid
162      * @param {Xmpp4Js.Jid} jid Jid object or string.
163      * @return Xmpp4Js.Chat.Chat
164      */
165     getUserChat : function (jid) {
166         for( var i = 0; i < this.chats.length; i++ ) {
167             var chat = this.chats[i];
168             if( chat.getParticipant().equals( jid, this.options.ignoreResource ) ) {
169                 return chat;
170             }
171         }
172     },
173 
174     /**
175      * Get or return a Chat object using a given message.
176      * This implementation checks thread -> jid (no resource) -> create.
177      * @todo write test
178      * @param msg {Xmpp4Js.Packet.Message} A message stanza to determine.
179      * @param isOutgoing {Boolean} If true use toJid, else fromJid
180      * @param ignoreResource {Boolean} Resort to ignoring the resource if needed (last attempt).
181      * @return {Xmpp4Js.Chat.Chat} The end result of the chat finding.
182      */
183     findBestChat : function (jid, thread) {
184         var chat = null;
185         var forJid = new Xmpp4Js.Jid(jid);
186 
187         if( thread && !this.options.ignoreThread ) {
188             chat = this.getThreadChat( thread );
189         } else {
190             chat = this.getUserChat( forJid );
191         }
192 
193         if( chat == null ) {
194 
195             throw new Error( "Could not find best chat for user/thread combination." );
196         }
197 
198         return chat;
199     },
200 
201     /**
202      * Set options. 
203      * FIXME Currently overwrites all existing options
204      * @param {Map} options
205      * @see #options
206      */
207     setOptions : function(options) {
208         this.options = options;
209     },
210 
211     /**
212      * Get options associated with this ChatManager.
213      * @return Map
214      * @see #options
215      */
216     getOptions : function() {
217         return this.options;
218     },
219 
220     /**
221      * The connection that this ChatManager is associated with.
222      * @return Xmpp4Js.JabberConnection
223      */
224     getConnection : function() {
225         return this.con;
226     }
227 };
228 
229 Xmpp4Js.Chat.ChatManager.instances = {};
230 Xmpp4Js.Chat.ChatManager.getInstanceFor = function(con) {
231     var instances = Xmpp4Js.Chat.ChatManager.instances;
232     
233     if( instances[con.id] === undefined ) {
234         instances[con.id] = new Xmpp4Js.Chat.ChatManager( con );
235     }
236 
237     return instances[con.id];
238 };
239 
240 
241 Xmpp4Js.Lang.extend(Xmpp4Js.Chat.ChatManager, Xmpp4Js.Event.EventProvider, Xmpp4Js.Chat.ChatManager.prototype);
242