#!/usr/bin/env node
var fs     = require('fs');
var path   = require('path');
var script = path.basename(__filename);

var srcDir = process.argv[2];
if (!srcDir) {
  var args = [];
  args[0] = process.argv[0].indexOf(' ') !== -1
    ? '"' + process.argv[0] + '"'
    : process.argv[0];
  args[1] = process.argv[1].indexOf(' ') !== -1
    ? '"' + process.argv[1] + '"'
    : process.argv[1];
  args[2] = path.join('path', 'to', 'mysql', 'src');
  console.error('Usage: ' + args.join(' '));
  process.exit(1);
}

var types      = extractTypes(srcDir);
var targetFile = path.join(__dirname, '..', 'lib', 'protocol', 'constants', 'types.js');
var stream     = fs.createWriteStream(targetFile);
var version    = extractMySqlVersion(srcDir);

stream.write('/**\n * MySQL type constants\n *\n * Extracted from version ' + version + '\n *\n * !! Generated by ' + script + ', do not modify by hand !!\n */\n\n');

var alignment = types.reduce(maxLength, 0);
for (var i = 0; i < types.length; i++) {
  if (i in types) {
    stream.write('exports.' + types[i] + (new Array(alignment - types[i].length + 1)).join(' ') + ' = ' + i + ';\n');
  }
}

stream.write('\n// Lookup-by-number table\n');

var alignment = String(types.length).length;
for (var i = 0; i < types.length; i++) {
  if (i in types) {
    stream.write('exports[' + i + ']' + (new Array(alignment - String(i).length + 1)).join(' ') + ' = \'' + types[i] + '\';\n');
  }
}

console.log('Wrote constants to ' + targetFile);

function extractMySqlVersion(srcDir) {
  var versionFile = path.join(srcDir, 'VERSION');
  var contents    = fs.readFileSync(versionFile, 'utf-8');
  var dictionary  = Object.create(null);

  contents.split('\n').forEach(function (line) {
    var pair = line.split('=');
    var key  = pair[0];
    var val  = pair.slice(1).join('=').trimRight();
    dictionary[key] = val;
  });

  return dictionary.MYSQL_VERSION_MAJOR + '.' +
    dictionary.MYSQL_VERSION_MINOR + '.' +
    dictionary.MYSQL_VERSION_PATCH;
}

function extractTypes(srcDir) {
  var headerFile = path.join(srcDir, 'include', 'mysql.h.pp');
  var contents   = fs.readFileSync(headerFile, 'utf-8');
  var enumRegexp = /typedef enum enum_field_types {([^}]*)}/m;
  var match      = enumRegexp.exec(contents);
  var regexp     = /([A-Z0-9_]+)(?: *= *([0-9]+))?/g;

  if (!match) {
    throw new Error('Cannot locate enum enum_field_types in "' + headerFile + '"');
  }

  var enumContents = match[1];
  var index        = 0;
  var types        = [];

  while ((match = regexp.exec(enumContents))) {
    var name = match[1];
    var num  = Number(match[2]) || index++;

    if (name.indexOf('MYSQL_TYPE_') === 0) {
      types[num] = name.substring(11);
    }
  }

  return types;
}

function maxLength(max, value) {
  return Math.max(max, value.length);
}
