import fs from 'fs';
import os from 'os';
import path from 'path';
import readline from 'readline';
import util from 'util';

import loglevel from 'loglevel';
import loglevelMessagePrefix from 'loglevel-message-prefix';

import Configuration from './Configuration';
import Importer from './Importer';
import WatchmanFileCache from './WatchmanFileCache';

const pathToLogFile = path.join(os.tmpdir(), 'importjs.log');
const logStream = fs.createWriteStream(pathToLogFile, {
  flags: 'w',
});

/* eslint-disable no-console */
const originalConsoleLog = console.log;
console.log = (...args) => {
  logStream.write(`${util.format.apply(null, args)}\n`);
};
console.trace = console.log;
console.debug = console.log;
console.info = console.log;
console.warn = console.log;
console.error = console.log;
/* eslint-enable no-console */

const commandsToFunctionNames = {
  fix: 'fixImports',
  word: 'import',
  goto: 'goto',
  rewrite: 'rewriteImports',
  add: 'addImports',
};

export default function daemon() {
  // The `importjsd` here is mostly a dummy file because config relies on a
  // `pathToCurrentFile`. Normally, this is the javascript file you are editing.
  const config = new Configuration('importjsd');

  loglevel.setLevel(config.get('logLevel'));
  loglevelMessagePrefix(loglevel);
  originalConsoleLog(`DAEMON active. Logs will go to: \n${pathToLogFile}`);

  WatchmanFileCache.initialize().then(() => {
    loglevel.info('WATCHMAN file cache is enabled');
  }).catch((err: Object) => {
    loglevel.info(`WATCHMAN file cache is not available. Reason:\n${err.stack}`);
  });

  const rlInterface = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    terminal: false,
  });

  rlInterface.on('line', (jsonPayload: string) => {
    loglevel.debug(`RECEIVED payload: ${jsonPayload}`);
    // The json payload is an array containing a job id and job details.
    const payload = JSON.parse(jsonPayload);
    const importer = new Importer(
      payload.fileContent.split('\n'), payload.pathToFile);

    // TODO: don't automatically invoke function here because of security issues
    const functionName = commandsToFunctionNames[payload.command];
    importer[functionName](payload.commandArg).then((result: Object) => {
      const jsonResponse = JSON.stringify(result);
      loglevel.debug(`SENDING response: ${jsonResponse}`);
      process.stdout.write(`${jsonResponse}\n`);
    }).catch((error: Object) => {
      const jsonResponse = JSON.stringify({
        error: error.stack,
      });
      loglevel.error(`ERROR response: ${jsonResponse}`);
      process.stdout.write(`${jsonResponse}\n`);
    });
  });
}

@@ -115,24 +115,59 @@
 om 'util';%0A%0A
+import commander from 'commander';%0A
 import logle
@@ -187,16 +187,16 @@
 level';%0A
-
 import l
@@ -999,16 +999,85 @@
 s',%0A%7D;%0A%0A
+commander.option('--parent-pid %3Cn%3E', parseInt).parse(process.argv);%0A%0A
 export d
@@ -1444,18 +1444,16 @@
  go to: 
-%5Cn
 $%7BpathTo
@@ -1676,23 +1676,574 @@
 ack%7D%60);%0A
-
   %7D);%0A%0A
+  if (commander.parentPid) %7B%0A    // Editor plugins should provide a %60--parent-pid=%3Cpid%3E%60 argument on startup,%0A    // so that we can check that the daemon process hasn't turned into a zombie%0A    // once in a while.%0A    setInterval(() =%3E %7B%0A      loglevel.debug(%60Making sure that the parent process (PID=$%7Bcommander.parentPid%7D) is still running.%60);%0A      try %7B%0A        process.kill(commander.parentPid, 0);%0A      %7D catch (error) %7B%0A        loglevel.info('Parent process seems to have died. Exiting.');%0A        process.exit(1);%0A      %7D%0A    %7D, 30000);%0A  %7D%0A%0A
   const 

Exit daemon if dead parent detected