var path = require("path");
var util = require("../util");
var b    = require("ast-types").builders;
var _    = require("lodash");

exports.ImportDeclaration = function (node) {
  var nodes = [];

  if (node.specifiers.length) {
    _.each(node.specifiers, function (specifier) {
      var variableName = specifier.name || specifier.id;
      var key          = specifier.id.name;

      // import foo from "foo";
      if (specifier.type === "ImportDefaultSpecifier") {
        key = b.identifier("default");
      }

      var templateName = "require-assign";

      // import * as bar from "foo";
      if (specifier.type !== "ImportNamespaceSpecifier") templateName += "-key";

      nodes.push(util.template(templateName, {
        VARIABLE_NAME: variableName.name,
        MODULE_NAME:   node.source.raw,
        KEY:           key
      }));
    });
  } else {
    nodes.push(util.template("require", {
      MODULE_NAME: node.source.raw
    }, true));
  }

  return nodes;
};

var pushExportSpecifiers = function (node, nodes) {
  _.each(node.specifiers, function (specifier) {
    var variableName = specifier.name || specifier.id;

    if (node.source) {
      if (specifier.type === "ExportBatchSpecifier") {
        nodes.push(util.template("exports-wildcard", {
          MODULE_NAME: node.source.raw
        }, true));
      } else {
        nodes.push(util.template("exports-require-assign-key", {
          VARIABLE_NAME: variableName.name,
          MODULE_NAME:   node.source.raw,
          KEY:           specifier.id
        }, true));
      }
    } else {
      nodes.push(util.template("exports-assign", {
        VALUE: specifier.id,
        KEY:   variableName
      }, true));
    }
  });
};

var pushExportDeclaration = function (node, parent, nodes) {
  var declar = node.declaration;

  if (node.default) {
    if (declar.type === "FunctionDeclaration") {
      declar.type = "FunctionExpression";
    } else if (declar.type === "ClassDeclaration") {
      declar.type = "ClassExpression";
    }

    nodes.push(util.template("exports-default", {
      VALUE: declar
    }, true));
  } else {
    var id = declar.id;
    if (declar.type === "VariableDeclaration") {
      id = declar.declarations[0].id;
    }

    var assign = util.template("exports-assign", {
      VALUE: id,
      KEY:   id
    }, true);

    nodes.push(declar);

    if (declar.type === "FunctionDeclaration") {
      assign._modulesHoist = true;
    }

    nodes.push(assign);
  }
};

exports.Program = {
  exit: function (node) {
    var unshift = [];

    node.body = node.body.filter(function (bodyNode) {
      if (bodyNode._modulesHoist) {
        unshift.push(bodyNode);
        return false;
      } else {
        return true;
      }
    });

    node.body = unshift.concat(node.body);
  }
};

exports.ExportDeclaration = function (node, parent) {
  var nodes = [];

  if (node.declaration) {
    pushExportDeclaration(node, parent, nodes);
  } else {
    pushExportSpecifiers(node, nodes);
  }

  return nodes;
};

@@ -294,33 +294,36 @@
 iableName = 
-s
+getS
 pecifier
 .name %7C%7C spe
@@ -306,33 +306,29 @@
 getSpecifier
-.name %7C%7C 
+Name(
 specifier.id
@@ -325,18 +325,21 @@
 ecifier.
-id
+name)
 ;%0A      
@@ -859,24 +859,45 @@
 %0A  %7D else %7B%0A
+    // import %22foo%22;%0A
     nodes.pu
@@ -1125,25 +1125,28 @@
 eName = 
-s
+getS
 pecifier
 .name %7C%7C
@@ -1141,17 +1141,13 @@
 fier
-.name %7C%7C 
+Name(
 spec
@@ -1151,19 +1151,17 @@
 pecifier
-.id
+)
 ;%0A%0A    i
@@ -1225,32 +1225,64 @@
 chSpecifier%22) %7B%0A
+        // export * from %22foo%22;%0A
         nodes.pu
@@ -1385,32 +1385,71 @@
 %0A      %7D else %7B%0A
+        // export %7B foo %7D from %22test%22;%0A
         nodes.pu
@@ -1657,24 +1657,49 @@
    %7D else %7B%0A
+      // export %7B foo %7D;%0A
       nodes.
@@ -1817,16 +1817,16 @@
 ;%0A    %7D%0A
-
   %7D);%0A%7D;
@@ -1823,24 +1823,115 @@
 %7D%0A  %7D);%0A%7D;%0A%0A
+var getSpecifierName = function (specifier) %7B%0A  return specifier.name %7C%7C specifier.id;%0A%7D;%0A%0A
 var pushExpo

add comments to display what module syntax each part handles