//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
//
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace FrameworkLibraries
{
	/// <summary>
	/// Podsumowanie dla DirectoryForm.
	/// </summary>
	public class DirectoryForm : System.Windows.Forms.Form
	{
		private System.Windows.Forms.TreeNode rootNode;
		private System.Windows.Forms.TreeView directoryTree;
		private System.Windows.Forms.ImageList directoryImageList;
		private System.Windows.Forms.ListView fileInfoList;
		private System.ComponentModel.IContainer components;
		enum ImageListTypes
		{
			Computer = 0,
			Drive = 1,
			CDRom = 2,
			Floppy = 3,
			Remote = 4,
			Disconnected = 5,
			FolderClosed = 6,
			FolderOpen = 7,
			Recycle = 8,
			File = 9
		}

		public DirectoryForm()
		{
			//
			// Wymagane do obsługi Windows Form Designer
			//
			InitializeComponent();
			InitializeTreeControl();
		}

		/// <summary>
		/// Oczyszczenie używanych zasobów.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Metoda wymagana do obsługi Designera - nie należy modyfikować
		/// zawartości tej metody przy użyciu edytora kodu.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(DirectoryForm));
			this.directoryTree = new System.Windows.Forms.TreeView();
			this.directoryImageList = new System.Windows.Forms.ImageList(this.components);
			this.fileInfoList = new System.Windows.Forms.ListView();
			this.SuspendLayout();
			// 
			// directoryTree
			// 
			this.directoryTree.ImageList = this.directoryImageList;
			this.directoryTree.Location = new System.Drawing.Point(8, 8);
			this.directoryTree.Name = "directoryTree";
			this.directoryTree.Size = new System.Drawing.Size(216, 376);
			this.directoryTree.TabIndex = 0;
			this.directoryTree.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.OnSelectNode);
			this.directoryTree.BeforeCollapse += new System.Windows.Forms.TreeViewCancelEventHandler(this.OnBeforeCollapse);
			this.directoryTree.BeforeExpand += new System.Windows.Forms.TreeViewCancelEventHandler(this.OnBeforeExpand);
			// 
			// directoryImageList
			// 
			this.directoryImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth24Bit;
			this.directoryImageList.ImageSize = new System.Drawing.Size(16, 16);
			this.directoryImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("directoryImageList.ImageStream")));
			this.directoryImageList.TransparentColor = System.Drawing.Color.Transparent;
			// 
			// fileInfoList
			// 
			this.fileInfoList.Location = new System.Drawing.Point(232, 8);
			this.fileInfoList.Name = "fileInfoList";
			this.fileInfoList.Size = new System.Drawing.Size(536, 376);
			this.fileInfoList.TabIndex = 1;
			this.fileInfoList.View = System.Windows.Forms.View.Details;
			// 
			// DirectoryForm
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
			this.ClientSize = new System.Drawing.Size(776, 392);
			this.Controls.AddRange(new System.Windows.Forms.Control[] {
																		  this.fileInfoList,
																		  this.directoryTree});
			this.Name = "DirectoryForm";
			this.Text = "Katalog";
			this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// Główny punkt wejścia dla aplikacji.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new DirectoryForm());
		}

		enum DriveType
		{
			Undetermined = 0,
			RootNotExist = 1,
			Removable = 2,
			Fixed = 3,
			Remote = 4,
			CDRom = 5,
			RamDisk = 6
		}
		class NativeMethods
	    {
			[DllImport("kernel32.dll")]
			public static extern int GetDriveTypeW(
				[In, MarshalAs(UnmanagedType.LPWStr)]
				string drive);
			[DllImport("kernel32.dll")]
			[return : MarshalAs( UnmanagedType.Bool )]
			public static extern bool GetDiskFreeSpaceW
				(
				[In, MarshalAs(UnmanagedType.LPWStr)]
				string root,
				[Out, MarshalAs(UnmanagedType.U4)]
				out uint cluster_sectors,
				[Out, MarshalAs(UnmanagedType.U4)]
				out uint  sector_bytes,
				[Out, MarshalAs(UnmanagedType.U4)]
				out uint  free_clusters,
				[Out, MarshalAs(UnmanagedType.U4)]
				out uint  total_clusters
				);
		}
		private void InitializeTreeControl()
		{
			// Inicjalizacja TreeControl
			// Umieszczenie danych w TreeView
			rootNode = new TreeNode("Mój komputer", (int)ImageListTypes.Computer, (int)ImageListTypes.Computer);
			directoryTree.Nodes.Add(rootNode);
			TreeNodeCollection driveCollection =  rootNode.Nodes;
			string [] driveNames = Directory.GetLogicalDrives();
			foreach (string s in driveNames) 
			{
				ImageListTypes imageIndex = ImageListTypes.Computer;
				ImageListTypes selectedIndex = ImageListTypes.Computer;
				DriveType dt = (DriveType)NativeMethods.GetDriveTypeW(s);
				if (dt == DriveType.Removable) 
				{
					imageIndex = ImageListTypes.Floppy;
					selectedIndex = ImageListTypes.Floppy;
					// Utworzenie węzła Drive Root
					TreeNode driveNode = new TreeNode(s, (int)ImageListTypes.Floppy, (int)ImageListTypes.Floppy);
					driveNode.Tag = s;
					//	Dodanie węzła
					driveCollection.Add(driveNode);
				}
				else 
				{
					if(dt == DriveType.Fixed)
					{
						imageIndex = ImageListTypes.Drive;
						selectedIndex = ImageListTypes.Drive;
					}
					if(dt == DriveType.CDRom)
					{
						imageIndex = ImageListTypes.CDRom;
						selectedIndex = ImageListTypes.CDRom;
					}
					if(dt == DriveType.Remote)
					{
						imageIndex = ImageListTypes.Remote;
						selectedIndex = ImageListTypes.Remote;
					}
					// Utworzenie węzła Drive Root
					TreeNode driveNode = new TreeNode(s, (int)imageIndex, (int)selectedIndex);
					driveNode.Tag = s;
					//	Dodanie węzła
					driveCollection.Add(driveNode);
					PopulateTreeNode(s, driveNode.Nodes);
				}
			}
			this.Cursor = Cursors.Arrow;
		}
		private int PopulateTreeNode(string path, TreeNodeCollection nodeCollection)
		{
			try
			{
				string [] fileNames = Directory.GetFiles(path);
				foreach (string s in fileNames) 
				{
					TreeNode fileNode = new TreeNode(s.Substring(s.LastIndexOf(@"\")+1), 9, 9);
					fileNode.Tag = s;
					nodeCollection.Add(fileNode);
				}
				string [] dirNames = Directory.GetDirectories(path);
				foreach (string s in dirNames) 
				{
					TreeNode dirNode;
					string dir = s.Substring(s.LastIndexOf(@"\")+1);
					if(dir.Equals("RECYCLER"))
						dirNode = new TreeNode(dir, (int)ImageListTypes.Recycle, (int)ImageListTypes.Recycle);
					else
						dirNode = new TreeNode(dir, (int)ImageListTypes.FolderClosed, (int)ImageListTypes.FolderOpen);
					dirNode.Tag = s;
					nodeCollection.Add(dirNode);
				}
			}
			catch(Exception e)
			{
				Debug.WriteLine(e);
				return 1;
			}
			return 0;
		}
		private void PopulateComputerListview()
		{
			Process [] pa = Process.GetProcesses();
			foreach(Process p in pa)
			{
				ListViewItem item = fileInfoList.Items.Add(p.Id.ToString());
				ProcessThreadCollection ptc = p.Threads;
				item.SubItems.Add(p.ProcessName);
				item.SubItems.Add(ptc.Count.ToString("#,#"));
				item.SubItems.Add(p.WorkingSet.ToString("#,#"));
				item.SubItems.Add(p.VirtualMemorySize.ToString("#,#"));
				item.SubItems.Add(p.TotalProcessorTime.ToString());
			}
		}
		private void PopulateDriveListview(string drive)
		{
			uint sectPerCluster;
			uint bytesPerSect;
			uint freeClusters;
			uint totalClusters;
			NativeMethods.GetDiskFreeSpaceW(drive,
				                            out sectPerCluster,
				                            out bytesPerSect,
				                            out freeClusters,
				                            out totalClusters);
			long totalBytes = (long)totalClusters * sectPerCluster * bytesPerSect;
			long freeBytes = (long)freeClusters * sectPerCluster * bytesPerSect;
			ListViewItem item = fileInfoList.Items.Add(drive);
			item.SubItems.Add(totalBytes.ToString("#,#"));
			item.SubItems.Add(freeBytes.ToString("#,#"));
		}
		private void PopulateDirectoryListview(string [] files)
		{
			foreach(string s in files)
			{
				FileInfo fi = new FileInfo(s);
				if(fi.Exists)
				{
					ListViewItem item = fileInfoList.Items.Add(s.Substring(s.LastIndexOf(@"\")+1));
					item.SubItems.Add(fi.Length.ToString("#,#"));
					item.SubItems.Add(Convert.ToString(fi.CreationTime));
					item.SubItems.Add(Convert.ToString(fi.LastWriteTime));
				}
			}
		}
		private void PopulateFileListview(string file)
		{
			FileInfo fi = new FileInfo(file);
			if(fi.Exists)
			{
				ListViewItem item = fileInfoList.Items.Add(file.Substring(file.LastIndexOf(@"\")+1));
				item.SubItems.Add(fi.Length.ToString("#,#"));
				item.SubItems.Add(Convert.ToString(fi.CreationTime));
				item.SubItems.Add(Convert.ToString(fi.LastWriteTime));
			}
		}
		private void OnSelectNode(object sender, System.Windows.Forms.TreeViewEventArgs e)
		{
			fileInfoList.Clear();
			if(e.Node.ImageIndex == (int)ImageListTypes.Computer)
			{
				fileInfoList.Clear();
				// Komputer
				fileInfoList.Columns.Add("Id",70,HorizontalAlignment.Center );
				fileInfoList.Columns.Add("Nazwa",70,HorizontalAlignment.Center );
				fileInfoList.Columns.Add("Liczba wątków",70,HorizontalAlignment.Center );
				fileInfoList.Columns.Add("Zestaw roboczy",100,HorizontalAlignment.Center );
				fileInfoList.Columns.Add("Rozmiar pamięci wirtualnej",100,HorizontalAlignment.Center );
				fileInfoList.Columns.Add("Całkowity czas procesora",100,HorizontalAlignment.Center );
				PopulateComputerListview();
			}
			else
			{
				// Sprawdzenie "normalnych" katalogów
				if(e.Node.ImageIndex == (int)ImageListTypes.FolderClosed ||
					e.Node.ImageIndex == (int)ImageListTypes.FolderOpen ||
					e.Node.ImageIndex == (int)ImageListTypes.Recycle)
				{
					try
					{
						string [] curDirFiles = Directory.GetFiles((string)e.Node.Tag);
						// Katalog
						fileInfoList.Columns.Add("Nazwa",225,HorizontalAlignment.Center );
						fileInfoList.Columns.Add("Wielkość",70,HorizontalAlignment.Center );
						fileInfoList.Columns.Add("Utworzony",100,HorizontalAlignment.Center );
						fileInfoList.Columns.Add("Zmodyfikowany",100,HorizontalAlignment.Center );
						PopulateDirectoryListview(curDirFiles);
					}
					catch(Exception exception)
					{
						Debug.WriteLine(exception);
					}
				}
				else
				{
					if(e.Node.ImageIndex == (int)ImageListTypes.Drive ||
						e.Node.ImageIndex == (int)ImageListTypes.CDRom ||
						e.Node.ImageIndex == (int)ImageListTypes.Floppy ||
						e.Node.ImageIndex == (int)ImageListTypes.Remote)
					{
						fileInfoList.Columns.Add("Nazwa",  70, HorizontalAlignment.Center );
						fileInfoList.Columns.Add("Pojemność",100, HorizontalAlignment.Center );
						fileInfoList.Columns.Add("Dostępne", 100, HorizontalAlignment.Center );
						PopulateDriveListview((string)e.Node.Tag);
					}
					else
					{
						if(e.Node.ImageIndex == (int)ImageListTypes.File)
						{
							fileInfoList.Columns.Add("Nazwa",225,HorizontalAlignment.Center );
							fileInfoList.Columns.Add("Wielkość",70,HorizontalAlignment.Center );
							fileInfoList.Columns.Add("Utworzony",100,HorizontalAlignment.Center );
							fileInfoList.Columns.Add("Zmodyfikowany",100,HorizontalAlignment.Center );
							PopulateFileListview((string)e.Node.Tag);
						}
					}
				}
			}
		}

		private void OnBeforeExpand(object sender, System.Windows.Forms.TreeViewCancelEventArgs e)
		{
			if(e.Node.ImageIndex == (int)ImageListTypes.FolderClosed)
				e.Node.ImageIndex = (int)ImageListTypes.FolderOpen;
			foreach(TreeNode node in e.Node.Nodes)
			{
				if(node.ImageIndex == (int)ImageListTypes.FolderClosed ||
				   node.ImageIndex == (int)ImageListTypes.FolderOpen ||
				   node.ImageIndex == (int)ImageListTypes.Recycle)
				{
					// Katalog lub dysk
					PopulateTreeNode((string)node.Tag, node.Nodes);
				}
			}
		}

		private void OnBeforeCollapse(object sender, System.Windows.Forms.TreeViewCancelEventArgs e)
		{
			if(e.Node.ImageIndex == (int)ImageListTypes.FolderOpen)
				e.Node.ImageIndex = (int)ImageListTypes.FolderClosed;	
		}
	}
}
