'use strict';

var fs = require('fs');
var path = require('path');

var assign = require('deep-assign');
var root = require('pkg-dir').sync();

var cosmiconfig = require('cosmiconfig');

function getDefaultConfig() {
  return {
    https: false,
    host: '0.0.0.0',
    port: 8080,
    locations: [],
    basePath: '',
    assetPath: '',
    browsers: '> 1%, last 2 versions, Firefox ESR',
    node: 'current',
    envVars: { HOPS_MODE: 'dynamic' },
    moduleDirs: [],
    appDir: '.',
    buildDir: 'build',
    cacheDir: 'node_modules/.cache/hops',
  };
}

function applyUserConfig(config) {
  var explorer = cosmiconfig('hops', {
    rcExtensions: true,
    stopDir: root,
    sync: true,
  });
  var result = explorer.load(process.cwd());
  return assign({}, config, result ? result.config : {});
}

function applyInheritedConfig(config) {
  var result = assign({}, config);
  while (result.extends) {
    var configName = result.extends;
    var configPath;
    try {
      configPath = require.resolve(configName);
    } catch (_) {
      configPath = path.join(root, configName);
    }
    delete result.extends;
    if (fs.existsSync(configPath)) {
      var loader = cosmiconfig('hops', {
        configPath: configPath,
        sync: true,
      });
      var _result = loader.load();
      assign(result, assign(_result ? _result.config : {}, result));
    } else {
      console.error('Failed to load inherited config', configName);
    }
  }
  return result;
}

function applyEnvironmentConfig(config) {
  var env = process.env.HOPS_ENV || process.env.NODE_ENV;
  var result = assign({}, config, config.env && config.env[env]);
  delete result.env;
  return result;
}

function resolvePaths(config) {
  var result = Object.assign({}, config);
  Object.keys(config)
    .filter(function(key) {
      return /(config|file|dir)s?$/i.test(key);
    })
    .forEach(function(key) {
      result[key] = (function resolve(item) {
        if (typeof item === 'string') {
          if (item.indexOf('<') === 0) {
            item = item.replace(/^(?:<([^>]+)>)(.*)/, function() {
              return path.join(config[arguments[1]], arguments[2]);
            });
          }
          return path.isAbsolute(item) ? item : path.join(root, item);
        } else if (Array.isArray(item)) {
          return item.map(resolve);
        } else {
          return item;
        }
      })(config[key]);
    });
  return result;
}

function normalizeURLs(config) {
  var basePath = config.basePath.replace(/^\/*/, '/').replace(/\/*$/, '');
  var assetPath = config.assetPath.replace(/(^\/*|\/*$)/g, '');
  return Object.assign({}, config, {
    locations: config.locations
      .map(function(location) {
        return basePath + location.replace(/\/*$/, '').replace(/^\/*/, '/');
      })
      .sort(function(locationA, locationB) {
        return locationB.length - locationA.length;
      }),
    basePath: basePath,
    assetPath: assetPath,
  });
}

module.exports = [
  getDefaultConfig,
  applyUserConfig,
  applyInheritedConfig,
  applyEnvironmentConfig,
  resolvePaths,
  normalizeURLs,
].reduce(function(result, step) {
  return step(result);
}, null);

@@ -1669,32 +1669,654 @@
 turn result;%0A%7D%0A%0A
+function resolvePlaceholders(config) %7B%0A  var keys = Object.keys(config);%0A  var regExp = new RegExp('%3C(' + keys.join('%7C') + ')%3E', 'g');%0A  function replaceRecursive(item) %7B%0A    if (Array.isArray(item)) %7B%0A      return item.map(replaceRecursive);%0A    %7D%0A    if (typeof item === 'string') %7B%0A      return item.replace(regExp, function(_, match) %7B%0A        var result = config%5Bmatch%5D.toString();%0A        return regExp.test(result) ? replaceRecursive(result) : result;%0A      %7D);%0A    %7D%0A    return item;%0A  %7D%0A  return keys.reduce(function(result, key) %7B%0A    result%5Bkey%5D = replaceRecursive(config%5Bkey%5D);%0A    return result;%0A  %7D, %7B%7D);%0A%7D%0A%0A
 function resolve
@@ -2323,32 +2323,32 @@
 Paths(config) %7B%0A
-
   var result = O
@@ -2597,212 +2597,8 @@
 ) %7B%0A
-          if (item.indexOf('%3C') === 0) %7B%0A            item = item.replace(/%5E(?:%3C(%5B%5E%3E%5D+)%3E)(.*)/, function() %7B%0A              return path.join(config%5Barguments%5B1%5D%5D, arguments%5B2%5D);%0A            %7D);%0A          %7D%0A
     
@@ -3446,24 +3446,24 @@
 itedConfig,%0A
-
   applyEnvir
@@ -3476,16 +3476,39 @@
 Config,%0A
+  resolvePlaceholders,%0A
   resolv

support placeholders everywhere