<commit_before>package com.intellij.tasks.mantis;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.KeyValue;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.tasks.Task;
import com.intellij.tasks.TaskBundle;
import com.intellij.tasks.TaskRepositoryType;
import com.intellij.tasks.impl.BaseRepository;
import com.intellij.tasks.impl.BaseRepositoryImpl;
import com.intellij.tasks.mantis.model.*;
import com.intellij.util.Function;
import com.intellij.util.NullableFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.net.HttpConfigurable;
import com.intellij.util.proxy.JavaProxyProperty;
import com.intellij.util.text.VersionComparatorUtil;
import com.intellij.util.xmlb.annotations.Tag;
import org.apache.axis.AxisFault;
import org.apache.axis.AxisProperties;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.math.BigInteger;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.intellij.tasks.actions.GotoTaskAction.PAGE_SIZE;

/**
 * @author <NAME>
 */
@Tag("Mantis")
public class MantisRepository extends BaseRepositoryImpl {

  private static final boolean DEBUG_ALL_PROJECTS = Boolean.getBoolean("tasks.mantis.debug.all.projects");
  private static final String SOAP_API_LOCATION = "/api/soap/mantisconnect.php";
  private static final Pattern ID_PATTERN = Pattern.compile("\\d+");

  private static final Logger LOG = Logger.getInstance(MantisRepository.class);

  // Projects fetched from server last time is cached, so workaround for IDEA-105413 could work.
  private List<MantisProject> myProjects = null;
  // It means that special pseudo-project "All Projects" is supported on server side.
  // false if Mantis version < 1.2.9, because of http://www.mantisbt.org/bugs/view.php?id=13526
  private boolean myAllProjectsAvailable = true;

  private MantisProject myCurrentProject;
  private MantisFilter myCurrentFilter;

  @SuppressWarnings({"UnusedDeclaration"})
  public MantisRepository() {
    // empty
  }

  public MantisRepository(TaskRepositoryType type) {
    super(type);
  }

  public MantisRepository(MantisRepository other) {
    super(other);
    myCurrentProject = other.getCurrentProject();
    myCurrentFilter = other.getCurrentFilter();
    myProjects = other.myProjects;
    // deep copy isn't needed because, new list will be assigned to field on update in configurable
    myAllProjectsAvailable = other.myAllProjectsAvailable;
  }

  @NotNull
  @Override
  public BaseRepository clone() {
    return new MantisRepository(this);
  }

  @Nullable
  @Override
  public String extractId(@NotNull String taskName) {
    Matcher matcher = ID_PATTERN.matcher(taskName);
    return matcher.find() ? matcher.group() : null;
  }

  @Override
  public Task[] getIssues(@Nullable String query, int offset, int limit, boolean withClosed, @NotNull ProgressIndicator cancelled)
    throws Exception {
    if (myCurrentProject == null || myCurrentFilter == null) {
      throw new Exception(TaskBundle.message("failure.configuration"));
    }
    ensureProjectsRefreshed();
    MantisConnectPortType soap = createSoap();

    List<Task> tasks = new ArrayList<Task>(limit);

    int pageNumber = offset / PAGE_SIZE + 1;
    // what the heck does it suppose to mean?
    while (tasks.size() < limit) {
      cancelled.checkCanceled();
      int pageSize = Math.min(PAGE_SIZE, limit - tasks.size());
      List<Task> issuesFromPage = getIssuesFromPage(soap, pageNumber, pageSize);
      tasks.addAll(issuesFromPage);
      if (issuesFromPage.size() < pageSize) {
        break;
      }
      pageNumber++;
    }
    return tasks.toArray(new Task[tasks.size()]);
  }

