<commit_before>/*******************************************************************************
 * Copyright (c) 2006-2008 VecTrace (<NAME>) and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Software Balm Consulting Inc (<NAME> <peter_hge at softwarebalm dot com>) - implementation
 *     <NAME>          - logError
 *     <NAME>              - storing in plain text instead of serializing Java Objects
 *     <NAME>           - support for project specific repository locations
 *     <NAME> (Intland)     - bug fixes
 *     <NAME> (Intland) - bug fixes
 *******************************************************************************/
package com.vectrace.MercurialEclipse.storage;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.preference.IPreferenceStore;

import com.vectrace.MercurialEclipse.MercurialEclipsePlugin;
import com.vectrace.MercurialEclipse.commands.HgPathsClient;
import com.vectrace.MercurialEclipse.exception.HgException;
import com.vectrace.MercurialEclipse.model.HgRoot;
import com.vectrace.MercurialEclipse.model.IHgRepositoryLocation;
import com.vectrace.MercurialEclipse.repository.IRepositoryListener;
import com.vectrace.MercurialEclipse.team.MercurialTeamProvider;
import com.vectrace.MercurialEclipse.utils.ResourceUtils;
import com.vectrace.MercurialEclipse.utils.StringUtils;

/**
 * A manager for all Mercurial repository locations.
 * <p>
 * Initially, all the data was stored in the file system and was project based. One file per project
 * plus one file for all repositories. This lead to unneeded overhead/complexity for the case where
 * 100 projects under the same root was managed with 100 files with redundant or partly different
 * information.
 * <p>
 * Right now the data stored in the plugin preferences and is hg root based. The repo data is stored
 * twice: once the default repo for each hg root (if any) and secondly as a list of all available
 * repositories.
 * <p>
 * Repositories are considered unique by comparing their URL's (without the login info). Hg roots
 * are considered unique by their absolut hg root paths. Projects are not tracked here anymore, as
 * they always inherit hg root account/repo information.
 * <p>
 * Additionally, we store default commit names for each hg root, which may be different to the hg
 * push/pull user names. The reason is that commit name (like '<EMAIL>') may be same for
 * different repositories, but the 'push' user name must be different due the different account
 * names which may exist for different repositories (like 'hgeclipse' or 'iloveeclipse' for
 * bitbucket or javaforge). See {@link HgCommitMessageManager}.
 * <p>
 *
 */
public class HgRepositoryLocationManager {

	private static final String KEY_REPOS_PREFIX = "repo_"; //$NON-NLS-1$
	private static final String KEY_DEF_REPO_PREFIX = "def_" + KEY_REPOS_PREFIX; //$NON-NLS-1$

	private final Map<HgRoot, SortedSet<IHgRepositoryLocation>> rootRepos;
	private final SortedSet<IHgRepositoryLocation> repoHistory;
	private final HgRepositoryLocationParserDelegator delegator;
	private final Object entriesLock;

	private volatile boolean initialized;
	private final List<IRepositoryListener> repositoryListeners;

	public HgRepositoryLocationManager() {
		super();
		entriesLock = new Object();
		repositoryListeners = new ArrayList<IRepositoryListener>();
		rootRepos = new ConcurrentHashMap<HgRoot, SortedSet<IHgRepositoryLocation>>();
		repoHistory = new TreeSet<IHgRepositoryLocation>();
		delegator = new HgRepositoryLocationParserDelegator();
	}

	/**
	 * Load all saved repository locations from the plug-in's default area.
	 *
	 * @throws HgException
	 */
	public void start() throws HgException {
		getProjectRepos();
	}

	/**
	 * Flush all repository locations out to a file in the plug-in's default
	 * area.
	 */
	public void stop() {
		saveProjectRepos();
		saveRepositoryHistory();
	}

	/**
	 * Return an ordered list of all repository locations that are presently
	 * known.
	 */
	public SortedSet<IHgRepositoryLocation> getAllRepoLocations() {
		SortedSet<IHgRepositoryLocation> allRepos = new TreeSet<IHgRepositoryLocation>();
		rootRepos.keySet();
		synchronized (entriesLock){
			for (SortedSet<IHgRepositoryLocation> locations : rootRepos.values()) {
				allRepos.addAll(locations);
			}
		}
		synchronized (repoHistory) {
			allRepos.addAll(repoHistory);
		}
		return allRepos;
	}

	public SortedSet<HgRoot> getAllRepoRoots() {
		SortedSet<HgRoot> allRoots = new TreeSet<HgRoot>();
		synchronized (entriesLock) {
			allRoots.addAll(rootRepos.keySet());
		}
		return allRoots;
	}


	public SortedSet<IHgRepositoryLocation> getAllRepoLocations(HgRoot hgRoot) {
		if(hgRoot == null){
			return new TreeSet<IHgRepositoryLocation>();
		}
		SortedSet<IHgRepositoryLocation> loc = rootRepos.get(hgRoot);
		if(loc != null) {
			return Collections.unmodifiableSortedSet(loc);
		}
		return new TreeSet<IHgRepositoryLocation>();
	}

