/**
 * Extensions of CFG
 * Created by chengfulin on 2015/4/15.
 */
var esgraph = require('esgraph'),
    esprima = require('esprima'),
    walkes = require('walkes'),
    namespace = require('./namespace'),
    internal = namespace();

/**
 * Extended for CFG build by esgraph
 * @constructor
 */
function CFGExt() {
    'use strict';
    internal(this).lastId = -1;
}

/**
 * Parse the code to AST with default range option
 * @param code source code
 * @returns {*}
 */
CFGExt.prototype.parseAST = function parseAST(code) {
    'use strict';
    return esprima.parse(code, {range: true});
};

/**
 * Get the CFG of the AST
 * @param ast
 * @returns {Array} CFG
 */
CFGExt.prototype.getCFG = function getCFG(ast) {
    'use strict';
    var cfg = esgraph(ast);
    for(var index = 0; index < cfg[2].length; ++index) {
        (cfg[2][index]).cfgId = internal(this).lastId + index + 1;
    }
    internal(this).lastId += cfg[2].length;
    return cfg;
};

/**
 * Find function scopes of AST parsed from source
 * @param ast
 * @returns {Array}
 */
CFGExt.prototype.findScopes = function findScopes(ast) {
    'use strict';
    var scopes = [];
    function handleInnerFunction(astNode, recurse) {
        scopes.push(astNode);
        recurse(astNode.body);
    }

    walkes(ast, {
        Program: function (node, recurse) {
            scopes.push(node);
            node.body.forEach(function (elem) {
                recurse(elem);
            });
        },
        FunctionDeclaration: handleInnerFunction,
        FunctionExpression: handleInnerFunction
    });
    return scopes;
};

/**
 * Convert a CFG to dot language for Graphviz output (with AST node type labeled, default)
 * @param cfg
 * @returns {*|string}
 */
CFGExt.prototype.toDot = function (cfg) {
    'use strict';
    var outputCFG = [].concat(cfg),
        option = {counter: outputCFG[0].cfgId};
    return esgraph.dot(cfg, option);
};

/**
 * Convert a CFG to dot language for Graphviz output (with id labeled)
 * @param cfg
 * @returns {*|string}
 */
CFGExt.prototype.toDotWithLabelId = function (cfg) {
    'use strict';
    var outputCFG = [].concat(cfg),
        option = {counter: outputCFG[0].cfgId};
    outputCFG[2].forEach(function (node) {
        if (!node.type) {
            node.label = node.cfgId;
        }
    });
    return esgraph.dot(cfg, option);
};

/**
 * Utility for resetting the current counter for Id
 */
CFGExt.prototype.resetCounter = function () {
    'use strict';
    internal(this).lastId = -1;
};

var singleTon = new CFGExt();
module.exports = singleTon;
@@ -618,17 +618,45 @@
  the AST
+ with additional information
 %0A
-
  * @para
@@ -784,16 +784,57 @@
 h(ast);%0A
+    /// Add cfgId and label to each node%0A
     for(
@@ -949,25 +949,173 @@
 ex + 1;%0A    
-%7D
+    (cfg%5B2%5D%5Bindex%5D).label = (cfg%5B2%5D%5Bindex%5D).cfgId;%0A    %7D%0A    /// label for entry and exit node%0A    cfg%5B0%5D.label = 'entry';%0A    cfg%5B1%5D.label = 'exit';
 %0A    interna

Add label when get CFG