  private List<Task> getIssuesFromPage(@NotNull MantisConnectPortType soap, int pageNumber, int pageSize) throws Exception {
    List<IssueHeaderData> collectedHeaders = new ArrayList<IssueHeaderData>();
    boolean isWorkaround = myCurrentProject.isUnspecified() && !myAllProjectsAvailable;
    // Projects to iterate over, actually needed only when "All Projects" pseudo-project is selected
    // and is unsupported on server side.
    List<MantisProject> projects = isWorkaround ? myProjects : Collections.singletonList(myCurrentProject);
    for (MantisProject project : projects) {
      if (isWorkaround && project.isUnspecified()) {
        continue;
      }
      assert !project.isUnspecified() || myAllProjectsAvailable;
      IssueHeaderData[] headers = fetchProjectIssues(soap, project, myCurrentFilter, pageNumber, pageSize);
      ContainerUtil.addAll(collectedHeaders, headers);
    }
    return ContainerUtil.mapNotNull(collectedHeaders, new NullableFunction<IssueHeaderData, Task>() {
      public Task fun(IssueHeaderData issueData) {
        if (issueData.getId() == null || issueData.getSummary() == null) {
          return null;
        }
        return new MantisTask(issueData, MantisRepository.this);
      }
    });
  }

  @Nullable
  @Override
  public Task findTask(@NotNull String id) throws Exception {
    IssueData data = fetchIssueById(createSoap(), id);
    // sanity check
    if (data == null || data.getId() == null || data.getSummary() == null) {
      return null;
    }
    return new MantisTask(data, this);
  }

  @Nullable
  @Override
  public CancellableConnection createCancellableConnection() {
    return new CancellableConnection() {
      @Override
      protected void doTest() throws Exception {
        myProjects = null;
        try {
          createSoap().mc_enum_access_levels(getUsername(), getPassword());
        }
        catch (Exception e) {
          throw handleException(e);
        }
      }

      @Override
      public void cancel() {
      }
    };
  }

  @NotNull
  public List<MantisProject> getProjects() throws Exception {
    ensureProjectsRefreshed();
    return myProjects == null ? Collections.<MantisProject>emptyList() : myProjects;
  }

