var child_process = require('child_process');
var net = require('net');
var os = require('os');
var fs = require('fs');
var path = require('path');
var exec = require('exec');

var autoUpdater = require('auto-updater');
var app = require('app');
var BrowserWindow = require('browser-window');
var ipc = require('ipc');

var dirname = __dirname;

var freeport = function (callback) {
  var server = net.createServer();
  var port = 0;
  server.on('listening', function() {
    port = server.address().port;
    server.close();
  });
  server.on('close', function() {
    callback(null, port);
  });
  server.listen(0, '127.0.0.1');
};

var start = function (callback) {
  if (process.env.NODE_ENV === 'development') {
    callback('http://localhost:3000');
  } else {
    process.stdout.write('Starting production server\n');
    if (os.platform() === 'darwin') {
      var kitePath = path.join(process.env.HOME, 'Library/Application Support/Kitematic/');
      var dataPath = path.join(kitePath, 'data');
      console.log(dataPath);
      var bundlePath = path.join(kitePath, 'bundle');
      if (!fs.existsSync(kitePath)) {
        fs.mkdirSync(kitePath);
      }
      if (!fs.existsSync(dataPath)) {
        fs.mkdirSync(dataPath);
      }
      if (!fs.existsSync(bundlePath)) {
        fs.mkdirSync(bundlePath);
      }
    }

    // One for meteor, one for mongo
    freeport(function (err, webPort) {
      freeport(function(err, mongoPort) {
        console.log('MongoDB: ' + mongoPort);
        console.log('webPort: ' + webPort);
        child_process.exec('kill $(ps aux -e | grep PURPOSE=KITEMATIC | awk \'{print $2}\') && rm ' + path.join(dataPath, 'mongod.lock'), function (error, stdout, stderr) {
          var mongoChild = child_process.spawn(path.join(dirname, 'resources', 'mongod'), ['--bind_ip', '127.0.0.1', '--dbpath', dataPath, '--port', mongoPort, '--unixSocketPrefix', dataPath], {
            env: {
              PURPOSE: 'KITEMATIC'
            }
          });
          var started = false;
          mongoChild.stdout.setEncoding('utf8');
          mongoChild.stdout.on('data', function (data) {
            console.log(data);
            if (data.indexOf('waiting for connections on port ' + mongoPort)) {
              if (!started) {
                started = true;
              } else {
                return;
              }

              console.log('Starting node child...');
              var rootURL = 'http://localhost:' + webPort;
              var user_env = process.env;
              user_env.ROOT_URL = rootURL;
              user_env.PORT = webPort;
              user_env.BIND_IP = '127.0.0.1';
              user_env.DB_PATH = dataPath;
              user_env.MONGO_URL = 'mongodb://localhost:' + mongoPort + '/meteor';
              user_env.METEOR_SETTINGS = fs.readFileSync(path.join(dirname, 'resources', 'settings.json'), 'utf8');
              user_env.DIR = dirname;
              user_env.NODE_ENV = 'production';
              user_env.NODE_PATH = path.join(dirname, 'node_modules');
              var nodeChild = child_process.spawn(path.join(dirname, 'resources', 'node'), [path.join(dirname, 'bundle', 'main.js')], {
                env: user_env
              });

              var opened = false;
              nodeChild.stdout.setEncoding('utf8');
              nodeChild.stdout.on('data', function (data) {
                console.log(data);
                if (data.indexOf('Kitematic started.') !== -1) {
                  if (!opened) {
                    opened = true;
                  } else {
                    return;
                  }
                  setTimeout(function () {
                    callback(rootURL, nodeChild, mongoChild);
                  }, 100);
                }
              });
            }
          });
        });
      });
    });
  }
};

mainWindow = null;

app.on('activate-with-no-open-windows', function () {
  if (mainWindow) {
    mainWindow.show();
  }
  return false;
});

app.on('ready', function() {
  start(function (url, nodeChild, mongoChild) {

    // Create the browser window.
    var windowOptions = {
      width: 800,
      height: 578,
      resizable: false,
      frame: false,
      'web-preferences': {
        'web-security': false
      }
    };
    mainWindow = new BrowserWindow(windowOptions);
    mainWindow.hide();
    mainWindow.loadUrl(url);

    process.on('uncaughtException', app.quit);

    var saveVMOnQuit = true;
    app.on('will-quit', function (e) {
      console.log('Cleaning up children.');
      if (nodeChild) {
        nodeChild.kill();
      }
      if (mongoChild) {
        mongoChild.kill();
      }
      if (saveVMOnQuit) {
        exec('VBoxManage controlvm boot2docker-vm savestate', function (stderr, stdout, code) {});
      }
    });

    mainWindow.webContents.on('new-window', function (e) {
      e.preventDefault();
    });

    mainWindow.webContents.on('did-finish-load', function() {
      mainWindow.show();
      mainWindow.focus();

      // Auto Updates
      autoUpdater.setFeedUrl('https://updates.kitematic.com/releases/latest?version=' + app.getVersion());

      autoUpdater.on('checking-for-update', function (e) {
        console.log('Checking for update...');
      });

      autoUpdater.on('update-available', function (e) {
        console.log('Update available.');
        console.log(e);
      });

      autoUpdater.on('update-not-available', function (e) {
        console.log('Update not available.');
      });

      autoUpdater.on('update-downloaded', function (e, releaseNotes, releaseName, releaseDate, updateURL) {
        console.log('Update downloaded.');
        mainWindow.webContents.send('notify', 'window:update-available');
      });

      autoUpdater.on('error', function (e) {
        console.log('An error occured while checking for updates.');
        console.log(e);
      });

      ipc.on('command', function (event, arg) {
        console.log('Command: ' + arg);
        if (arg === 'application:quit-install') {
          saveVMOnQuit = false;
          autoUpdater.quitAndInstall();
        }
      });

      autoUpdater.checkForUpdates();
    });
  });
});