using System;
using System.Collections;
using System.Data;
using System.Configuration;
using System.Web;
using System.IO;
using RTE;

public class LocalFileProvider : RTE.EditorFileProvider
{
	static public string PhysicalFolder
	{
		get
		{
			return "d:\\myfolder";
		}
	}

	HttpContext _context;


	Hashtable _zonetoweb = new Hashtable();
	Hashtable _zonetophy = new Hashtable();


	public override void Init(HttpContext context,ConfigSecurity security)
	{
		_context = context;
		string zoneid = security.StorageId;

		string webpath = security.StoragePath;

		if (webpath.StartsWith("~/"))
			webpath = webpath.Remove(0, 1);
		else if (!webpath.StartsWith("/")) 
			throw (new Exception("Invalid StoragePath"));

		string phypath = Path.Combine(PhysicalFolder,webpath.Remove(0,1).Replace('/', '\\'));

		phypath = phypath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar;

		string handler = security.FileProviderArg0;
		if(string.IsNullOrEmpty(handler))
			handler = "/download.ashx?file=";
		if (handler.StartsWith("~/"))
			handler = System.Web.HttpRuntime.AppDomainAppVirtualPath.TrimEnd('/') + handler.Remove(0, 1);

		_zonetoweb[zoneid] = handler + webpath;
		_zonetophy[zoneid] = phypath;
	}

	private string GetZoneWebPath(string zoneid)
	{
		string webpath = (string)_zonetoweb[zoneid];
		if (webpath == null)
			throw (new Exception("Invalid zone"));
		return webpath;
	}
	private string GetZonePhyPath(string zoneid)
	{
		string phypath = (string)_zonetophy[zoneid];
		if (phypath == null)
			throw (new Exception("Invalid zone"));
		return phypath;
	}

	public override string GetUrlPrefix(Storage zone)
	{
		return GetZoneWebPath(zone.ID).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
	}
	public override long CalcStorageSize(Storage zone)
	{
		string path = GetZonePhyPath(zone.ID);
		return CalcDirectorySize(path);
	}

	static long CalcDirectorySize(string path)
	{
		long size = 0;
		try
		{
			foreach (string eachfile in Directory.GetFiles(path))
			{
				try
				{
					size += new FileInfo(eachfile).Length;
				}
				catch
				{
				}
			}
		}
		catch
		{
		}
		try
		{
			foreach (string eachdir in Directory.GetDirectories(path))
			{
				size += CalcDirectorySize(eachdir);
			}
		}
		catch
		{
		}
		return size;
	}

	public override FolderID GetRootId(Storage zone)
	{
		return new FolderID(zone.ID, GetZonePhyPath(zone.ID), zone.Category, zone.Extensions);
	}

	public override string GetUrlPath(FolderID folderid)
	{
		string phypath = GetZonePhyPath(folderid.ZoneID);
		return folderid.Value.Remove(0, phypath.Length - 1).Replace('\\', '/');
	}

