// Imports
// -------------------------------------------------------------------------------------------------

var pluck = require('101/pluck');
var AMDFormatter = require('6to5/lib/6to5/transformation/modules/amd');
var t = require('6to5/lib/6to5/types');
var util = require('6to5/lib/6to5/util');
var asArray = require('as/array');
var basename = require('basename');

var template = require('./template');


// Main
// -------------------------------------------------------------------------------------------------

// Extend AMDFormatter.
var self = function SixToLibrary () {
  AMDFormatter.apply(this, arguments);
  this.globalExportId = t.toIdentifier(basename(this.file.opts.filename));
  this.globalImportIds = {};
  };
util.inherits(self, AMDFormatter);


// Override the method `transform`.
self.prototype.transform = function (ast) {
  var moduleName;
  var program = ast.program;
  var body = program.body;
  var globalImportIds = this.globalImportIds;

  // Parse module names.
  var ids = asArray(this.ids);
  var importIds = ids.map(function (id) {
    return globalImportIds[id.key];
    });
  var importLocations = ids.map(function (id) {
    return t.literal(id.key);
    });

  // Create the factory.
  var factory = t.functionExpression
    ( null
    , [t.identifier('exports')].concat(ids.map(pluck('value')))
    , t.blockStatement(body)
    );

  // Create the runner.
  var runner = template('runner-body',
    { AMD_ARGUMENTS: [t.arrayExpression(
        [].concat( (moduleName = this.getModuleName())
                 ? t.literal(moduleName)
                 : []
                 )
          .concat(t.literal('exports'))
          .concat(importLocations)
        )]
    , COMMON_ARGUMENTS: importLocations.map(function (name) {
        return t.callExpression(t.identifier('require'), [name]);
        })
    , GLOBAL_EXPORTS: [template('global-exports',
        { EXPORTS_NAMESPACE: t.identifier(this.globalExportId)
        })]
    , GLOBAL_IMPORTS: importIds
    });

  // Finish off.
  var call = t.callExpression(runner, [t.thisExpression(), factory]);
  program.body = [t.expressionStatement(call)];
  };


// Override the method `importDeclaration`.
self.prototype.importDeclaration = function (declaration) {
  // Add the import's specifier.
  this._pushSpecifier(declaration);

  // Apply the super method.
  AMDFormatter.prototype.importDeclaration.apply(this, arguments);
  };


// Override the method `importSpecifier`.
self.prototype.importSpecifier = function (specifier, declaration) {
  // Add the import's specifier.
  this._pushSpecifier(declaration, specifier);

  // Apply the super method.
  AMDFormatter.prototype.importSpecifier.apply(this, arguments);
  };


self.prototype._pushSpecifier = function (declaration, specifier) {
  var name = declaration.source.value;
  var ids = this.globalImportIds;

  if (!ids[name]) ids[name] = template('global-import',
    { IMPORT_IDENTIFIER: t.identifier(t.toIdentifier(
      (  specifier && specifier.default && specifier.id && specifier.id.name
      || name
      )))
    });
  return ids[name];
  };


// Export
// -------------------------------------------------------------------------------------------------

module.exports = self;

@@ -106,16 +106,49 @@
 ------%0A%0A
+var nodeUtil = require('util');%0A%0A
 var pluc
@@ -735,30 +735,24 @@
 this.globalI
-mportI
 ds = %7B%7D;%0A  %7D
@@ -950,29 +950,26 @@
 ;%0A  var 
-g
+rawG
 lobalI
-mportI
 ds = thi
@@ -973,30 +973,24 @@
 this.globalI
-mportI
 ds;%0A%0A  // Pa
@@ -1044,22 +1044,22 @@
 ;%0A  var 
-import
+global
 Ids = id
@@ -1088,22 +1088,19 @@
     
-return
+var
  globalI
 mpor
@@ -1099,24 +1099,141 @@
 balI
-mportIds%5Bid.key%5D
+d = rawGlobalIds%5Bid.key%5D;%0A    if (!globalId) throw new Error ('No specifier found for the id %22' + id.key + '%22.');%0A    return globalId
 ;%0A  
@@ -2112,22 +2112,22 @@
 MPORTS: 
-import
+global
 Ids%0A    
@@ -2414,36 +2414,43 @@
 er.%0A  this._push
-Spec
+GlobalIdent
 ifier(declaratio
@@ -2709,28 +2709,35 @@
   this._push
-Spec
+GlobalIdent
 ifier(declar
@@ -2861,113 +2861,855 @@
 ;%0A%0A%0A
-self.prototype._pushSpecifier = function (declaration, specifier) %7B%0A  var name = declaration.source.value
+// Override the method %60exportSpecifier%60.%0Aself.prototype.exportSpecifier = function (specifier, declaration) %7B%0A  // Add the export's specifier.%0A  this._pushGlobalIdentifier(declaration, specifier);%0A%0A  // Apply the super method.%0A  AMDFormatter.prototype.exportSpecifier.apply(this, arguments);%0A  %7D;%0A%0A%0Aself.prototype._pushGlobalIdentifier = function (declaration, specifier) %7B%0A  var name =%0A    (  specifier && specifier.default && specifier.id && specifier.id.name%0A    %7C%7C specifier && specifier.type == %22ExportSpecifier%22 && specifier.id && specifier.id.name%0A    %7C%7C declaration.source && declaration.source.value%0A    %7C%7C null%0A    );%0A  if (name === null) throw new Error%0A    ( %22Unable to resolve global identifier %22%0A    + %22for the declaration:%5Cn%22 + nodeUtil.inspect(declaration) + %22%5Cn%22%0A    + %22and specifier:%5Cn%22 + nodeUtil.inspect(specifier) + %22.%22%0A    )
 ;%0A  
@@ -3734,14 +3734,8 @@
 balI
-mportI
 ds;%0A
@@ -3770,25 +3770,25 @@
  = template(
-'
+%22
 global-impor
@@ -3788,17 +3788,17 @@
 l-import
-'
+%22
 ,%0A    %7B 
@@ -3848,107 +3848,12 @@
 ier(
-%0A      (  specifier && specifier.default && specifier.id && specifier.id.name%0A      %7C%7C name%0A      )
+name
 ))%0A 

Fix export specifiers