	/**
	 * @param repo non null repo location
	 * @return a set of projects we know managed at given location, never null
	 */
	public Set<IProject> getAllRepoLocationProjects(IHgRepositoryLocation repo) {
		Set<IProject> projects = new HashSet<IProject>();<commit_msg>#13028 TODO added<commit_after>/*******************************************************************************
 * Copyright (c) 2006-2008 VecTrace (Zingo Andersen) and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Software Balm Consulting Inc (<NAME> <peter_hge at softwarebalm dot com>) - implementation
 *     <NAME>          - logError
 *     <NAME>              - storing in plain text instead of serializing Java Objects
 *     <NAME>           - support for project specific repository locations
 *     <NAME> (Intland)     - bug fixes
 *     <NAME> (Intland) - bug fixes
 *******************************************************************************/
package com.vectrace.MercurialEclipse.storage;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.preference.IPreferenceStore;

import com.vectrace.MercurialEclipse.MercurialEclipsePlugin;
import com.vectrace.MercurialEclipse.commands.HgPathsClient;
import com.vectrace.MercurialEclipse.exception.HgException;
import com.vectrace.MercurialEclipse.model.HgRoot;
import com.vectrace.MercurialEclipse.model.IHgRepositoryLocation;
import com.vectrace.MercurialEclipse.repository.IRepositoryListener;
import com.vectrace.MercurialEclipse.team.MercurialTeamProvider;
import com.vectrace.MercurialEclipse.utils.ResourceUtils;
import com.vectrace.MercurialEclipse.utils.StringUtils;

/**
 * A manager for all Mercurial repository locations.
 * <p>
 * Initially, all the data was stored in the file system and was project based. One file per project
 * plus one file for all repositories. This lead to unneeded overhead/complexity for the case where
 * 100 projects under the same root was managed with 100 files with redundant or partly different
 * information.
 * <p>
 * Right now the data stored in the plugin preferences and is hg root based. The repo data is stored
 * twice: once the default repo for each hg root (if any) and secondly as a list of all available
 * repositories.
 * <p>
 * Repositories are considered unique by comparing their URL's (without the login info). Hg roots
 * are considered unique by their absolut hg root paths. Projects are not tracked here anymore, as
 * they always inherit hg root account/repo information.
 * <p>
 * Additionally, we store default commit names for each hg root, which may be different to the hg
 * push/pull user names. The reason is that commit name (like '<EMAIL>') may be same for
 * different repositories, but the 'push' user name must be different due the different account
 * names which may exist for different repositories (like 'hgeclipse' or 'iloveeclipse' for
 * bitbucket or javaforge). See {@link HgCommitMessageManager}.
 * <p>
 *
 */
public class HgRepositoryLocationManager {

	private static final String KEY_REPOS_PREFIX = "repo_"; //$NON-NLS-1$
	private static final String KEY_DEF_REPO_PREFIX = "def_" + KEY_REPOS_PREFIX; //$NON-NLS-1$

	private final Map<HgRoot, SortedSet<IHgRepositoryLocation>> rootRepos;
	private final SortedSet<IHgRepositoryLocation> repoHistory;
	private final HgRepositoryLocationParserDelegator delegator;
	private final Object entriesLock;

	private volatile boolean initialized;
	private final List<IRepositoryListener> repositoryListeners;

	public HgRepositoryLocationManager() {
		super();
		entriesLock = new Object();
		repositoryListeners = new ArrayList<IRepositoryListener>();
		rootRepos = new ConcurrentHashMap<HgRoot, SortedSet<IHgRepositoryLocation>>();
		repoHistory = new TreeSet<IHgRepositoryLocation>();
		delegator = new HgRepositoryLocationParserDelegator();
	}

	/**
	 * Load all saved repository locations from the plug-in's default area.
	 *
	 * @throws HgException
	 */
	public void start() throws HgException {
		getProjectRepos();
	}

	/**
	 * Flush all repository locations out to a file in the plug-in's default
	 * area.
	 */
	public void stop() {
		saveProjectRepos();
		saveRepositoryHistory();
	}

	/**
	 * Return an ordered list of all repository locations that are presently
	 * known.
	 */
	public SortedSet<IHgRepositoryLocation> getAllRepoLocations() {
		SortedSet<IHgRepositoryLocation> allRepos = new TreeSet<IHgRepositoryLocation>();
		rootRepos.keySet();
		synchronized (entriesLock){
			for (SortedSet<IHgRepositoryLocation> locations : rootRepos.values()) {
				allRepos.addAll(locations);
			}
		}
		synchronized (repoHistory) {
			allRepos.addAll(repoHistory);
		}
		return allRepos;
	}

	// TODO ME doesn't update rootRepos map until workbench restart.
	// Map should be updated after every clone operation
	public SortedSet<HgRoot> getAllRepoRoots() {
		SortedSet<HgRoot> allRoots = new TreeSet<HgRoot>();
		synchronized (entriesLock) {
			allRoots.addAll(rootRepos.keySet());
		}
		return allRoots;
	}


	public SortedSet<IHgRepositoryLocation> getAllRepoLocations(HgRoot hgRoot) {
		if(hgRoot == null){
			return new TreeSet<IHgRepositoryLocation>();
		}
		SortedSet<IHgRepositoryLocation> loc = rootRepos.get(hgRoot);
		if(loc != null) {
			return Collections.unmodifiableSortedSet(loc);
		}
		return new TreeSet<IHgRepositoryLocation>();
	}

	/**
	 * @param repo non null repo location
	 * @return a set of projects we know managed at given location, never null
	 */
	public Set<IProject> getAllRepoLocationProjects(IHgRepositoryLocation repo) {
		Set<IProject> projects = new HashSet<IProject>();
{'fraction_non_alphanumeric': 0.11223805532271584, 'fraction_numerical': 0.0037720033528918693, 'mean_word_length': 4.82568359375, 'pattern_counts': {'":': 0, '<': 74, '<?xml version=': 0, '>': 74, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, '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': '984523', 'n_tokens_mistral': 3625, 'n_tokens_neox': 3345, 'n_words': 1061}