using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace APE.model
{
    abstract public class AbstractNode
    {
		public List<AbstractNode> children = new List<AbstractNode>();
		public bool isOnCurrentPath = false;
        public bool loaded = false;
		public AbstractNode Parent { get; set; }
		public string Name { get; set; }

        public AbstractNode(AbstractNode parentN, string nameN)
        {
			Parent = parentN;
            Name = nameN;
        }

		public void accept(FSNodeVisitor visitor) {
			if (this is RootNode) {
				visitor.visit(this as RootNode);
			} else if (this is DriveNode) {
				visitor.visit(this as DriveNode);
			} else if (this is DirectoryNode) {
				visitor.visit(this as DirectoryNode);
			} else if (this is FileNode) {
				visitor.visit(this as FileNode);
			}
		}

		virtual public bool pathExists() {
			return true;
		}

        virtual public void loadChildren() {
            foreach (AbstractNode fsi in children) {
                fsi.accept(new FSLoadVisitor());
            }
        }

        virtual public string getDirectory()
        {
            return Parent.getFullPath();
        }

        virtual public string getFullPath()
        {
            if (Parent is RootNode) {
                return Name + "\\";
            } else {
                return getDirectory() + "\\" + Name;
            }
        }
    }

	public class FileNode : AbstractNode
    {
		public FileNode(AbstractNode parentN, string nameN)
            : base(parentN, nameN)
        {
        }

        public override void loadChildren()
        {
            // Does nothing; recursion is simplified; 
			// It does not have to rely on reflection.
        }

		public override bool pathExists() {
			return File.Exists(getFullPath());
		}
	}

	public class DirectoryNode : AbstractNode
    {
		public DirectoryNode(AbstractNode parentN, string nameN)
            : base(parentN, nameN)
        {
        }

		public override bool pathExists() {
			return Directory.Exists(getFullPath());
		}
    }

	public class DriveNode : AbstractNode
    {
        DriveType enumDriveType;
        string VolumeLabel;
        long TotalFreeSpace;
        public long TotalSize;
        public bool isReady;

        public DriveNode(AbstractNode parentN, DriveInfo d)
            : base(parentN, d.Name.Substring(0,d.Name.Length-1))
        {
            enumDriveType = d.DriveType;
			// I create nodes of only those drives which are ready. 
			// Later new system might be devised which enables user to 
			// switch them on/off.
            isReady = d.IsReady; 
            if (d.IsReady)
            {
                VolumeLabel = d.VolumeLabel;
                TotalFreeSpace = d.TotalFreeSpace;
                TotalSize = d.TotalSize;
            }
        }
    }

	public class RootNode : AbstractNode
    {
		public RootNode()
            : base(null, "Root")
        {
        }

        public override string getDirectory()
        {
            return "";
        }

        override public string getFullPath()
        {
            return "";
        }
    }
}
