var fs = require('fs');
var exec = require('exec');
var path = require('path');
var async = require('async');

var VirtualBox = {
  REQUIRED_VERSION: '4.3.18',
  INCLUDED_VERSION: '4.3.18',
  INSTALLER_FILENAME: 'virtualbox-4.3.18.pkg',
  INSTALLER_CHECKSUM: '5836c94481c460c648b9216386591a2915293ac86b9bb6c57746637796af6af2',
  command: function () {
    return '/usr/bin/VBoxManage';
  },
  installed: function () {
    return fs.existsSync('/usr/bin/VBoxManage') && fs.existsSync('/Applications/VirtualBox.app/Contents/MacOS/VirtualBox');
  },
  install: function (callback) {
    // -W waits for the process to close before finishing.
    exec('open -W ' + path.join(process.cwd(), 'resources', this.INSTALLER_FILENAME).replace(' ', '\\ '), function (stderr, stdout, code) {
      if (code) {
        callback(stderr);
        return;
      }
      callback(null);
    });
  },
  version: function (callback) {
    if (!this.installed()) {
      callback('VirtualBox not installed.');
      return;
    }
    exec('/usr/bin/VBoxManage -v', function (stderr, stdout, code) {
      if (code) {
        callback(stderr);
        return;
      }
      // Output is x.x.xryyyyyy
      var match = stdout.match(/(\d+\.\d+\.\d+).*/);
      if (!match || match.length < 2) {
        callback('VBoxManage -v output format not recognized.');
        return;
      }
      callback(null, match[1]);
    });
  },
  saveVMs: function (callback) {
    if (!this.installed()) {
      callback('VirtualBox not installed.');
      return;
    }
    exec('list runningvms | sed -E \'s/.*\\{(.*)\\}/\\1/\' | xargs -L1 -I {} VBoxManage controlvm {} savestate', function (stderr, stdout, code) {
      if (code) {
        callback(stderr);
      } else {
        callback();
      }
    });
  },
  kill: function (callback) {
    this.saveRunningVMs(function (err) {
      if (err) {callback(err); return;}
      exec('pkill VirtualBox', function (stderr, stdout, code) {
        if (code) {callback(stderr); return;}
        exec('pkill VBox', function (stderr, stdout, code) {
          if (code) {callback(stderr); return;}
          callback();
        });
      });
    });
  },
  vmState: function (name, callback) {
    exec(this.command() + ' showvminfo ' + name + ' --machinereadable', function (stderr, stdout, code) {
      if (code) { callback(stderr); return; }
      var match = stdout.match(/VMState="(\w+)"/);
      if (!match) {
        callback('Could not parse VMState');
        return;
      }
      callback(null, match[1]);
    });
  },
  deleteVM:function (name, callback) {
    VirtualBox.vmState(name, function (err, state) {
      // No VM found
      if (err) { callback(null, false); return; }
      VirtualBox.exec('controlvm ' + name + ' acpipowerbutton', function (stderr, stdout, code) {
        if (code) { callback(stderr, false); return; }
        var state = null;

        async.until(function () {
          return state === 'poweroff';
        }, function (callback) {
          VirtualBox.vmState(name, function (err, newState) {
            if (err) { callback(err); return; }
            state = newState;
            setTimeout(callback, 250);
          });
        }, function (err) {
          VirtualBox.exec('unregistervm ' + name + ' --delete', function (stderr, stdout, code) {
            if (code) { callback(err); return; }
            callback();
          });
        });
      });
    });
  }
};

module.exports = VirtualBox;