#!/usr/bin/env node
var protobuf = require('./')
var encodings = require('protocol-buffers-encodings')
var fs = require('fs')
var os = require('os')

var filename = null
var output = null
var watch = false

var RESERVED = {
  type: true,
  message: true,
  name: true,
  buffer: true,
  encode: true,
  decode: true,
  encodingLength: true,
  dependencies: true
}

// handrolled parser to not introduce minimist as this is used a bunch of prod places
// TODO: if this becomes more complicated / has bugs, move to minimist
for (var i = 2; i < process.argv.length; i++) {
  var v = process.argv[i]
  var n = v.split('=')[0]
  if (v[0] !== '-') {
    filename = v
  } else if (n === '--output' || n === '-o' || n === '-wo') {
    if (n === '-wo') watch = true
    output = v === n ? process.argv[++i] : v.split('=').slice(1).join('=')
  } else if (n === '--watch' || n === '-w') {
    watch = true
  }
}

if (!filename) {
  console.error('Usage: protocol-buffers [schema-file.proto] [options]')
  console.error()
  console.error(' --output, -o  [output-file.js]')
  console.error(' --watch,  -w  (recompile on schema change)')
  console.error()
  process.exit(1)
}

if (watch && !output) {
  console.error('--watch requires --output')
  process.exit(1)
}

if (!output) {
  process.stdout.write(compile())
} else {
  write()
  if (watch) fs.watch(filename, write)
}

function write () {
  fs.writeFileSync(output, compile())
}

function isEncoder (m) {
  return typeof m.encode === 'function'
}

function compile () {
  var out = ''
  var messages = protobuf(fs.readFileSync(filename))

  out += '// This file is auto generated by the protocol-buffers cli tool' + os.EOL
  out += os.EOL
  out += '/* eslint-disable quotes */' + os.EOL
  out += '/* eslint-disable indent */' + os.EOL
  out += '/* eslint-disable no-redeclare */' + os.EOL
  out += os.EOL
  out += '// Remember to `npm install --save protocol-buffers-encodings`' + os.EOL
  out += 'var encodings = require(\'protocol-buffers-encodings\')' + os.EOL
  out += 'var varint = encodings.varint' + os.EOL
  out += 'var skip = encodings.skip' + os.EOL
  out += os.EOL

  visit(messages, 'exports', '')

  function visit (messages, exports, spaces) {
    var encoders = Object.keys(messages).filter(function (name) {
      if (RESERVED[name]) return false
      return isEncoder(messages[name])
    })

    var enums = Object.keys(messages).filter(function (name) {
      if (RESERVED[name]) return false
      return !isEncoder(messages[name])
    })

    enums.forEach(function (name) {
      out += spaces + 'var ' + name + ' = ' + exports + '.' + name + ' = ' +
        JSON.stringify(messages[name], null, 2).replace(/\n/g, os.EOL) + os.EOL + os.EOL
    })

    encoders.forEach(function (name) {
      out += spaces + 'var ' + name + ' = ' + exports + '.' + name + ' = {' + os.EOL
      out += spaces + '  buffer: true,' + os.EOL
      out += spaces + '  encodingLength: null,' + os.EOL
      out += spaces + '  encode: null,' + os.EOL
      out += spaces + '  decode: null' + os.EOL
      out += spaces + '}' + os.EOL
      out += os.EOL
    })

    encoders.forEach(function (name) {
      out += spaces + 'define' + name + '()' + os.EOL
    })

    if (encoders.length) out += os.EOL

    encoders.forEach(function (name) {
      out += spaces + 'function define' + name + ' () {' + os.EOL

      visit(messages[name], name, spaces + '  ')
      out += spaces + '  var enc = [' + os.EOL

      messages[name].dependencies.forEach(function (e, i, enc) {
        var name = encodings.name(e)
        if (name) name = 'encodings.' + name
        else name = e.name
        out += spaces + '    ' + name + (i < enc.length - 1 ? ',' : '') + os.EOL
      })

      out += spaces + '  ]' + os.EOL + os.EOL
      out += spaces + '  ' + name + '.encodingLength = encodingLength' + os.EOL
      out += spaces + '  ' + name + '.encode = encode' + os.EOL
      out += spaces + '  ' + name + '.decode = decode' + os.EOL + os.EOL
      out += spaces + '  ' + funToString(messages[name].encodingLength, spaces + '  ') + os.EOL + os.EOL
      out += spaces + '  ' + funToString(messages[name].encode, spaces + '  ') + os.EOL + os.EOL
      out += spaces + '  ' + funToString(messages[name].decode, spaces + '  ') + os.EOL
      out += spaces + '}' + os.EOL + os.EOL
    })
  }

  out += funToString(require('./compile').defined, '') + os.EOL

  return out

  function funToString (fn, spaces) {
    return fn.toString().split('\n').map(indent).join('\n')

    function indent (n, i) {
      if (!i) return n.replace(/(function \w+)\(/, '$1 (')
      return spaces + n
    }
  }
}

@@ -3584,24 +3584,74 @@
 gs.' + name%0A
+        else if (!e.name) name = 'encodings.enum'%0A
         else

fix #74 (#75)