"use strict";

const co = require('co');
const fs = require('fs');
const path = require('path');
const spawn = require('child_process').spawn;

module.exports = {
  duniter: {

    methods: {
      canWrite: getNPMAccess
    },

    cli: [{
      name: 'plug [what]',
      desc: 'Plugs in a duniter module to this Duniter codebase, making it available for the node.',
      logs: false,
      onDatabaseExecute: (server, conf, program, params) => co(function*() {
        const what = params[0];
        try {
          console.log('Trying to install module "%s"...', what)
          yield checkNPMAccess()
          yield npmInstall(what)
          console.log('Module successfully installed.')
        } catch (err) {
          console.error('Error during installation of the plugin:', err);
        }
        // Close the DB connection properly
        return server && server.disconnect()
      })
    }, {
      name: 'unplug [what]',
      desc: 'Plugs in a duniter module to this Duniter codebase, making it available for the node.',
      logs: false,
      onDatabaseExecute: (server, conf, program, params) => co(function*() {
        const what = params[0];
        try {
          console.log('Trying to remove module "%s"...', what)
          yield checkNPMAccess()
          yield npmRemove(what)
          console.log('Module successfully uninstalled.')
        } catch (err) {
          console.error('Error during installation of the plugin:', err);
        }
        // Close the DB connection properly
        return server && server.disconnect()
      })
    }]
  }
}

function npmInstall(what) {
  return new Promise((res, rej) => {
    const npm = getNPM()
    const cwd = getCWD()
    const install = spawn(npm, ['i', '--save', what], { cwd })

    install.stdout.pipe(process.stdout)
    install.stderr.pipe(process.stderr)

    install.stderr.on('data', (data) => {
      if (data.toString().match(/ERR!/)) {
        setTimeout(() => {
          install.kill('SIGINT')
        }, 100)
      }
    });

    install.on('close', (code) => {
      if (code === null || code > 0) {
        return rej('could not retrieve or install the plugin')
      }
      res()
    });
  })
}


function npmRemove(what) {
  return new Promise((res, rej) => {
    const npm = getNPM()
    const cwd = getCWD()
    const uninstall = spawn(npm, ['remove', '--save', what], { cwd })

    uninstall.stdout.pipe(process.stdout)
    uninstall.stderr.pipe(process.stderr)

    uninstall.stderr.on('data', (data) => {
      if (data.toString().match(/ERR!/)) {
        setTimeout(() => {
          uninstall.kill('SIGINT')
        }, 100)
      }
    });

    uninstall.on('close', (code) => {
      if (code === null || code > 0) {
        return rej('error during the uninstallation of the plugin')
      }
      res()
    });
  })
}

function getNPM() {
  return process.argv[0].replace(/node$/, 'npm')
}

function getCWD() {
  return process.argv[1].replace(/bin\/duniter$/, '')
}

function checkNPMAccess() {
  return co(function*() {
    const hasReadWriteAccess = yield getNPMAccess()
    if (!hasReadWriteAccess) {
      throw 'no write access on disk'
    }
  })
}

function getNPMAccess() {
  return new Promise((res) => {
    fs.access(path.join(__dirname, '/../../package.json'), fs.constants.R_OK | fs.constants.W_OK, (err) => {
      res(!err)
    })
  })
}

@@ -213,16 +213,51 @@
 PMAccess
+,%0A      npmInstall,%0A      npmRemove
 %0A    %7D,%0A
@@ -1638,24 +1638,34 @@
 Install(what
+, npm, cwd
 ) %7B%0A  return
@@ -1693,35 +1693,36 @@
 j) =%3E %7B%0A    
-const
+npm =
  npm 
-=
+%7C%7C
  getNPM()%0A  
@@ -1720,34 +1720,35 @@
 tNPM()%0A    c
-onst
+wd =
  cwd 
-=
+%7C%7C
  getCWD()%0A  
@@ -2266,16 +2266,26 @@
 ove(what
+, npm, cwd
 ) %7B%0A  re
@@ -2325,19 +2325,20 @@
     
-const
+npm =
  npm 
-=
+%7C%7C
  get
@@ -2352,18 +2352,19 @@
    c
-onst
+wd =
  cwd 
-=
+%7C%7C
  get

Allow to parameterize the NPM and CWD vars for plugin installation/removal