    async = require 'async'
    fs = require 'fs-extra'
    {spawn, exec} = require 'child_process'
    readdirp = require 'readdirp'
    minifier = require 'node-minify'  

    log = require './log'

### Commands ###

    run = (cmd, opts) ->

      log.cyan "Run (opts): #{cmd}"
  
      spawned = exec cmd, (error, stdout, stderr) -> opts.cb stdout.toString()  if opts and opts.cb 
     
      spawned.stdout.on 'data', (data) -> opts.data data  if opts and opts.data
      spawned.stderr.on 'data', (data) -> opts.error data  if opts and opts.error
      spawned.on 'exit', () -> opts.exit()  if opts and opts.exit

    runWithCb = (cmd, cb) ->

      log.cyan "Run: #{cmd}"

      spawned = exec cmd, (error, stdout, stderr) -> 

      spawned.on 'exit', cb

    runWithOutputAndCb = (cmd, opts, cb) ->

      log.cyan "Run: #{cmd}"

      spawned = exec cmd, (error, stdout, stderr) -> 

        #console.log stderr

        #opts.data stdout.toString()  if opts and opts.data and stdout.toString()
        #opts.error stderr.toString()  if opts and opts.error and stderr.toString()
     
      spawned.stdout.on 'data', (data) -> console.log data.toString().replace(/\r\n\r\n/g, '') #opts.data data  if opts and opts.data
      spawned.stderr.on 'data', (data) -> console.log data.toString().replace(/\r\n\r\n/g, '') #opts.error data  if opts and opts.error

      spawned.on 'exit', () -> cb()

### Filesystem ###

    copyFileFromSource = (opts, cb) -> fs.outputFile opts.to, fs.readFileSync(opts.from, 'utf8'), cb

    copyFile = (opts, cb) -> fs.copy opts.from, opts.to, cb

    copyDir = (opts, cb) -> fs.copy opts.from, opts.to, cb

    listFiles = (path, fileFilter, cb) ->

      opts = 
        root: path 

      opts.fileFilter = "*#{fileFilter}"  if fileFilter

      files = []

      readdirp opts, (file) ->

        files.push file.fullPath

      , (err, results) -> cb files

Concat only.

    concatFiles = (files, to, cb) ->

      new minifier.minify
        type: 'no-compress'
        fileIn: files
        fileOut: to
        buffer: 1000 * 1024
        callback: cb

Concat + minify.

    concatMinifyFile = (resourceType, file, to, cb) ->

      type = 'gcc'  if resourceType is 'js'
      type = 'yui-css'  if resourceType is 'css'
 
      new minifier.minify
        type: type
        fileIn: file
        fileOut: to
        #buffer: 1000 * 1024
        callback: cb

    replaceStringInFiles = (dir, toReplace, as, cb) ->

      listFiles dir, undefined, (files) ->

        replaceStringInFile file, toReplace, as  for file in files

        cb()

    replaceStringInFile = (file, toReplace, as) ->

      log.cyan "Replacing: #{toReplace} in #{file} with #{as}"

      contents = fs.readFileSync file, 'utf8'
      re = new RegExp toReplace, 'g'
      fs.writeFileSync file, contents.replace(re, as), 'utf8'

## Public API ##

    publicFns = 
      run: run
      runWithCb: runWithCb
      runWithOutputAndCb: runWithOutputAndCb
      copyFileFromSource: copyFileFromSource
      copyFile: copyFile
      copyDir: copyDir
      replaceStringInFiles: replaceStringInFiles
      replaceStringInFile: replaceStringInFile
      listFiles: listFiles
      concatFiles: concatFiles
      concatMinifyFile: concatMinifyFile

    module.exports = publicFns