define(function(require,exports,module){var ASTWalker=brackets.getModule("thirdparty/acorn/dist/walk"),EditorManager=brackets.getModule("editor/EditorManager"),_=brackets.getModule("thirdparty/lodash"),StringUtils=brackets.getModule("utils/StringUtils"),Session=brackets.getModule("JSUtils/Session"),RefactoringUtils=require("RefactoringUtils"),Strings=brackets.getModule("strings"),InlineMenu=brackets.getModule("widgets/InlineMenu").InlineMenu,template=JSON.parse(require("text!Templates.json")),session=null;function analyzeCode(text,scopes,srcScope,destScope,start,end){var identifiers={},inThisScope={},thisPointerUsed=!1,returnStatementUsed=!1,variableDeclarations={},changedValues={},dependentValues={},ast=RefactoringUtils.getAST(text),doc=session.editor.document,restScopeStr;ASTWalker.full(ast,function(node){var value,name;switch(node.type){case"AssignmentExpression":value=node.left;break;case"VariableDeclarator":inThisScope[node.id.name]=!0,value=node.init&&node.id;var variableDeclarationNode=RefactoringUtils.findSurroundASTNode(ast,node,["VariableDeclaration"]);variableDeclarations[node.id.name]=variableDeclarationNode.kind;break;case"ThisExpression":thisPointerUsed=!0;break;case"UpdateExpression":value=node.argument;break;case"Identifier":identifiers[node.name]=!0;break;case"ReturnStatement":returnStatementUsed=!0}value&&(name="MemberExpression"===value.type?value.object.name:value.name,changedValues[name]=!0)}),restScopeStr=srcScope.originNode?doc.getText().substr(end,srcScope.originNode.end-end):doc.getText().substr(end),ASTWalker.simple(RefactoringUtils.getAST(restScopeStr),{Identifier:function(node){var name=node.name;dependentValues[name]=!0},Expression:function(node){if("MemberExpression"===node.type){var name=node.object.name;dependentValues[name]=!0}}});var passProps=scopes.slice(srcScope.id,destScope.id).reduce(function(props,scope){return _.union(props,_.keys(scope.props))},[]),retProps=scopes.slice(srcScope.id,destScope.id+1).reduce(function(props,scope){return _.union(props,_.keys(scope.props))},[]);return{passParams:_.intersection(_.difference(_.keys(identifiers),_.keys(inThisScope)),passProps),retParams:_.intersection(_.keys(changedValues),_.keys(dependentValues),retProps),thisPointerUsed:thisPointerUsed,returnStatementUsed:returnStatementUsed,variableDeclarations:variableDeclarations}}function extract(ast,text,scopes,srcScope,destScope,start,end,isExpression){var retObj=analyzeCode(text,scopes,srcScope,destScope,start,end),passParams=retObj.passParams,retParams=retObj.retParams,thisPointerUsed=retObj.thisPointerUsed,returnStatementUsed=retObj.returnStatementUsed,variableDeclarations=retObj.variableDeclarations,doc=session.editor.document,fnBody=text,fnName=RefactoringUtils.getUniqueIdentifierName(scopes,"extracted"),fnDeclaration,fnCall;function appendVarDeclaration(identifier){return variableDeclarations.hasOwnProperty(identifier)?variableDeclarations[identifier]+" "+identifier:identifier}if(destScope.isClass?fnCall=StringUtils.format(template.functionCall.class,fnName,passParams.join(", ")):thisPointerUsed?(passParams.unshift("this"),fnCall=StringUtils.format(template.functionCall.thisPointer,fnName,passParams.join(", ")),passParams.shift()):fnCall=StringUtils.format(template.functionCall.normal,fnName,passParams.join(", ")),returnStatementUsed&&(fnCall="return "+fnCall),isExpression)fnBody=StringUtils.format(template.returnStatement.single,fnBody);else{var retParamsStr="";retParams.length>1?(retParamsStr=StringUtils.format(template.returnStatement.multiple,retParams.join(", ")),fnCall="var ret = "+fnCall+";\n",fnCall+=retParams.map(function(param){return StringUtils.format(template.assignment,appendVarDeclaration(param),"ret."+param)}).join("\n")):1===retParams.length?(retParamsStr=StringUtils.format(template.returnStatement.single,retParams.join(", ")),fnCall=StringUtils.format(template.assignment,appendVarDeclaration(retParams[0]),fnCall)):fnCall+=";",fnBody=fnBody+"\n"+retParamsStr}fnDeclaration=destScope.isClass?StringUtils.format(template.functionDeclaration.class,fnName,passParams.join(", "),fnBody):StringUtils.format(template.functionDeclaration.normal,fnName,passParams.join(", "),fnBody),start=session.editor.posFromIndex(start),end=session.editor.posFromIndex(end);for(var insertPos=_.clone(start),fnScopes=scopes.filter(RefactoringUtils.isFnScope),i=0;i1)return editor.displayErrorMessageAtCursor(Strings.ERROR_EXTRACTTO_FUNCTION_MULTICURSORS),void result.resolve(Strings.ERROR_EXTRACTTO_FUNCTION_MULTICURSORS);initializeSession(editor);var selection=editor.getSelection(),doc=editor.document,retObj=RefactoringUtils.normalizeText(editor.getSelectedText(),editor.indexFromPos(selection.start),editor.indexFromPos(selection.end)),text=retObj.text,start=retObj.start,end=retObj.end,ast,scopes,expns,inlineMenu;return RefactoringUtils.getScopeData(session,editor.posFromIndex(start)).done(function(scope){ast=RefactoringUtils.getAST(doc.getText());var isExpression=!1;return RefactoringUtils.checkStatement(ast,start,end,doc.getText())||(isExpression=RefactoringUtils.getExpression(ast,start,end,doc.getText()))?1===(scopes=RefactoringUtils.getAllScopes(ast,scope,doc.getText())).length?(extract(ast,text,scopes,scopes[0],scopes[0],start,end,isExpression),void result.resolve()):((inlineMenu=new InlineMenu(editor,Strings.EXTRACTTO_FUNCTION_SELECT_SCOPE)).open(scopes.filter(RefactoringUtils.isFnScope)),result.resolve(inlineMenu),inlineMenu.onSelect(function(scopeId){extract(ast,text,scopes,scopes[0],scopes[scopeId],start,end,isExpression),inlineMenu.close()}),void inlineMenu.onClose(function(){inlineMenu.close()})):(editor.displayErrorMessageAtCursor(Strings.ERROR_EXTRACTTO_FUNCTION_NOT_VALID),void result.resolve(Strings.ERROR_EXTRACTTO_FUNCTION_NOT_VALID))}).fail(function(){editor.displayErrorMessageAtCursor(Strings.ERROR_TERN_FAILED),result.resolve(Strings.ERROR_TERN_FAILED)}),result.promise()}function initializeSession(editor){session=new Session(editor)}exports.handleExtractToFunction=handleExtractToFunction});