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 nowjs
  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: {"log level" : 2},
 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 nowjs#
 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 nowjs#
 66  * @function
 67  * @name getGroups
 68 
 69  * @description Retrieves a list (represented in Javascript as an
 70  * array) of all groups that have been created and passes it in to the
 71  * supplied callback.
 72 
 73  * @param {Function} callback Takes one argument, an array of all
 74  * groups that have been created.
 75 
 76  * @example nowjs.on('connect', function () {
 77  *   var self = this;
 78  *   getGroups(function (groups) {
 79  *     nowjs.getGroup(groups[Math.floor(groups.length * Math.random())]).addUser(self);
 80  *   });
 81  * });
 82  */
 83 Now.prototype.getGroups = function (callback) {
 84   callback(Object.keys(this.groups));
 85 };
 86 
 87 /**
 88  * @memberOf nowjs#
 89  * @function
 90  * @name getGroup
 91  * @description Retrieves and returns a group from its name, creating it if
 92  * necessary.
 93  * @param {String} name The name of the group to be retrieved.
 94  * @type Group
 95  * @example var new_group = nowjs.getGroup('a new group');
 96  */
 97 Now.prototype.getGroup = function (name) {
 98   if (!nowUtil.hasProperty(this.groups, name)) {
 99     this.groups[name] = new this.Group(name);
100     /**
101      * @name nowjs#newgroup
102      * @event
103      * @param {Group} group The group created by {@link nowjs#getGroup}.
104      * @description Called when a new group is created.
105      * @example nowjs.on('newgroup', function (name) {
106      *   console.log('You have successfully created the group `' + name + '`');
107      * });
108      */
109 
110     this.emit('newgroup', this.groups[name]);
111   }
112   return this.groups[name];
113 };
114 
115 /**
116  * @static
117  * @memberOf nowjs
118  * @function
119  * @name initialize
120 
121  * @description Returns a reference to the `everyone` object. The
122  * options object, if supplied, will be automatically merged with the
123  * default values.
124 
125  * @param {httpServer} server A Node.js http server (such as the one
126  * available in the http module or a module like Express) on which to
127  * run Now.
128 
129  * @param {Object} [options={"clientWrite" : true, "autoHost" : true,
130   "host" : undefined, "port" : undefined, "socketio" : {},
131   "closureTimeout : 30000, "client : {},  "scope" : "window"}]
132 
133  * @type Group
134 
135  * @example nowjs.initialize(server, {clientWrite: false, socketio: {'log level': 2});
136  */
137 Now.prototype.initialize = function (server, options) {
138   // Merge options
139   if (typeof options === 'object') {
140     nowUtil.extend(this.options, options);
141   } else {
142     options = this._readConfigFile(options);
143     if (options) {
144       nowUtil.extend(this.options, options);
145     }
146   }
147 
148   this.Group = require('./group').initialize(this);
149   this.User = require('./user').initialize(this);
150   this.Handlers = require('./handlers').initialize(this);
151   this.Support = require('./support').initialize(this);
152 
153   var self = this;
154 
155   fileServer.wrapServer(server, this.options);
156   this.server = io.listen(server);
157   for (var i in this.options.socketio) {
158     this.server.set(i, this.options.socketio[i]);
159   }
160 
161   // Need this to be separate from clientsMap.
162   this.server.sockets.on('connection', function (socket) {
163     var user = new self.User(socket);
164     socket.user = self.users[socket.id] = user;
165     self.getGroup('everyone').addUser(socket.id);
166     socket.emit('rd');
167   });
168 
169   var everyone = this.getGroup('everyone');
170   everyone.isSuperGroup = true;
171 
172   // Shim for backwards compatibility.
173   this.on('connect', function () {
174     var user = nowUtil.clone(this);
175     user._events = everyone._events;
176     everyone.emit.apply(user, ['connect']);
177   });
178 
179   this.on('disconnect', function () {
180     var user = nowUtil.clone(this);
181     user._events = everyone._events;
182     everyone.emit.apply(user, ['disconnect']);
183   });
184 
185   return everyone;
186 };
187 
188 Now.prototype.addSupportServer = function(host, port){
189   var server = new this.Support(host, port);
190   return server;
191 }
192 
193 exports.Now = Now;
194 
195 /**
196  * @name nowjs#connect
197  * @event
198  * @version 0.7.0
199 
200  * @description Called in the context of a user when the server first
201  * receives a message from the given user.
202 
203  * @example nowjs.on('connect', function () {
204  *   this.now.receiveMessage('SERVER', 'Welcome to NowJS.');
205  * });
206  */
207 
208 /**
209  * @name nowjs#disconnect
210  * @event
211  * @version 0.7.0
212 
213  * @description Called in the context of a user who has just
214  * disconnected from the server.
215 
216  * @example nowjs.on('disconnect, function () {
217  *   delete myArray[this.user.clientId];
218  * });
219  */
220 
221 /**
222  * @name nowjs#groupdel
223  * @event
224  * @version 0.7.0
225 
226  * @param {Group} group Actually not quite a group; this parameter
227  * refers to a clone of the group in question that also carries the
228  * fully qualified name (fqn) of the variable to delete. Access the
229  * fqn via `group.fqn`.
230 
231  * @description Called when deleting a variable from all members of
232  * the group specified by this function's argument.
233 
234  * @example nowjs.on('groupdel', function (group) {
235  *   if (group.groupName === 'everyone') {
236  *     console.log('Everyone now no longer possesses ' + group.fqn);
237  *   }
238  * });
239  */
240 
241 /**
242  * @name nowjs#grouprv
243  * @event
244  * @version 0.7.0
245 
246  * @param {Group} group Similar to {@link nowjs#groupdel}, this is also
247  * a clone of the actual group. In addition to the fully qualified
248  * name, this clone also possesses a serialized form of its target
249  * value, accessible via `group.val`.
250 
251  * @description Called when replacing the value of a variable for all
252  * members of the group specified by this function's argument.
253 
254  * @example nowjs.on('grouprv', function (group) {
255  *   if (group.groupName === 'everyone') {
256  *     console.log('Everyone now sees ' + group.fqn + ' as ' + group.val);
257  *   }
258  * });
259  */
260 
261