text: var _ = require('lodash');
  var Emitter = require('events').EventEmitter;
  var path = require('path');
  var grunt = require('grunt');
  var packageMatcher = require('./package_matcher');
  
  var Assets = function(cwd, componentsDir) {
    this._assets = {};
    this._cwd = cwd;
    this._componentsDir = componentsDir;
  };
  
  Assets.prototype.addOverridden = function(override, pkg) {
    var pkgPath = path.join(this._componentsDir, pkg);
  
    _(override).each(function(overriddenPaths, assetType) {
      this.addAssets(overriddenPaths, pkg, assetType, pkgPath);
    }, this);
  };
  
  Assets.prototype.addUntyped = function(pkgFiles, pkg) {
    this.addAssets(pkgFiles, pkg, '__untyped__');
  };
  
  Assets.prototype.addAssets = function(filePatterns, pkg, assetType, pkgPath) {
    pkgPath = pkgPath || '';
  
    if (!_.isArray(filePatterns)) {
      filePatterns = [ filePatterns ];
    }
  
    var basePath = path.join(this._cwd, pkgPath);
  
    this._assets[assetType] = this._assets[assetType] || {};
    this._assets[assetType][pkg] = _(grunt.file.expand({cwd: basePath}, filePatterns)).map(function(expandedPath) {
      return path.join(pkgPath, expandedPath);
    });
  };
  
  Assets.prototype.toObject = function() {
    return _.clone(this._assets);
  };
  
  
  var BowerAssets = function(bower, cwd, onlyDepedencies) {
    this.bower = bower;
    this.cwd = cwd;
    this.onlyDependencies = onlyDepedencies;
    this.config = bower.config.json || 'bower.json';
    this.assets = new Assets(cwd, bower.config.directory);
  };
  
  BowerAssets.prototype = Object.create(Emitter.prototype);
  BowerAssets.prototype.constructor = BowerAssets;
  
  BowerAssets.prototype.get = function() {
    var bower = this.bower;
    var bowerConfig = grunt.file.readJSON(path.join(this.cwd, this.config));
    var exportsOverride = bowerConfig.exportsOverride;
    var bowerDependencies = this.onlyDependencies ? bowerConfig.dependencies : {};
  
    var paths = bower.commands.list({paths: true});
    paths.on('end', function(data) {
      this.emit('end', this.mergePaths(
        data,
        exportsOverride ? exportsOverride : {},
        bowerDependencies
      ));
    }.bind(this));
    paths.on('error', function(err) {
      this.emit('error', err);
    }.bind(this));
  
    return this;
  };
  
  /**
   *
   * @param bowerComponents - output of 'bower list' command
   * @param overrides - overrides coming from 'bower.json : exportsOverride'
   * @param bowerDependencies - if true only installs packages that are in bower 'depedencies' object
   *
   * @returns assets grouped by component and type
   */
  BowerAssets.prototype.mergePaths = function(bowerComponents, overrides, bowerDependencies) {
    var findOverride = function(pkg) {
      return _(overrides).find(function(override, override_key) {
        return packageMatcher.matches(pkg, override_key);
      });
    };
  
    var findDependency = function (pkg) {
      return _(bowerDependencies).find(function (dependency, dependency_key) {
          return packageMatcher.matches(pkg, dependency_key);
      });
    };
  
    _(bowerComponents).each(function(pkgFiles, pkg) {
      var existsDepedency = this.onlyDependencies ? findDependency(pkg) !== undefined : true;
  
      if (existsDepedency) {
        var activeOverride = findOverride(pkg);
  
        if (activeOverride) {
          this.assets.addOverridden(activeOverride, pkg);
        } else {
          this.assets.addUntyped(pkgFiles, pkg);
        }
      }
    }, this);
  
    return this.assets.toObject();
  };
  
  module.exports = BowerAssets;
  