package jetbrains.mps.execution.api.configurations;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import com.intellij.execution.BeforeRunTaskProvider;
import jetbrains.mps.logging.Logger;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import java.lang.reflect.Method;
import jetbrains.mps.internal.collections.runtime.Sequence;
import java.util.Objects;
import java.lang.reflect.InvocationTargetException;
import com.intellij.execution.BeforeRunTask;
import org.jetbrains.annotations.NotNull;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.project.Project;

@GeneratedClass(node = "r:49e72ff8-8ace-42fd-8f9f-5961eed9792e(jetbrains.mps.execution.api.configurations)/7037083547575991021", model = "r:49e72ff8-8ace-42fd-8f9f-5961eed9792e(jetbrains.mps.execution.api.configurations)")
public abstract class BaseMpsBeforeTaskProvider<T extends BaseMpsBeforeTaskProvider.BaseMpsBeforeRunTask<?>> extends BeforeRunTaskProvider<T> {
  private static final Logger LOG = Logger.getLogger(BaseMpsBeforeTaskProvider.class);
  private final String myName;
  private final String myCaption;

  public BaseMpsBeforeTaskProvider(String name, String caption) {
    myName = name;
    myCaption = caption;
  }

  protected abstract T createTaskImpl();

  @Override
  public String getName() {
    return myCaption;
  }

  @Override
  public String getDescription(T task) {
    return myCaption;
  }

  @Override
  public T createTask(RunConfiguration runConfiguration) {
    if (hasExecuteMethod(runConfiguration)) {
      return createTaskImpl();
    }
    return null;
  }

  private boolean hasExecuteMethod(RunConfiguration runConfiguration) {
    try {
      if (getMethod(runConfiguration) != null) {
        return true;
      }
    } catch (NoSuchMethodException e) {
    }
    return false;
  }

  @Override
  public boolean executeTask(DataContext context, RunConfiguration configuration, ExecutionEnvironment env, T task) {
    if (!(configure(configuration, task))) {
      return false;
    }
    try {
      return task.execute(PlatformDataKeys.PROJECT.getData(context), env);
    } catch (Throwable t) {
      if (LOG.isErrorLevel()) {
        LOG.error("Error during executing provider " + (myCaption + "(" + this.getClass().getName() + ")"), t);
      }
    }
    return false;
  }

  private boolean configure(RunConfiguration runConfiguration, T task) {
    try {
      Method method = getMethod(runConfiguration);
      if (method == null) {
        return false;
      }
      Object[] parameters = (Object[]) method.invoke(runConfiguration);
      Method configureMethod = Sequence.fromIterable(Sequence.fromArray(task.getClass().getMethods())).findFirst((it) -> Objects.equals(it.getName(), getConfigureMethodName()));
      return (Boolean) configureMethod.invoke(task, parameters);
    } catch (NoSuchMethodException e) {
    } catch (InvocationTargetException e) {
      if (LOG.isErrorLevel()) {
        LOG.error("", e);
      }
    } catch (IllegalAccessException e) {
      if (LOG.isErrorLevel()) {
        LOG.error("", e);
      }
    } catch (ClassCastException e) {
      if (LOG.isErrorLevel()) {
        LOG.error("", e);
      }
    }
    return false;
  }

  private Method getMethod(RunConfiguration configuration) throws NoSuchMethodException {
    return configuration.getClass().getMethod(getCreateMethodName(myName));
  }

  @Override
  public boolean isConfigurable() {
    return false;
  }

  @Override
  public boolean configureTask(RunConfiguration runConfiguration, T task) {
    return hasExecuteMethod(runConfiguration);
  }

  @Override
  public boolean canExecuteTask(RunConfiguration configuration, T task) {
    return true;
  }

  public static String getCreateMethodName(String name) {
    return "create" + name.replace(" ", "") + "Task";
  }

  public static String getConfigureMethodName() {
    return "configure";
  }

  public static abstract class BaseMpsBeforeRunTask<T extends BaseMpsBeforeRunTask<?>> extends BeforeRunTask<T> {
    public BaseMpsBeforeRunTask(@NotNull Key<T> providerId) {
      super(providerId);
      setEnabled(true);
    }

    public abstract boolean execute(Project project, ExecutionEnvironment environment);
  }
}
