using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Substrate.Core;
namespace Substrate
{
///
/// Manages the regions of a Beta-compatible world.
///
public class RegionManager : IRegionManager
{
private string _regionPath;
private Dictionary _cache;
private ChunkCache _chunkCache;
///
/// Creates a new instance of a for the given region directory and chunk cache.
///
/// The path to a directory containing region files.
/// The shared chunk cache to hold chunk data in.
public RegionManager (string regionDir, ChunkCache cache)
{
_regionPath = regionDir;
_chunkCache = cache;
_cache = new Dictionary();
}
///
/// Gets a at the given coordinates.
///
/// The global X-coordinate of a region.
/// The global Z-coordinate of a region.
/// A representing a region at the given coordinates, or null if the region does not exist.
public Region GetRegion (int rx, int rz)
{
RegionKey k = new RegionKey(rx, rz);
Region r;
try {
if (_cache.TryGetValue(k, out r) == false) {
r = new Region(this, _chunkCache, rx, rz);
_cache.Add(k, r);
}
return r;
}
catch (FileNotFoundException) {
_cache.Add(k, null);
return null;
}
}
///
/// Determines if a region exists at the given coordinates.
///
/// The global X-coordinate of a region.
/// The global Z-coordinate of a region.
/// True if a region exists at the given global region coordinates; false otherwise.
public bool RegionExists (int rx, int rz)
{
Region r = GetRegion(rx, rz);
return r != null;
}
///
/// Creates a new empty region at the given coordinates, if no region exists.
///
/// The global X-coordinate of a region.
/// The global Z-coordinate of a region.
/// A new empty object for the given coordinates, or an existing if one exists.
public Region CreateRegion (int rx, int rz)
{
Region r = GetRegion(rx, rz);
if (r == null) {
string fp = "r." + rx + "." + rz + ".mca";
using (RegionFile rf = new RegionFile(Path.Combine(_regionPath, fp))) {
}
r = new Region(this, _chunkCache, rx, rz);
RegionKey k = new RegionKey(rx, rz);
_cache[k] = r;
}
return r;
}
///
/// Gets a for the given region filename.
///
/// The filename of the region to get.
/// A corresponding to the coordinates encoded in the filename.
public Region GetRegion (string filename)
{
int rx, rz;
if (!Region.ParseFileName(filename, out rx, out rz)) {
throw new ArgumentException("Malformed region file name: " + filename, "filename");
}
return GetRegion(rx, rz);
}
///
/// Get the current region directory path.
///
/// The path to the region directory.
public string GetRegionPath ()
{
return _regionPath;
}
// XXX: Exceptions
///
/// Deletes a region at the given coordinates.
///
/// The global X-coordinate of a region.
/// The global Z-coordinate of a region.
/// True if a region was deleted; false otherwise.
public bool DeleteRegion (int rx, int rz)
{
Region r = GetRegion(rx, rz);
if (r == null) {
return false;
}
RegionKey k = new RegionKey(rx, rz);
_cache.Remove(k);
r.Dispose();
try {
File.Delete(r.GetFilePath());
}
catch (Exception e) {
Console.WriteLine("NOTICE: " + e.Message);
return false;
}
return true;
}
#region IEnumerable Members
///
/// Returns an enumerator that iterates over all of the regions in the underlying dimension.
///
/// An enumerator instance.
public IEnumerator GetEnumerator ()
{
return new Enumerator(this);
}
#endregion
#region IEnumerable Members
///
/// Returns an enumerator that iterates over all of the regions in the underlying dimension.
///
/// An enumerator instance.
IEnumerator IEnumerable.GetEnumerator ()
{
return new Enumerator(this);
}
#endregion
private struct Enumerator : IEnumerator
{
private List _regions;
private int _pos;
public Enumerator (RegionManager rm)
{
_regions = new List();
_pos = -1;
if (!Directory.Exists(rm.GetRegionPath())) {
throw new DirectoryNotFoundException();
}
string[] files = Directory.GetFiles(rm.GetRegionPath());
_regions.Capacity = files.Length;
foreach (string file in files) {
try {
Region r = rm.GetRegion(file);
_regions.Add(r);
}
catch (ArgumentException) {
continue;
}
}
}
public bool MoveNext ()
{
_pos++;
return (_pos < _regions.Count);
}
public void Reset ()
{
_pos = -1;
}
void IDisposable.Dispose () { }
object IEnumerator.Current
{
get
{
return Current;
}
}
Region IEnumerator.Current
{
get
{
return Current;
}
}
public Region Current
{
get
{
try {
return _regions[_pos];
}
catch (IndexOutOfRangeException) {
throw new InvalidOperationException();
}
}
}
}
}
}