  private void ensureProjectsRefreshed() throws Exception {
    if (myProjects == null) {
      refreshProjects();
    }<commit_msg>Fetch Mantis projects and filters on test connection (workaround for support 38685)<commit_after>package com.intellij.tasks.mantis;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.KeyValue;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.tasks.Task;
import com.intellij.tasks.TaskBundle;
import com.intellij.tasks.TaskRepositoryType;
import com.intellij.tasks.impl.BaseRepository;
import com.intellij.tasks.impl.BaseRepositoryImpl;
import com.intellij.tasks.mantis.model.*;
import com.intellij.util.Function;
import com.intellij.util.NullableFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.net.HttpConfigurable;
import com.intellij.util.proxy.JavaProxyProperty;
import com.intellij.util.text.VersionComparatorUtil;
import com.intellij.util.xmlb.annotations.Tag;
import org.apache.axis.AxisFault;
import org.apache.axis.AxisProperties;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.math.BigInteger;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.intellij.tasks.actions.GotoTaskAction.PAGE_SIZE;

/**
 * @author <NAME>
 */
@Tag("Mantis")
public class MantisRepository extends BaseRepositoryImpl {

  private static final boolean DEBUG_ALL_PROJECTS = Boolean.getBoolean("tasks.mantis.debug.all.projects");
  private static final String SOAP_API_LOCATION = "/api/soap/mantisconnect.php";
  private static final Pattern ID_PATTERN = Pattern.compile("\\d+");

  private static final Logger LOG = Logger.getInstance(MantisRepository.class);

  // Projects fetched from server last time is cached, so workaround for IDEA-105413 could work.
  private List<MantisProject> myProjects = null;
  // It means that special pseudo-project "All Projects" is supported on server side.
  // false if Mantis version < 1.2.9, because of http://www.mantisbt.org/bugs/view.php?id=13526
  private boolean myAllProjectsAvailable = true;

  private MantisProject myCurrentProject;
  private MantisFilter myCurrentFilter;

  @SuppressWarnings({"UnusedDeclaration"})
  public MantisRepository() {
    // empty
  }

  public MantisRepository(TaskRepositoryType type) {
    super(type);
  }

  public MantisRepository(MantisRepository other) {
    super(other);
    myCurrentProject = other.getCurrentProject();
    myCurrentFilter = other.getCurrentFilter();
    myProjects = other.myProjects;
    // deep copy isn't needed because, new list will be assigned to field on update in configurable
    myAllProjectsAvailable = other.myAllProjectsAvailable;
  }

  @NotNull
  @Override
  public BaseRepository clone() {
    return new MantisRepository(this);
  }

  @Nullable
  @Override
  public String extractId(@NotNull String taskName) {
    Matcher matcher = ID_PATTERN.matcher(taskName);
    return matcher.find() ? matcher.group() : null;
  }

  @Override
  public Task[] getIssues(@Nullable String query, int offset, int limit, boolean withClosed, @NotNull ProgressIndicator cancelled)
    throws Exception {
    if (myCurrentProject == null || myCurrentFilter == null) {
      throw new Exception(TaskBundle.message("failure.configuration"));
    }
    ensureProjectsRefreshed();
    MantisConnectPortType soap = createSoap();

    List<Task> tasks = new ArrayList<Task>(limit);

    int pageNumber = offset / PAGE_SIZE + 1;
    // what the heck does it suppose to mean?
    while (tasks.size() < limit) {
      cancelled.checkCanceled();
      int pageSize = Math.min(PAGE_SIZE, limit - tasks.size());
      List<Task> issuesFromPage = getIssuesFromPage(soap, pageNumber, pageSize);
      tasks.addAll(issuesFromPage);
      if (issuesFromPage.size() < pageSize) {
        break;
      }
      pageNumber++;
    }
    return tasks.toArray(new Task[tasks.size()]);
  }

  private List<Task> getIssuesFromPage(@NotNull MantisConnectPortType soap, int pageNumber, int pageSize) throws Exception {
    List<IssueHeaderData> collectedHeaders = new ArrayList<IssueHeaderData>();
    boolean isWorkaround = myCurrentProject.isUnspecified() && !myAllProjectsAvailable;
    // Projects to iterate over, actually needed only when "All Projects" pseudo-project is selected
    // and is unsupported on server side.
    List<MantisProject> projects = isWorkaround ? myProjects : Collections.singletonList(myCurrentProject);
    for (MantisProject project : projects) {
      if (isWorkaround && project.isUnspecified()) {
        continue;
      }
      assert !project.isUnspecified() || myAllProjectsAvailable;
      IssueHeaderData[] headers = fetchProjectIssues(soap, project, myCurrentFilter, pageNumber, pageSize);
      ContainerUtil.addAll(collectedHeaders, headers);
    }
    return ContainerUtil.mapNotNull(collectedHeaders, new NullableFunction<IssueHeaderData, Task>() {
      public Task fun(IssueHeaderData issueData) {
        if (issueData.getId() == null || issueData.getSummary() == null) {
          return null;
        }
        return new MantisTask(issueData, MantisRepository.this);
      }
    });
  }

  @Nullable
  @Override
  public Task findTask(@NotNull String id) throws Exception {
    IssueData data = fetchIssueById(createSoap(), id);
    // sanity check
    if (data == null || data.getId() == null || data.getSummary() == null) {
      return null;
    }
    return new MantisTask(data, this);
  }

  @Nullable
  @Override
  public CancellableConnection createCancellableConnection() {
    return new CancellableConnection() {
      @Override
      protected void doTest() throws Exception {
        myProjects = null;
        try {
          refreshProjects();
        }
        catch (Exception e) {
          throw handleException(e);
        }
      }

      @Override
      public void cancel() {
      }
    };
  }

  @NotNull
  public List<MantisProject> getProjects() throws Exception {
    ensureProjectsRefreshed();
    return myProjects == null ? Collections.<MantisProject>emptyList() : myProjects;
  }

  private void ensureProjectsRefreshed() throws Exception {
    if (myProjects == null) {
      refreshProjects();
    }
{'fraction_non_alphanumeric': 0.1020619377438102, 'fraction_numerical': 0.002786402356500279, 'mean_word_length': 3.992845786963434, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4232838', 'n_tokens_mistral': 3725, 'n_tokens_neox': 3588, 'n_words': 866}