1 var io = require('socket.io');
  2 var fileServer = require('./fileServer');
  3 var EventEmitter = require('events').EventEmitter;
  4 var nowUtil = require('./nowUtil').nowUtil;
  5 
  6 /**
  7  * @name Now
  8  * @constructor
  9  * @description The object returned by require('now').
 10  */
 11 var Now = function () {
 12   this.closures = {};
 13   this.groups = {};
 14   this.users = {};
 15   this.options = {
 16     clientWrite: true,
 17     autoHost: true,
 18     socketio: {},
 19     client: {},
 20     scope: 'window',
 21     closureTimeout: 30000
 22   };
 23 };
 24 
 25 Now.prototype.__proto__ = EventEmitter.prototype;
 26 
 27 Now.prototype._readConfigFile = function (path) {
 28   path = path || process.cwd() + "/nowjs.json";
 29   try {
 30     var conf = require('fs').readFileSync(path), parsedConf;
 31     try {
 32       parsedConf = JSON.parse(conf);
 33     } catch (e) {
 34       //throw new logging.NowError("Malformed configuration file.");
 35       //throw e;
 36     }
 37     return parsedConf;
 38   } catch (err) {
 39     //throw e;
 40     //logging.log("No configuration file found");
 41     return undefined;
 42   }
 43 };
 44 
 45 /**
 46  * @memberOf Now#
 47  * @function
 48  * @name getClient
 49 
 50  * @description Retrieves a user from the given client ID and executes
 51  * of several actions in the context of that user.
 52 
 53  * @param {String} id The client ID associated with the target user.
 54  * @param {Function} callback Takes no arguments. Called in the
 55  * context of the user corresponding to the given id.
 56  * @example nowjs.getClient('1234567890' function () {
 57  *   this.now.receiveMessage('SERVER', 'Anything is possible with NowJS.');
 58  * });
 59  */
 60 Now.prototype.getClient = function (id, callback) {
 61   callback.apply(this.users[id]);
 62 };
 63 
 64 /**
 65  * @memberOf Now#
 66  * @function
 67  * @name getGroup
 68  * @description Retrieves and returns a group from its name, creating it if
 69  * necessary.
 70  * @param {String} name The name of the group to be retrieved.
 71  * @type Group
 72  * @example var new_group = nowjs.getGroup('a new group');
 73  */
 74 Now.prototype.getGroup = function (name) {
 75   if (!nowUtil.hasProperty(this.groups, name)) {
 76     this.groups[name] = new this.Group(name);
 77     /**
 78      * @name Now#newgroup
 79      * @event
 80      * @param {Group} group The group created by {@link Now#getGroup}.
 81      * @description Called when a new group is created.
 82      * @example nowjs.on('newgroup', function (name) {
 83      *   console.log('You have successfully created the group `' + name + '`');
 84      * });
 85      */
 86 
 87     this.emit('newgroup', this.groups[name]);
 88   }
 89   return this.groups[name];
 90 };
 91 
 92 /**
 93  * @static
 94  * @memberOf Now
 95  * @function
 96  * @name initialize
 97 
 98  * @description Returns a reference to the `everyone` object. The
 99  * options object, if supplied, will be automatically merged with the
100  * default values.
101 
102  * @param {httpServer} server A Node.js http server (such as the one
103  * available in the http module or a module like Express) on which to
104  * run Now.
105 
106  * @param {Object} [options={"clientWrite" : true, "autoHost" : true,
107   "host" : undefined, "port" : undefined, "socketio" : {},
108   "closureTimeout : 30000, "client : {},  "scope" : "window"}]
109 
110  * @type Group
111 
112  * @example nowjs.initialize(server, {clientWrite: false, socketio: {'log level': 2});
113  */
114 Now.prototype.initialize = function (server, options) {
115   // Merge options
116   if (typeof options === 'object') {
117     nowUtil.extend(this.options, options);
118   } else {
119     options = this._readConfigFile(options);
120     if (options) {
121       nowUtil.extend(this.options, options);
122     }
123   }
124 125 
  this.Group = require('./group').initialize(this);
126   this.User = require('./user').initialize(this);
127   this.Handlers = require('./handlers').initialize(this);
128 
129   var self = this;
130 
131   fileServer.wrapServer(server, this.options);
132   this.server = io.listen(server);
133   for (var i in this.options.socketio) {
134     this.server.set(i, this.options.socketio[i]);
135   }
136 
137   // Need this to be separate from clientsMap.
138   this.server.sockets.on('connection', function (socket) {
139     var user = new self.User(socket);
140     socket.user = self.users[socket.id] = user;
141     self.getGroup('everyone').addUser(socket.id);
142     socket.emit('rd');
143   });
144 
145   var everyone = this.getGroup('everyone');
146   everyone.isSuperGroup = true;
147 
148   // Shim for backwards compatibility.
149   this.on('connect', function () {
150     var user = nowUtil.clone(this);
151     user._events = everyone._events;
152     everyone.emit.apply(user, ['connect']);
153   });
154 
155   this.on('disconnect', function () {
156     var user = nowUtil.clone(this);
157     user._events = everyone._events;
158     everyone.emit.apply(user, ['disconnect']);
159   });
160 
161   return everyone;
162 };
163 
164 exports.Now = Now;
165 
166 /**
167  * @name Now#connect
168  * @event
169  * @version 0.7.0
170 
171  * @description Called in the context of a user when the server first
172  * receives a message from the given user.
173 
174  * @example nowjs.on('connect', function () {
175  *   this.now.receiveMessage('SERVER', 'Welcome to NowJS.');
176  * });
177  */
178 
179 /**
180  * @name Now#disconnect
181  * @event
182  * @version 0.7.0
183 
184  * @description Called in the context of a user who has just
185  * disconnected from the server.
186 
187  * @example nowjs.on('disconnect, function () {
188  *   delete myArray[this.user.clientId];
189  * });
190  */
191 
192 /**
193  * @name Now#groupdel
194  * @event
195  * @version 0.7.0
196 
197  * @param {Group} group Actually not quite a group; this parameter
198  * refers to a clone of the group in question that also carries the
199  * fully qualified name (fqn) of the variable to delete. Access the
200  * fqn via `group.fqn`.
201 
202  * @description Called when deleting a variable from all members of
203  * the group specified by this function's argument.
204 
205  * @example nowjs.on('groupdel', function (group) {
206  *   if (group.groupName === 'everyone') {
207  *     console.log('Everyone now no longer possesses ' + group.fqn);
208  *   }
209  * });
210  */
211 
212 /**
213  * @name Now#grouprv
214  * @event
215  * @version 0.7.0
216 
217  * @param {Group} group Similar to {@link Now#groupdel}, this is also
218  * a clone of the actual group. In addition to the fully qualified
219  * name, this clone also possesses a serialized form of its target
220  * value, accessible via `group.val`.
221 
222  * @description Called when replacing the value of a variable for all
223  * members of the group specified by this function's argument.
224 
225  * @example nowjs.on('grouprv', function (group) {
226  *   if (group.groupName === 'everyone') {
227  *     console.log('Everyone now sees ' + group.fqn + ' as ' + group.val);
228  *   }
229  * });
230  */
231 
232