using System;
using System.Collections.Generic;
using Mono.Fuse;
using System.Reflection;
using Mono.Unix.Native;
using System.Runtime.InteropServices;

class TypeNavigator : FileSystem
{
	Dictionary<string,Assembly> assemblies;
	Dictionary<string,string[]> assembly_results = new Dictionary<string,string[]>();
	
	public TypeNavigator ()
	{
		assemblies = new Dictionary<string,Assembly> ();

		Assembly a = Assembly.Load ("mscorlib");
		assemblies [a.GetName().Name] = a;
	}

	protected override Errno OnReadDirectory (string path, [Out] out string[] paths, OpenedFileInfo fi)
	{
		int i = 0;
			
		if (path == "/"){
			paths = new string [assemblies.Count+2];
			i = 0;
			paths [i++] = ".";
			paths [i++] = "..";			
			foreach (string val in assemblies.Keys){
				paths [i++] = val;
				Console.WriteLine ("  {0}", val);
			}

			return 0;
		}
		path = path.Substring (1);
		string [] elements = path.Split (new char [] { '/' });

		try {
			if (elements.Length == 1){
				string key = elements [0];
				Assembly ass = assemblies [key];
				if (ass == null){
					paths = new string [0];
					return Errno.ENOENT;
				}
				if (assembly_results.ContainsKey (key))
					paths = assembly_results [key];
				else {
					Type [] types = ass.GetTypes ();
					
					paths = new string [types.Length+2];
					i = 0;
					paths [i++] = ".";
					paths [i++] = "..";			
					foreach (Type t in types)
						paths [i++] = t.FullName; 
					
					assembly_results [key] = paths;
				}
				return 0;
			}
			if (elements.Length == 2){
				Assembly ass = assemblies [elements [0]];
				if (ass != null){
					Type t = ass.GetType (elements [1]);
					if (t != null){
						MemberInfo [] mi = t.GetMembers ();
						paths = new string [mi.Length + 2];
						paths [i++] = ".";
						paths [i++] = "..";
						
						foreach (MemberInfo m in mi)
							paths [i++] = m.Name;

						return 0;
					}
				}
			}
			
		} catch (Exception e) {
			Console.WriteLine ("Exception: {0}", e.ToString ());
		}
		paths = new string [0];
		return Errno.ENOENT;
	}
	
	protected override Errno OnGetFileAttributes (string path, ref Stat stbuf)
	{
		int sep = 0;
		
		foreach (char c in path){
			if (c == '/')
				sep++;
		}
		
		stbuf = new Stat ();

		if (sep < 3){
			stbuf.st_mode = FilePermissions.S_IFDIR | NativeConvert.FromOctalPermissionString ("0755");
			stbuf.st_nlink = 1;
		} else {
			stbuf.st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString ("0444");
			stbuf.st_nlink = 1;
		}
		stbuf.st_size = 0;

		return 0;
	}
	
	public static void Main (string [] args)
	{
		if (args.Length < 1){
			Console.WriteLine ("Error: must specify a directory to mount at");
			return;
		}
		
		using (TypeNavigator t = new TypeNavigator ()){
			t.MountPoint = args [0];
			t.Start ();
		}
	}
}
