;(function() {
  'use strict';

  var splitPathRe =
    /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;

  var Path = {
    dirname: function(path) {
      var result = Path.posixSplitPath(path),
        root = result[0],
        dir = result[1];

      if (!root && !dir) {
        // No dirname whatsoever
        return '.';
      }

      if (dir) {
        // It has a dirname, strip trailing slash
        dir = dir.substr(0, dir.length - 1);
      }

      return root + dir;
    },
    resolve: function() {
      var resolvedPath = '',
        resolvedAbsolute = false;

      for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
        var path = (i >= 0) ? arguments[i] : '/';

        // Skip empty and invalid entries
        if (typeof path !== 'string') {
          throw new TypeError('Arguments to path.resolve must be strings');
        } else if (!path) {
          continue;
        }

        resolvedPath = path + '/' + resolvedPath;
        resolvedAbsolute = path[0] === '/';
      }

      // At this point the path should be resolved to a full absolute path, but
      // handle relative paths to be safe (might happen when process.cwd() fails)

      // Normalize the path
      resolvedPath = Path.normalizeArray(resolvedPath.split('/'),
        !resolvedAbsolute).join('/');

      var result = ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
      if(result[0]==='/')
        return result.substr(1);
      return result;
    },
    normalizeArray: function(parts, allowAboveRoot) {
      var res = [];
      for (var i = 0; i < parts.length; i++) {
        var p = parts[i];

        // ignore empty parts
        if (!p || p === '.')
          continue;

        if (p === '..') {
          if (res.length && res[res.length - 1] !== '..') {
            res.pop();
          } else if (allowAboveRoot) {
            res.push('..');
          }
        } else {
          res.push(p);
        }
      }

      return res;
    },
    join: function(){
      var path = '';
      for( var i = 0; i < arguments.length; i++ ){
        var segment = arguments[ i ];
        if( typeof segment !== 'string' ){
          throw new TypeError( 'Arguments to path.join must be strings' );
        }
        if( segment ){
          if( !path ){
            path += segment;
          }else{
            path += '/' + segment;
          }
        }
      }
      return Path.normalize( path );
    },
    basename: function(path, ext) {
      var f = Path.posixSplitPath(path)[2];
      // TODO: make this comparison case-insensitive on windows?
      if (ext && f.substr(-1 * ext.length) === ext) {
        f = f.substr(0, f.length - ext.length);
      }
      return f;
    },
    posixSplitPath: function(filename) {
      return splitPathRe.exec(filename).slice(1);
    },
    normalize: function( path ){
      var isAbsolute = Path.isAbsolute( path ),
        trailingSlash = path && path[ path.length - 1 ] === '/';

      // Normalize the path
      path = Path.normalizeArray( path.split( '/' ), !isAbsolute ).join( '/' );

      if( !path && !isAbsolute ){
        path = '.';
      }
      if( path && trailingSlash ){
        path += '/';
      }

      return ( isAbsolute ? '/' : '' ) + path;
    },

// posix version
    isAbsolute: function( path ){
      return path.charAt( 0 ) === '/';
    }
  };


  var log = function() {
    console.log.apply(console, ['Define'].concat([].slice.call(arguments)));
  };

  var head = document.getElementsByTagName('head')[0];
  var cssLoader = function(fileName) {
    var link = document.createElement('link');
    link.setAttribute('rel', 'stylesheet');
    link.setAttribute('type', 'text/css');
    link.setAttribute('href', fileName);
    head.appendChild(link);
  };
  var jsLoader = function(fileName) {
    fileName = fileName.replace(/src\//,'');
    var script = document.createElement('script');
    script.setAttribute('type', script.type = 'text/javascript');
    script.onload = function(){

    };
    script.setAttribute('src', script.src = fileName);
    head.appendChild(script);
  };

  var InstantLoaders = [
    {name: '.scss', loader: cssLoader},
    {name: '.css', loader: cssLoader},
    {name: '.jsx', loader: jsLoader},
    {name: '.js', loader: jsLoader},
  ];

  var Ready = function() {}; Ready.prototype = {ready: true};
  var Wait = function(fileName) {this.fileName = fileName; this.wait = [];};
  Wait.prototype = {
    fileName: '',
    ready: false,
    resolving: 0,
    checkInstantLoad: function() {
      for( var i = 0, _i = InstantLoaders.length; i < _i; i++ ){
        const instantLoader = InstantLoaders[ i ];
        if(this.fileName.substr(-instantLoader.name.length).toLowerCase()===instantLoader.name){
          if(instantLoader.loader(this.fileName)) {
            return true;
          }
          break;
        }
      }
      return false;
    }
  };

  var wait = {
    exports: Ready()
  };
  var defined = {

  };
  var resolve = function(base, file) {
    return Path.resolve(Path.dirname(base), file);
  };
  var exec = function(def) {
    var exports = {};
    def.fn.apply(null, def.deps.map(function(dep) {
      if(dep === 'exports'){
        return exports;
      }

      return defined[resolve(def.fileName, dep)];
    }));
    defined[def.fileName] = exports;
    wait[def.fileName] = new Ready();
    for( var i = 0, _i = wait.length; i < _i; i++ ){
      var waitElement = wait[ i ];
      waitElement.resolving--;

    }
    for( var i = 0, _i = wait.length; i < _i; i++ ){
      if(waitElement.resolving === 0){
        exec(waitElement.def)
      }

    }
  };
  window.define = function(fileName, deps, fn) {
    defined[fileName] = {fileName:fileName, deps: deps, fn:fn};
    var unresolved = deps.filter(function(dep) {
      if(dep === 'exports'){
        return false;
      }
      var resolvedName = resolve(fileName, dep);
      var waiter = wait[resolvedName];

      if(!wait[resolvedName]){
        waiter = wait[resolvedName] = new Wait(resolvedName)
      }
      if(!waiter.ready){
        waiter.wait.push( fileName );
        if( waiter.checkInstantLoad() ){
          wait[ resolvedName ] = new Ready();
        }
      }
      return !wait[resolvedName].ready;
    });
    if(unresolved.length === 0){
      log(fileName, 'deps fullfilled');
      exec(defined[fileName])
    }else{
      log(fileName, 'is waiting for', unresolved);
      var waiter = wait[fileName] = new Wait(fileName);
      for( var i = 0, _i = unresolved.length; i < _i; i++ ){
        var unresolvedElement = unresolved[ i ];
        waiter.wait.push(resolve(fileName, unresolvedElement));
        waiter.resolving++;

      }
    }
  };
})();