content: package tim.prune.gui.map;
  
  import java.util.ArrayList;
  
  
  /**
   * Class to hold a library for all the map sources
   * and provide access to each one
   */
  public abstract class MapSourceLibrary
  {
  	/** list of map sources */
  	private static ArrayList<MapSource> _sourceList = null;
  	/** Number of fixed sources */
  	private static int _numFixedSources = 0;
  
  	/**
  	 * @param inConfigString string describing extra sources
  	 */
  	public static void init(String inConfigString)
  	{
  		_sourceList = new ArrayList<>();
  		addFixedSources();
  		_numFixedSources = _sourceList.size();
  		addConfigSources(inConfigString);
  	}
  
  	/** Private constructor to block instantiation */
  	private MapSourceLibrary() {}
  
  
  	/** @return number of fixed sources which shouldn't be deleted */
  	public static int getNumFixedSources() {
  		return _numFixedSources;
  	}
  
  	/**
  	 * Initialise source list by adding bare minimum
  	 */
  	private static void addFixedSources()
  	{
  		_sourceList.add(new OsmMapSource("Mapnik", "https://tile.openstreetmap.org/"));
  		_sourceList.add(new OsmMapSource("Cycling Trails", "https://tile.openstreetmap.org/", "png",
  			"https://tile.waymarkedtrails.org/cycling/", "png", 18));
  		_sourceList.add(new OsmMapSource("Reitkarte", "http://topo[234].wanderreitkarte.de/topo/"));
  		_sourceList.add(new OsmMapSource("Mapsforfree", "https://maps-for-free.com/layer/relief/z{z}/row{y}/{z}_{x}-{y}.jpg", "jpg",
  			"https://maps-for-free.com/layer/water/z{z}/row{y}/{z}_{x}-{y}.gif", "gif", 11));
  		_sourceList.add(new OsmMapSource("OpenTopoMap", "https://[abc].tile.opentopomap.org", "png", 17));
  		_sourceList.add(new OsmMapSource("OpenSeaMap", "http://tile.openstreetmap.org/",
  			"http://tiles.openseamap.org/seamark/", 18));
  	}
  
  	/**
  	 * Add custom sources from Config to the library
  	 * @param inConfigString string describing custom sources
  	 */
  	private static void addConfigSources(String inConfigString)
  	{
  		if (inConfigString != null && inConfigString.length() > 10)
  		{
  			// Loop over sources in string, separated by vertical bars
  			int splitPos = inConfigString.indexOf('|');
  			while (splitPos > 0)
  			{
  				String sourceString = inConfigString.substring(0, splitPos);
  				MapSource source = OsmMapSource.fromConfig(sourceString);
  				if (source != null) {
  					_sourceList.add(source);
  				}
  				inConfigString = inConfigString.substring(splitPos+1);
  				splitPos = inConfigString.indexOf('|');
  			}
  		}
  	}
  
  	/**
  	 * @return current number of sources
  	 */
  	public static int getNumSources() {
  		return _sourceList.size();
  	}
  
  	/**
  	 * Add the given MapSource to the list (at the end)
  	 * @param inSource MapSource object
  	 */
  	public static void addSource(MapSource inSource) {
  		// Check whether source is already there?  Check whether valid?
  		_sourceList.add(inSource);
  	}
  
  	/**
  	 * Edit the given MapSource object by replacing with a new one
  	 * @param inOriginal existing MapSource object
  	 * @param inNewSource new MapSource object
  	 */
  	public static void editSource(MapSource inOriginal, MapSource inNewSource)
  	{
  		// Check whether original source is still there
  		int origPos = _sourceList.indexOf(inOriginal);
  		if (origPos < 0) {
  			addSource(inNewSource);
  		}
  		else {
  			_sourceList.set(origPos, inNewSource);
  		}
  	}
  
  	/**
  	 * @param inIndex source index number
  	 * @return corresponding map source object
  	 */
  	public static MapSource getSource(int inIndex)
  	{
  		// Check whether within range
  		if (inIndex < 0 || inIndex >= _sourceList.size()) {return null;}
  		return _sourceList.get(inIndex);
  	}
  
  	/**
  	 * Delete the specified source
  	 * @param inIndex index of source to delete
  	 */
  	public static void deleteSource(int inIndex)
  	{
  		if (inIndex >= _numFixedSources) {
  			_sourceList.remove(inIndex);
  		}
  	}
  
  	/**
  	 * Check whether the given name already exists in the library (case-insensitive)
  	 * @param inName name to check
  	 * @return true if already exists, false otherwise
  	 */
  	public static boolean hasSourceName(String inName)
  	{
  		if (inName == null) {return false;}
  		String checkName = inName.toLowerCase().trim();
  		for (MapSource source : _sourceList)
  		{
  			String name = source.getName().toLowerCase();
  			if (name.equals(checkName)) {return true;}
  		}
  		return false;
  	}
  
  	/**
  	 * @return String containing all custom-added sources as a |-separated list
  	 */
  	public static String getConfigString()
  	{
  		StringBuilder builder = new StringBuilder();
  		for (int i=getNumFixedSources(); i<getNumSources(); i++) {
  			builder.append(getSource(i).getConfigString()).append('|');
  		}
  		return builder.toString();
  	}
  }
  