/**
 * Requires parentheses around immediately invoked function expressions.
 *
 * Type: `Boolean`
 *
 * Values: `true`
 *
 * JSHint: [`immed`](http://www.jshint.com/docs/options/#immed)
 *
 * #### Example
 *
 * ```js
 * "requireParenthesesAroundIIFE": true
 * ```
 *
 * ##### Valid
 *
 * ```js
 * var a = (function(){ return 1; })();
 * var b = (function(){ return 2; }());
 * var c = (function(){ return 3; }).call(this, arg1);
 * var d = (function(){ return 3; }.call(this, arg1));
 * var e = (function(){ return d; }).apply(this, args);
 * var f = (function(){ return d; }.apply(this, args));
 * ```
 *
 * ##### Invalid
 *
 * ```js
 * var a = function(){ return 1; }();
 * var c = function(){ return 3; }.call(this, arg1);
 * var d = function(){ return d; }.apply(this, args);
 * ```
 */

var assert = require('assert');

module.exports = function() {};

module.exports.prototype = {

    configure: function(requireParenthesesAroundIIFE) {
        assert(
            typeof requireParenthesesAroundIIFE === 'boolean',
            'requireParenthesesAroundIIFE option requires boolean value'
        );
        assert(
            requireParenthesesAroundIIFE === true,
            'requireParenthesesAroundIIFE option requires true value or should be removed'
        );
    },

    getOptionName: function() {
        return 'requireParenthesesAroundIIFE';
    },

    check: function(file, errors) {

        function isWrapped(node) {
            var openParensToken = file.getPrevToken(file.getFirstNodeToken(node));

            var closingParensToken = file.getNextToken(file.getLastNodeToken(node));
            var closingTokenValue = closingParensToken ? closingParensToken.value : '';

            return openParensToken.value + closingTokenValue === '()';
        }

        file.iterateNodesByType('CallExpression', function(node) {
            var callee = node.callee;
            var outer = node;
            var inner;

            if (callee.type === 'MemberExpression' &&
                callee.object.type === 'FunctionExpression' &&
                callee.property.type === 'Identifier' &&
                (callee.property.name === 'call' || callee.property.name === 'apply')
            ) {
                inner = callee.object;
            } else if (callee.type === 'FunctionExpression') {
                inner = callee;
            } else {
                return;
            }

            if (!isWrapped(inner) && !isWrapped(outer)) {
                errors.add(
                    'Wrap immediately invoked function expressions in parentheses',
                    node.loc.start.line,
                    node.loc.start.column
                );

            }
        });
    }

};

@@ -817,16 +817,49 @@
 ssert');
+%0Avar utils = require('../utils');
 %0A%0Amodule
@@ -1897,570 +1897,79 @@
 var 
-callee = node.callee;%0A            var outer = node;%0A            var inner;%0A%0A            if (callee.type === 'MemberExpression' &&%0A                callee.object.type === 'FunctionExpression' &&%0A                callee.property.type === 'Identifier' &&%0A                (callee.property.name === 'call' %7C%7C callee.property.name === 'apply')%0A            ) %7B%0A                inner = callee.object;%0A            %7D else if (callee.type === 'FunctionExpression') %7B%0A                inner = callee;%0A            %7D else %7B%0A                return;%0A            %7D%0A%0A            if (
+inner = utils.getFunctionNodeFromIIFE(node);%0A%0A            if (inner && 
 !isW
@@ -2000,13 +2000,12 @@
 ped(
-outer
+node
 )) %7B

use utils methods for IIFE detection