/* @flow */

import childProcess from 'mz/child_process'
import path from 'path'

import BuildState from '../BuildState'
import Rule from '../Rule'
import File from '../File'

export default class BibTeX extends Rule {
  static fileTypes: Set<string> = new Set(['BibTeXControlFile', 'BibTeXFile'])

  static async analyze (buildState: BuildState, jobName: ?string, file: File): Promise<?Rule> {
    if (this.phases.has(buildState.phase) && this.fileTypes.has(file.type)) {
      const auxFile = await buildState.getFile(buildState.resolveOutputPath('.aux', jobName))
      if (!auxFile) return
      const id = buildState.getRuleId(this.name, jobName, auxFile)
      if (buildState.getRule(id)) return
      return new this(buildState, jobName, auxFile)
    }
  }

  async evaluate () {
    const triggers = Array.from(this.getTriggers())
    const run: boolean = triggers.length === 0 ||
      triggers.some(file => file.type !== 'ParsedLaTeXLog' || (file.value && file.value.messages && file.value.messages.some(message => message.text.match(/run BibTeX/))))

    if (!run) return true

    this.info(`Running ${this.id}...`)

    try {
      const args = await this.constructArguments()
      const options = this.constructProcessOptions()
      const command = `bibtex ${args.join(' ')}`

      const stdout = await childProcess.exec(command, options)
      await this.addResolvedInputs(['.log-ParsedLaTeXLog'])
      await this.addResolvedOutputs(['.bbl', '.blg'])
      await this.parseOutput(stdout)
    } catch (error) {
      this.error(error.toString())
      return false
    }

    return true
  }

  constructProcessOptions () {
    const options: Object = {
      cwd: this.rootPath
    }

    if (this.options.outputDirectory) {
      options.env = Object.assign({}, process.env, { BIBINPUTS: `.:${this.options.outputDirectory}` })
    }

    return options
  }

  async constructArguments () {
    const args = []
    const auxFile = await this.getInput(this.resolveOutputPath('.aux'))

    if (auxFile) args.push(`"${auxFile.normalizedFilePath}"`)

    return args
  }

  async parseOutput (stdout: string) {
    const databasePattern = /^Database file #\d+: (.*)$/mg
    let match

    while ((match = databasePattern.exec(stdout)) !== null) {
      await this.getInput(path.resolve(this.rootPath, match[1]))
      if (this.options.outputDirectory) {
        await this.getInput(path.resolve(this.rootPath, this.options.outputDirectory, match[1]))
      }
    }
  }
}

@@ -79,47 +79,8 @@
 h'%0A%0A
-import BuildState from '../BuildState'%0A
 impo
@@ -221,137 +221,62 @@
 t(%5B'
-BibTeXControlFile', 'BibTeXFile'%5D)%0A%0A  static async analyze (buildState: BuildState, jobName: ?string, file: File): Promise%3C?Rule%3E
+ParsedLaTeXLog'%5D)%0A%0A  input: ?File%0A%0A  async evaluate ()
  %7B%0A 
@@ -286,391 +286,291 @@
 if (
+!
 this.
-phases.has(buildState.phase)
+input && !!this.firstParameter.value && !!this.firstParameter.value.messages
  && 
+!!
 this.fi
-leTypes.has(file.type)) %7B%0A      const auxFile = await buildState.getFile(buildState.resolveOutputPath('.aux', jobName))%0A      if (!auxFile) return%0A      const id = buildState.getRuleId(this.name, jobName, auxFile)%0A      if (buildState.getRule(id)) return%0A      return new this(buildState, jobName, auxFile)%0A    %7D%0A  %7D%0A%0A  async evaluate () %7B
+rstParameter.value.messages.some(message =%3E message.text.match(/BibTeX/))) %7B%0A      this.input = await this.getInput(this.resolveOutputPath('.aux'))%0A    %7D%0A%0A    if (!this.input) return true%0A
 %0A   
@@ -1139,68 +1139,8 @@
 ns)%0A
-      await this.addResolvedInputs(%5B'.log-ParsedLaTeXLog'%5D)%0A
     
@@ -1653,96 +1653,27 @@
  %5B%5D%0A
+%0A
     
-const auxFile = await this.getInput(this.resolveOutputPath('.aux'))%0A%0A    if (auxFile
+if (this.input
 ) ar
@@ -1688,15 +1688,18 @@
 %60%22$%7B
-auxFile
+this.input
 .nor

Change trigger for BibTeX to LaTeX log