import parser from 'minimist'
import pkginfo from 'pkginfo'
import path from 'path'

class Commander {
  constructor() {
    this.details = {
      options: [],
      commands: []
    }

    this.option('help', 'Output usage information')
    this.command('help', 'Display help')
  }

  option (name, description, init, defaultValue) {
    let usage = []

    switch (name.constructor) {
      case String:
        usage[0] = name.charAt(0)
        usage[1] = name

        break
      case Array:
        usage = usage.concat(name)
        break
      default:
        throw new Error('Invalid name for option')
    }

    if (usage.length > 0 && usage[0].length > 1) {
      throw new Error('Short version of option is longer than 1 char')
    }

    let optionDetails = {
      defaultValue,
      usage,
      description
    }

    if (defaultValue) {
      let initFunction = typeof init === 'function'
      optionDetails.init = initFunction ? init : this.handleType(defaultValue)[1]
    }

    this.details.options.push(optionDetails)
    return this
  }

  command (usage, description) {
    this.details.commands.push({
      usage,
      description
    })

    return this
  }

  handleType (value) {
    const type = value.constructor

    switch (type) {
      case String:
        return ['[value]', toString]
        break
      case Array:
        return ['<list>']
        break
      case Number:
        return ['<n>', parseInt]
        break
      default:
        return false
    }
  }

  setProperties (option) {
    let value = false

    for (let name of option.usage) {
      let fromArgs = this.args[name]

      if (fromArgs) {
        value = fromArgs
      }
    }

    for (let name of option.usage) {
      let propVal = value || option.defaultValue,
          condition = true

      if (option.init) {
        if (option.init === toString) {
          condition = propVal.constructor === Number
        }

        if (condition) {
          propVal = option.init(propVal)
        }
      }

      if (propVal) this[name] = propVal
    }
  }

  generateDetails (kind) {
    const items = this.details[kind]
    let parts = []

    for (let item in items) {
      let usage = items[item].usage,
          initial = items[item].defaultValue

      if (usage.constructor === Array) {
        usage = `-${usage[0]}, --${usage[1]}`
        usage += initial ? ' ' + this.handleType(initial)[0] : ''
      }

      items[item].usage = usage
    }

    const longest = items.sort((a, b) => {
      return b.usage.length - a.usage.length
    })[0].usage.length

    for (let item of items) {
      let usage = item.usage,
          difference = longest - usage.length

      usage += ' '.repeat(difference)
      parts.push('  ' + usage + '  ' + item.description)
    }

    return parts
  }

  renderHelp () {
    const binary = path.basename(this.args._[0])

    let details = [
      '',
      `Usage: ${binary} [options] [command]`,
      '',
      '',
      'Commands:',
      ''
    ]

    const commands = this.generateDetails('commands'),
          options = this.generateDetails('options')

    details = details.concat(
      commands,
      [
        '',
        'Options:',
        ''
      ],
      options,
      ''
    )

    console.log(details.join('\n  '))
    process.exit()
  }

  parse (argv) {
    this.args = parser(argv.slice(1))

    const parent = module.parent

    pkginfo(parent)
    const version = parent.exports.version

    if (version) {
      this.option('version', 'Output the version number', version)

      if (this.args.v || this.args.version) {
        console.log(version)
        process.exit()
      }
    }

    if (this.args._[1] == 'help' || this.args.h || this.args.help) {
      this.renderHelp()
    }

    for (let option of this.details.options) {
      this.setProperties(option)
    }

    const args = this.args
    args._.shift()

    this.raw = args
  }
}

export default new Commander

@@ -76,16 +76,53 @@
 m 'path'
+%0Aimport %7B exec %7D from 'child_process'
 %0A%0Aclass 
@@ -3360,60 +3360,630 @@
 %0A%0A  
-parse (argv) %7B%0A    this.args = parser(argv.slice(1))
+runCommand (name) %7B%0A    const full = path.basename(this.args._%5B0%5D) + '-' + name%0A%0A    let args = process.argv,%0A        i = 0%0A%0A    while (i %3C 3) %7B%0A      args.shift()%0A      i++%0A    %7D%0A%0A    console.log(args)%0A%0A    let child = exec(full, args, %7B%0A      stdio: 'inherit',%0A      detached: true%0A    %7D)%0A%0A    child.on('error', err =%3E %7B%0A      throw err%0A    %7D)%0A  %7D%0A%0A  parse (argv) %7B%0A    this.args = parser(argv.slice(1))%0A    const subCommand = this.args._%5B1%5D %7C%7C%C2%A0false%0A%0A    for (let command of this.details.commands) %7B%0A      if (command.usage !== subCommand) %7B%0A        continue%0A      %7D%0A%0A      this.runCommand(subCommand)%0A      break%0A    %7D
 %0A%0A  

Prepare for sub commands