	public override FolderID GetParentId(FolderID folderid)
	{
		string phypath = GetZonePhyPath(folderid.ZoneID);

		string path = folderid.Value.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
		int pos = path.LastIndexOfAny(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar });
		path = path.Substring(0, pos + 1);
		if (path.IndexOf(phypath) == -1)
			return null;
		return new FolderID(folderid.ZoneID, path, folderid.Category, folderid.Extensions);
	}
	public override FolderID HasFolder(FolderID folderid, string foldername)
	{
		string childid = Path.Combine(folderid.Value, foldername);
		if (Directory.Exists(childid))
		{
			string path = childid.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar;
			return new FolderID(folderid.ZoneID, path, folderid.Category, folderid.Extensions);
		}
		return null;
	}
	public override PathItem[] GetFolders(FolderID folderid, GetItemOption option)
	{
		if (!Directory.Exists(folderid.Value))
			return new PathItem[0];

		string[] dirs = SafeGetDirectories(folderid.Value);
		ArrayList list = new ArrayList();
		foreach (string fullname in dirs)
		{
			PathItem item = GetFolderItem(fullname, folderid.Filter, option);
			if (this.IsHiddenItem(item))
				continue;
			list.Add(item);
		}
		return (PathItem[])list.ToArray(typeof(PathItem));
	}
	public override PathItem[] GetFiles(FolderID folderid, GetItemOption option)
	{
		if (!Directory.Exists(folderid.Value))
			return new PathItem[0];

		IList files = folderid.Filter.GetFiles(folderid.Value);
		ArrayList list = new ArrayList();
		foreach (string fullname in files)
		{
			PathItem item = GetFileItem(option, fullname);
			if (this.IsHiddenItem(item))
				continue;
			list.Add(item);
		}
		return (PathItem[])list.ToArray(typeof(PathItem));
	}

	public override PathItem GetItem(FolderID folderid, GetItemOption option, string name)
	{
		if (name == "..")
			return null;

		string fullname = folderid.Value + name;
		if (Directory.Exists(fullname))
			return GetFolderItem(fullname, folderid.Filter, option);
		if (File.Exists(fullname))
			return GetFileItem(option, fullname);
		return null;
	}

	private static PathItem GetFileItem(GetItemOption option, string fullname)
	{
		PathItem item = new PathItem();
		item.IsFolder = false;
		item.Name = Path.GetFileName(fullname);
		FileInfo info = null;
		if (option.GetSize || option.GetTime)
		{
			info = new FileInfo(fullname);
			if (option.GetSize)
				item.Size = info.Length;
			else
				item.Size = -1;
			if (option.GetTime)
				item.Time = GetItemOption.CalcTime(info.LastWriteTime);
		}
		return item;
	}


	private static PathItem GetFolderItem(string fullname, FileFilter filter, GetItemOption option)
	{
		PathItem item = new PathItem();
		item.IsFolder = true;
		item.Name = Path.GetFileName(fullname);
		item.Size = -1;
		if (option.GetSize)
		{
			try
			{
				item.Size = Directory.GetFiles(fullname).Length; // filter.GetFiles(fullname).Count;
				foreach (string subdir in SafeGetDirectories(fullname))
				{
					if (subdir.EndsWith(EditorFileManager.CACHE_FOLDER_NAME))
					{
						string n = Path.GetFileName(subdir);
						if (n == EditorFileManager.CACHE_FOLDER_NAME)
							continue;
					}
					item.Size++;
				}
			}
			catch
			{
			}
		}
		return item;
	}

	public override byte[] LoadFile(FolderID folderid, string filename)
	{
		string fullname = folderid.Value + filename;

		if (!File.Exists(fullname))
			throw (new Exception(filename + " does not exist"));

		using (FileStream fs = new FileStream(fullname, FileMode.Open, FileAccess.Read, FileShare.Read, 65536))
		{
			byte[] data = new byte[fs.Length];
			fs.Read(data, 0, data.Length);
			return data;
		}
	}

	public override void CreateFile(FolderID folderid, string filename, Stream stream)
	{
		string fullname = folderid.Value + filename;

		if (Directory.Exists(fullname))
			throw (new Exception(filename + " is a folder"));

		if (!Directory.Exists(folderid.Value))
			Directory.CreateDirectory(folderid.Value);

		byte[] buff = new byte[4096];
		using (FileStream fs = new FileStream(fullname, FileMode.Create, FileAccess.Write, FileShare.None, 65536))
		{
			while (true)
			{
				int rc = stream.Read(buff, 0, buff.Length);
				if (rc == 0)
					break;
				fs.Write(buff, 0, rc);
			}
		}
	}
	public override void CreateFolder(FolderID folderid, string filename)
	{
		string fullname = folderid.Value + filename;
		if (File.Exists(fullname))
			throw (new Exception(filename + " is a file"));
		PathItem item = GetItem(folderid, GetItemOption.None, filename);
		if (item != null)
			return;
		Directory.CreateDirectory(fullname);
	}
	public override void DeleteFile(FolderID folderid, string filename)
	{
		string fullname = folderid.Value + filename;
		if (File.Exists(fullname))
			File.Delete(fullname);
	}
	public override void DeleteFolder(FolderID folderid, string filename)
	{
		string fullname = folderid.Value + filename;
		if (Directory.Exists(fullname))
			Directory.Delete(fullname, true);
	}
	public override void ChangeFileName(FolderID folderid, string filename, string newname)
	{
		string fullname1 = folderid.Value + filename;
		string fullname2 = folderid.Value + newname;
		File_Move(fullname1, fullname2);
	}
	public override void ChangeFolderName(FolderID folderid, string filename, string newname)
	{
		string fullname1 = folderid.Value + filename;
		string fullname2 = folderid.Value + newname;
		Directory_Move(fullname1, fullname2, folderid.Filter);
	}
	public override void MoveFile(FolderID folderid, FolderID targetid, string filename)
	{
		string fullname1 = folderid.Value + filename;
		string fullname2 = targetid.Value + filename;
		File_Move(fullname1, fullname2);
	}
	public override void MoveFolder(FolderID folderid, FolderID targetid, string filename)
	{
		string fullname1 = folderid.Value + filename;
		string fullname2 = targetid.Value + filename;
		Directory_Move(fullname1, fullname2, folderid.Filter);
	}

	public override void CopyFile(FolderID folderid, FolderID targetid, string filename)
	{
		string fullname1 = folderid.Value + filename;
		string fullname2 = targetid.Value + filename;
		File_Copy(fullname1, fullname2);
	}
	public override void CopyFolder(FolderID folderid, FolderID targetid, string filename)
	{
		string fullname1 = folderid.Value + filename;
		string fullname2 = targetid.Value + filename;
		Directory_Copy(fullname1, fullname2, folderid.Filter);
	}

	static private void Directory_Copy(string src, string dst, FileFilter filter)
	{
		if (!Directory.Exists(dst))
			Directory.CreateDirectory(dst);
		foreach (string srcfile in Directory.GetFiles(src))
		{
			string name = Path.GetFileName(srcfile);
			string dstfile = Path.Combine(dst, name);
			File_Copy(srcfile, dstfile);
		}
		foreach (string srcfile in SafeGetDirectories(src))
		{
			string name = Path.GetFileName(srcfile);
			string dstfile = Path.Combine(dst, name);
			Directory_Copy(srcfile, dstfile, filter);
		}
	}
	static private void File_Copy(string src, string dst)
	{
		if (!File.Exists(src)) return;
		if (!File.Exists(dst))
		{
			File.Copy(src, dst);
			return;
		}
		File.Move(dst, dst + ".moving");
		try
		{
			File.Copy(src, dst);
		}
		catch
		{
			File.Move(dst + ".moving", dst);
			throw;
		}
	}


	static private void Directory_Move(string src, string dst, FileFilter filter)
	{
		if (!Directory.Exists(dst))
		{
			Directory.Move(src, dst);
			return;
		}
		foreach (string srcfile in Directory.GetFiles(src))
		{
			string name = Path.GetFileName(srcfile);
			string dstfile = Path.Combine(dst, name);
			File_Move(srcfile, dstfile);
		}
		foreach (string srcfile in SafeGetDirectories(src))
		{
			string name = Path.GetFileName(srcfile);
			string dstfile = Path.Combine(dst, name);
			Directory_Move(srcfile, dstfile, filter);
		}
		Directory.Delete(src);
	}
	static private void File_Move(string src, string dst)
	{
		if (!File.Exists(src)) return;
		if (!File.Exists(dst))
		{
			File.Move(src, dst);
			return;
		}
		File.Move(dst, dst + ".moving");
		try
		{
			File.Move(src, dst);
		}
		catch
		{
			File.Move(dst + ".moving", dst);
			throw;
		}
		File.Delete(dst + ".moving");
	}

	static private string[] SafeGetDirectories(string folder)
	{
		if (!Directory.Exists(folder))
			return new string[0];
		try
		{
			return Directory.GetDirectories(folder);
		}
		catch
		{
		}
		return new string[0];
	}


}

