// Generated by CoffeeScript 1.9.2
(function() {
  var clone, evaluateFunctionArgs, falafel, fs, isRootDir, loadConfig, merge, path, skipFile, through,
    indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

  path = require('path');

  fs = require('fs');

  through = require('through');

  falafel = require('falafel');

  loadConfig = require('./loadConfig');

  skipFile = require('./skipFile');

  exports.loadTransformConfig = loadConfig.loadTransformConfig;

  exports.loadTransformConfigSync = loadConfig.loadTransformConfigSync;

  exports.skipFile = skipFile;

  isRootDir = function(filename) {
    return filename === path.resolve(filename, '/');
  };

  merge = function(a, b) {
    var answer, key;
    if (a == null) {
      a = {};
    }
    if (b == null) {
      b = {};
    }
    answer = {};
    for (key in a) {
      answer[key] = a[key];
    }
    for (key in b) {
      answer[key] = b[key];
    }
    return answer;
  };

  clone = function(a) {
    var answer, key;
    if (!a) {
      return a;
    }
    answer = {};
    for (key in a) {
      answer[key] = a[key];
    }
    return answer;
  };

  exports.makeStringTransform = function(transformName, options, transformFn) {
    var transform;
    if (options == null) {
      options = {};
    }
    if (transformFn == null) {
      transformFn = options;
      options = {};
    }
    transform = function(file, config) {
      var configData, content, end, ref, write;
      configData = transform.configData != null ? transform.configData : loadConfig.loadTransformConfigSync(transformName, file, options);
      if (config != null) {
        configData = (ref = clone(configData)) != null ? ref : {
          config: {}
        };
        configData.config = merge(configData.config, config);
        if (configData.config.appliesTo) {
          configData.appliesTo = configData.config.appliesTo;
          delete configData.config.appliesTo;
        }
      }
      if (skipFile(file, configData, options)) {
        return through();
      }
      content = '';
      write = function(buf) {
        return content += buf;
      };
      end = function() {
        var err, handleError, transformOptions;
        handleError = (function(_this) {
          return function(error) {
            var suffix;
            suffix = " (while " + transformName + " was processing " + file + ")";
            if (error instanceof Error && error.message) {
              error.message += suffix;
            } else {
              error = new Error("" + error + suffix);
            }
            return _this.emit('error', error);
          };
        })(this);
        try {
          transformOptions = {
            file: file,
            configData: configData,
            config: configData != null ? configData.config : void 0,
            opts: configData != null ? configData.config : void 0
          };
          return transformFn.call(this, content, transformOptions, (function(_this) {
            return function(err, transformed) {
              if (err) {
                return handleError(err);
              }
              _this.queue(String(transformed));
              return _this.queue(null);
            };
          })(this));
        } catch (_error) {
          err = _error;
          return handleError(err);
        }
      };
      return through(write, end);
    };
    transform.configure = function(config, configOptions) {
      var answer;
      if (configOptions == null) {
        configOptions = {};
      }
      answer = exports.makeStringTransform(transformName, options, transformFn);
      answer.setConfig(config, configOptions);
      return answer;
    };
    transform.setConfig = function(config, configOptions) {
      var configDir, configFile;
      if (configOptions == null) {
        configOptions = {};
      }
      configFile = configOptions.configFile || null;
      configDir = configOptions.configDir || (configFile ? path.dirname(configFile) : null);
      if (!config) {
        this.configData = null;
      } else {
        this.configData = {
          config: config,
          configFile: configFile,
          configDir: configDir,
          cached: false
        };
        if (config.appliesTo) {
          this.configData.appliesTo = config.appliesTo;
          delete config.appliesTo;
        }
      }
      return this;
    };
    return transform;
  };

  exports.makeFalafelTransform = function(transformName, options, transformFn) {
    var falafelOptions, ref, transform;
    if (options == null) {
      options = {};
    }
    if (transformFn == null) {
      transformFn = options;
      options = {};
    }
    falafelOptions = (ref = options.falafelOptions) != null ? ref : {};
    transform = exports.makeStringTransform(transformName, options, function(content, transformOptions, done) {
      var pending, transformCb, transformErr, transformed;
      transformErr = null;
      pending = 1;
      transformed = null;
      transformCb = function(err) {
        if (err && !transformErr) {
          transformErr = err;
          done(err);
        }
        if (transformErr) {
          return;
        }
        pending--;
        if (pending === 0) {
          return done(null, transformed);
        }
      };
      transformed = falafel(content, falafelOptions, function(node) {
        var err;
        pending++;
        try {
          return transformFn(node, transformOptions, transformCb);
        } catch (_error) {
          err = _error;
          return transformCb(err);
        }
      });
      return transformCb(transformErr, transformed);
    });
    transform.configure = function(config, configOptions) {
      var answer;
      if (configOptions == null) {
        configOptions = {};
      }
      answer = exports.makeFalafelTransform(transformName, options, transformFn);
      answer.setConfig(config, configOptions);
      return answer;
    };
    return transform;
  };

  exports.makeRequireTransform = function(transformName, options, transformFn) {
    var evaluateArguments, ref, transform;
    if (options == null) {
      options = {};
    }
    if (transformFn == null) {
      transformFn = options;
      options = {};
    }
    evaluateArguments = (ref = options.evaluateArguments) != null ? ref : true;
    transform = exports.makeFalafelTransform(transformName, options, function(node, transformOptions, done) {
      var args;
      if (node.type === 'CallExpression' && node.callee.type === 'Identifier' && node.callee.name === 'require') {
        args = evaluateFunctionArgs(evaluateArguments, transformOptions, node);
        return transformFn(args.values(), transformOptions, function(err, transformed) {
          if (err) {
            return done(err);
          }
          if (transformed != null) {
            node.update(transformed);
          }
          return done();
        });
      } else {
        return done();
      }
    });
    transform.configure = function(config, configOptions) {
      var answer;
      if (configOptions == null) {
        configOptions = {};
      }
      answer = exports.makeRequireTransform(transformName, options, transformFn);
      answer.setConfig(config, configOptions);
      return answer;
    };
    return transform;
  };

  exports.makeFunctionTransform = function(transformName, options, transformFn) {
    var evaluateArguments, functionNames, ref, transform;
    if (options == null) {
      options = {};
    }
    if (transformFn == null) {
      transformFn = options;
      options = {};
    }
    evaluateArguments = (ref = options.evaluateArguments) != null ? ref : true;
    functionNames = [];
    if (options.functionNames != null) {
      if (Array.isArray(options.functionNames) || {}.toString.call(options.functionNames) === '[object Array]') {
        functionNames = options.functionNames;
      } else if (typeof options.functionNames === 'string') {
        functionNames = [options.functionNames];
      }
    }
    if (functionNames.length === 0) {
      functionNames.push('require');
    }
    transform = exports.makeFalafelTransform(transformName, options, function(node, transformOptions, done) {
      var args, ref1;
      if (node.type === 'CallExpression' && node.callee.type === 'Identifier' && (ref1 = node.callee.name, indexOf.call(functionNames, ref1) >= 0)) {
        args = evaluateFunctionArgs(evaluateArguments, transformOptions, node);
        return transformFn({
          name: node.callee.name,
          args: args
        }, transformOptions, function(err, transformed) {
          if (err) {
            return done(err);
          }
          if (transformed != null) {
            node.update(transformed);
          }
          return done();
        });
      } else {
        return done();
      }
    });
    transform.configure = function(config, configOptions) {
      var answer;
      if (configOptions == null) {
        configOptions = {};
      }
      answer = exports.makeFunctionTransform(transformName, options, transformFn);
      answer.setConfig(config, configOptions);
      return answer;
    };
    return transform;
  };

  exports.runTransform = function(transform, file, options, done) {
    var doTransform;
    if (options == null) {
      options = {};
    }
    if (done == null) {
      done = options;
      options = {};
    }
    doTransform = function(content) {
      var data, err, throughStream;
      data = "";
      err = null;
      throughStream = options.config != null ? transform(file, options.config) : transform(file);
      throughStream.on("data", function(d) {
        return data += d;
      });
      throughStream.on("end", function() {
        if (!err) {
          return done(null, data);
        }
      });
      throughStream.on("error", function(e) {
        err = e;
        return done(err);
      });
      throughStream.write(content);
      return throughStream.end();
    };
    if (options.content) {
      return process.nextTick(function() {
        return doTransform(options.content);
      });
    } else {
      return fs.readFile(file, "utf-8", function(err, content) {
        if (err) {
          return done(err);
        }
        return doTransform(content);
      });
    }
  };

  evaluateFunctionArgs = function(evaluateArguments, transformOptions, node) {
    var arg, args, dirname, varNames, vars;
    if (evaluateArguments) {
      dirname = path.dirname(transformOptions.file);
      varNames = ['__filename', '__dirname', 'path', 'join'];
      vars = [transformOptions.file, dirname, path, path.join];
      args = node["arguments"].map(function(arg) {
        var err, t;
        t = "return " + (arg.source());
        try {
          return {
            value: Function(varNames, t).apply(null, vars),
            type: arg.type
          };
        } catch (_error) {
          err = _error;
          return {
            value: arg.source(),
            type: arg.type
          };
        }
      });
    } else {
      args = (function() {
        var i, len, ref, results;
        ref = node["arguments"];
        results = [];
        for (i = 0, len = ref.length; i < len; i++) {
          arg = ref[i];
          results.push({
            value: arg.source(),
            type: arg.type
          });
        }
        return results;
      })();
    }
    args.values = function() {
      var i, len, values;
      values = [];
      for (i = 0, len = this.length; i < len; i++) {
        arg = this[i];
        if (arg.value != null) {
          values.push(arg.value);
        }
      }
      return values;
    };
    return args;
  };

}).call(this);
