package com.karateca.jstoolbox.generatemethod;

import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.ui.components.JBList;
import com.karateca.jstoolbox.MyAction;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.util.List;

/**
 * @author Andres Dominguez
 */
public class OverrideMethodAction extends MyAction {

  private Project project;
  private Editor editor;
  private Document document;
  private ParentNamespaceFinder namespaceFinder;
  private static final String DEFAULT_JS_DOC = "/**\n" +
      " * @override\n" +
      " */";

  @Override
  public void actionPerformed(AnActionEvent actionEvent) {
    if (!canEnableAction(actionEvent)) {
      return;
    }

    project = actionEvent.getData(PlatformDataKeys.PROJECT);
    editor = actionEvent.getData(PlatformDataKeys.EDITOR);
    if (project == null || editor == null) {
      return;
    }
    document = editor.getDocument();

    namespaceFinder = new ParentNamespaceFinder(document, project);

    namespaceFinder.addResultsReadyListener(new ChangeListener() {
      @Override
      public void stateChanged(ChangeEvent changeEvent) {
        if (changeEvent.getSource().equals("ParentNamespaceFound")) {
          // TODO: show not found.
          showDialog();
        }
      }
    });

    namespaceFinder.findParentClass();
  }

  /**
   * Show the dialog to select the method to override.
   */
  private void showDialog() {
    List<Function> functionNames = namespaceFinder.getFunctionNames();

    // Select the closest element found from the current position.
    final JBList jbList = new JBList(functionNames.toArray());

    // Open a pop-up to select which describe() or it() you want to change.
    JBPopupFactory.getInstance()
        .createListPopupBuilder(jbList)
        .setTitle("Select the method to override")
        .setItemChoosenCallback(new Runnable() {
          public void run() {
            if (jbList.getSelectedValue() != null) {
              addNewMethod((Function) jbList.getSelectedValue());
            }
          }
        })
        .createPopup()
        .showCenteredInCurrentWindow(project);
  }

  /**
   * Create a new method that will override the parent.
   *
   * @param function The method that you want ot override.
   */
  private void addNewMethod(Function function) {
    String fnNameFormat = "%s.prototype." + function.getName();
    String methodPrototype = String.format(fnNameFormat, namespaceFinder.getCurrentNamespace());
    String parentMethodPrototype = String.format(fnNameFormat, namespaceFinder.getParentNamespace());

    String jsDoc = function.getJsDoc();
    if (jsDoc == null) {
      jsDoc = DEFAULT_JS_DOC;
    }

    String arguments = function.getArguments();
    String callArguments = arguments;
    if (callArguments.trim().length() > 0) {
      callArguments = ", " + callArguments;
    }

    final String methodTemplate = String.format("%s\n%s = function(%s) {\n" +
        "  %s.call(this%s);\n" +
        "};\n", jsDoc, methodPrototype, arguments, parentMethodPrototype,
        callArguments);

    runWriteActionInsideCommand(project, "Override method", new Runnable() {
      @Override
      public void run() {
        int offset = editor.getCaretModel().getOffset();
        document.replaceString(offset, offset, methodTemplate);
      }
    });
  }
}

@@ -735,118 +735,14 @@
 der 
-namespaceFinder;%0A  private static final String DEFAULT_JS_DOC = %22/**%5Cn%22 +%0A      %22 * @override%5Cn%22 +%0A      %22 */%22
+finder
 ;%0A%0A 
@@ -1096,34 +1096,25 @@
 ent();%0A%0A    
-namespaceF
+f
 inder = new 
@@ -1156,34 +1156,25 @@
 ject);%0A%0A    
-namespaceF
+f
 inder.addRes
@@ -1448,26 +1448,17 @@
 );%0A%0A    
-namespaceF
+f
 inder.fi
@@ -1611,26 +1611,17 @@
 Names = 
-namespaceF
+f
 inder.ge
@@ -2578,34 +2578,25 @@
 NameFormat, 
-namespaceF
+f
 inder.getCur
@@ -2680,18 +2680,9 @@
 at, 
-namespaceF
+f
 inde
@@ -2742,16 +2742,24 @@
 .get
+Extended
 JsDoc();
 %0A   
@@ -2758,69 +2758,8 @@
 c();
-%0A    if (jsDoc == null) %7B%0A      jsDoc = DEFAULT_JS_DOC;%0A    %7D
 %0A%0A  

rename variable. Use get getExtendedJsDoc()