// Generated by CoffeeScript 1.12.7
(function() {
  var EventEmitter, Server, chokidar, defaultExclusions, defaultExts, defaultPort, fs, http, https, path, protocol_version, url, ws,
    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    hasProp = {}.hasOwnProperty;

  fs = require('fs');

  path = require('path');

  ws = require('ws');

  http = require('http');

  https = require('https');

  url = require('url');

  chokidar = require('chokidar');

  EventEmitter = require('events');

  protocol_version = '7';

  defaultPort = 35729;

  defaultExts = ['html', 'css', 'js', 'png', 'gif', 'jpg', 'php', 'php5', 'py', 'rb', 'erb', 'coffee'];

  defaultExclusions = [/\.git\//, /\.svn\//, /\.hg\//];

  Server = (function(superClass) {
    extend(Server, superClass);

    function Server(config1) {
      var base, base1, base2, base3, base4, base5, base6, base7, base8, base9;
      this.config = config1;
      if (this.config == null) {
        this.config = {};
      }
      if ((base = this.config).version == null) {
        base.version = protocol_version;
      }
      if ((base1 = this.config).port == null) {
        base1.port = defaultPort;
      }
      if ((base2 = this.config).exts == null) {
        base2.exts = [];
      }
      if ((base3 = this.config).extraExts == null) {
        base3.extraExts = [];
      }
      if ((base4 = this.config).exclusions == null) {
        base4.exclusions = [];
      }
      if ((base5 = this.config).filesToReload == null) {
        base5.filesToReload = [];
      }
      if (this.config.exts.length === 0) {
        this.config.exts = defaultExts;
      }
      if (this.config.extraExts.length > 0) {
        this.config.exts = this.config.extraExts.concat(defaultExts);
      }
      this.config.exclusions = this.config.exclusions.concat(defaultExclusions);
      if ((base6 = this.config).applyCSSLive == null) {
        base6.applyCSSLive = true;
      }
      if ((base7 = this.config).originalPath == null) {
        base7.originalPath = '';
      }
      if ((base8 = this.config).overrideURL == null) {
        base8.overrideURL = '';
      }
      if ((base9 = this.config).usePolling == null) {
        base9.usePolling = false;
      }
    }

    Server.prototype.listen = function(callback) {
      this.debug("LiveReload is waiting for a browser to connect...");
      this.debug("Protocol version: " + this.config.version + "\nExclusions: " + this.config.exclusions + "\nExtensions: " + this.config.exts + "\nPolling: " + this.config.usePolling + "\n");
      if (this.config.server) {
        this.config.server.listen(this.config.port);
        this.server = new ws.Server({
          server: this.config.server
        });
      } else {
        this.server = new ws.Server({
          port: this.config.port
        });
      }
      this.server.on('connection', this.onConnection.bind(this));
      this.server.on('close', this.onClose.bind(this));
      this.server.on('error', this.onError.bind(this));
      if (callback) {
        return this.server.once('listening', callback);
      }
    };

    Server.prototype.onError = function(err) {
      this.debug("Error " + err);
      return this.emit("error", err);
    };

    Server.prototype.onConnection = function(socket) {
      this.debug("Browser connected.");
      socket.on('message', (function(_this) {
        return function(message) {
          var data, request;
          _this.debug("Client message: " + message);
          request = JSON.parse(message);
          if (request.command === "hello") {
            _this.debug("Client requested handshake...");
            _this.debug("Handshaking with client using protocol " + _this.config.version + "...");
            data = JSON.stringify({
              command: 'hello',
              protocols: ['http://livereload.com/protocols/official-7', 'http://livereload.com/protocols/official-8', 'http://livereload.com/protocols/official-9', 'http://livereload.com/protocols/2.x-origin-version-negotiation', 'http://livereload.com/protocols/2.x-remote-control'],
              serverName: 'node-livereload'
            });
            socket.send(data);
          }
          if (request.command === "info") {
            return _this.debug("Server received client data. Not sending response.");
          }
        };
      })(this));
      socket.on('error', (function(_this) {
        return function(err) {
          return _this.debug("Error in client socket: " + err);
        };
      })(this));
      return socket.on('close', (function(_this) {
        return function(message) {
          return _this.debug("Client closed connection");
        };
      })(this));
    };

    Server.prototype.onClose = function(socket) {
      return this.debug("Socket closed.");
    };

    Server.prototype.watch = function(paths) {
      this.debug("Watching " + paths + "...");
      return this.watcher = chokidar.watch(paths, {
        ignoreInitial: true,
        ignored: this.config.exclusions,
        usePolling: this.config.usePolling
      }).on('add', this.filterRefresh.bind(this)).on('change', this.filterRefresh.bind(this)).on('unlink', this.filterRefresh.bind(this));
    };

    Server.prototype.filterRefresh = function(filepath) {
      var delayedRefresh, fileext, filename, refresh;
      refresh = false;
      this.debug("Saw change to " + filepath);
      fileext = path.extname(filepath).substring(1);
      filename = path.basename(filepath);
      if (this.config.exts.indexOf(fileext) !== -1) {
        refresh = true;
      }
      if (this.config.filesToReload.indexOf(filename) !== -1) {
        refresh = true;
      }
      if (refresh) {
        if (this.config.delay) {
          return delayedRefresh = setTimeout((function(_this) {
            return function() {
              clearTimeout(delayedRefresh);
              return _this.refresh(filepath);
            };
          })(this), this.config.delay);
        } else {
          return this.refresh(filepath);
        }
      }
    };

    Server.prototype.refresh = function(filepath) {
      var data;
      this.debug("Reloading: " + filepath);
      data = JSON.stringify({
        command: 'reload',
        path: filepath,
        liveCSS: this.config.applyCSSLive,
        liveImg: this.config.applyImgLive,
        originalPath: this.config.originalPath,
        overrideURL: this.config.overrideURL
      });
      return this.sendAllClients(data);
    };

    Server.prototype.alert = function(message) {
      var data;
      this.debug("Alert: " + message);
      data = JSON.stringify({
        command: 'alert',
        message: message
      });
      return this.sendAllClients(data);
    };

    Server.prototype.sendAllClients = function(data) {
      return this.server.clients.forEach((function(_this) {
        return function(socket) {
          _this.debug("broadcasting to all clients: " + data);
          return socket.send(data, function(error) {
            if (error) {
              return _this.debug(error);
            }
          });
        };
      })(this));
    };

    Server.prototype.debug = function(str) {
      if (this.config.debug) {
        return console.log(str + "\n");
      }
    };

    Server.prototype.close = function() {
      if (this.watcher) {
        this.watcher.close();
      }
      this.server._server.close();
      return this.server.close();
    };

    return Server;

  })(EventEmitter);

  exports.createServer = function(config, callback) {
    var app, requestHandler, server;
    if (config == null) {
      config = {};
    }
    requestHandler = function(req, res) {
      if (url.parse(req.url).pathname === '/livereload.js') {
        res.writeHead(200, {
          'Content-Type': 'text/javascript'
        });
        return res.end(fs.readFileSync(require.resolve('livereload-js')));
      }
    };
    if (config.https == null) {
      app = http.createServer(requestHandler);
    } else {
      app = https.createServer(config.https, requestHandler);
    }
    if (config.server == null) {
      config.server = app;
    }
    server = new Server(config);
    if (!config.noListen) {
      server.listen(callback);
    }
    return server;
  };

}).call(this);
