var app = require('app');
var net = require('net');
var path = require('path');
var fs = require('fs');
var os = require('os');

function deleteSocketFile(socketPath) {
  if (process.platform === 'win32') {
    return;
  }

  if (fs.existsSync(socketPath)) {
    try {
      fs.unlinkSync(socketPath);
    }
    catch (error) {
      // Ignore ENOENT errors in case the file was deleted between the exists
      // check and the call to unlink sync. This occurred occasionally on CI
      // which is why this check is here.
      if (error.code !== 'ENOENT') {
        throw error;
      }
    }
  }
}

// Creates server to listen for additional atom application launches.
//
// You can run the atom command multiple times, but after the first launch
// the other launches will just pass their information to this server and then
// close immediately.
function listenForArgumentsFromNewProcess(socketPath, callback) {
  deleteSocketFile(socketPath);

  var server = net.createServer(function(connection) {
    connection.on('data', function(data) {
      var args = JSON.parse(data);
      callback(args);
    });
  });
  server.listen(socketPath);
  server.on('error', function(error) {
    console.error('Application server failed', error);
  });
  return server;
}

function tryStart(socketPath, callback) {
  // FIXME: Sometimes when socketPath doesn't exist, net.connect would strangely
  // take a few seconds to trigger 'error' event, it could be a bug of node
  // or atom-shell, before it's fixed we check the existence of socketPath to
  // speedup startup.
  if (process.platform !== 'win32' && !fs.existsSync(socketPath)) {
    callback()
    return
  }

  var client = net.connect({path: socketPath}, function() {
    client.write(JSON.stringify(process.argv.slice(1)), function() {
      client.end();
      app.terminate();
    });
  });
  client.on('error', callback);
}

module.exports = function(name, startCallback, newProcessCallback) {
  var socketPath;
  if (process.platform === 'win32') {
    socketPath = '\\\\.\\pipe\\' + name + '-sock'
  }
  else {
    socketPath = path.join(os.tmpdir(), name + '.sock')
  }

  tryStart(socketPath, function() {
    var server = listenForArgumentsFromNewProcess(socketPath, newProcessCallback);

    app.on('will-quit', function() {
      server.close();
      deleteSocketFile(socketPath);
    });

    app.on('will-exit', function() {
      server.close();
      deleteSocketFile(socketPath);
    });

    startCallback();
  });
};
