/// <summary>
 ///         constructor.
 /// </summary>
 /// <param name="fileNumber">the block index the file begins at in the parent container file.</param>
 /// <param name="name">the name of this virtual item (file name or directory name).</param>
 /// <param name="parentDirectory">an instance of the parent directory.</param>
 /// <param name="containerFile">an instance of the parent container file.</param>
 internal VirtualItem(uint fileNumber, string name, VirtualDirectory parentDirectory,
     ContainerFile containerFile)
 {
     FileNumber = fileNumber;
                 Name = name;
                 ParentDirectory = parentDirectory;
                 ContainerFile = containerFile;
 }
        /// <summary>
        ///         adds a new directory to this directory.
        /// </summary>
        /// <param name="directoryName">the name of the new directory to be created.</param>
        /// <returns>the created directory.</returns>
        public VirtualDirectory AddDirectory(string directoryName)
        {
            if (!ValidName(directoryName))
                        {
                                throw new ArgumentException("directoryName invalid");
                        }

                        if (ReadAllItems().Any(item => item.Name.Equals(directoryName)))
                        {
                                throw new ItemNameInUseException(directoryName);
                        }

                        var newDirectory = new VirtualDirectory(CreateNewFile(), directoryName, this, ContainerFile);
                        AddItem(newDirectory);

                        return newDirectory;
        }
        /// <summary>
        ///         copies this file into the target directory with a given name.
        /// </summary>
        /// <param name="targetDirectory">the target directory this file should be copied to</param>
        /// <param name="newName">the new name the copied file should take after copying.</param>
        /// <returns>the created copy.</returns>
        public override VirtualItem Copy(VirtualDirectory targetDirectory, string newName)
        {
            const int COPY_CHUNK_SIZE = 2048;

                        if (!ValidName(newName))
                        {
                                throw new ArgumentException("newName invalid");
                        }

                        if (targetDirectory == null)
                        {
                                throw new ArgumentException("targetDirectory must not be null");
                        }

                        if (targetDirectory.ReadAllItems().Any(item => item.Name.Equals(newName)))
                        {
                                throw new ItemNameInUseException(newName);
                        }

                        VirtualFile fileCopy = targetDirectory.AddFile(newName);

                        FileStream fromStream = GetFileStream();
                        FileStream toStream = fileCopy.GetFileStream();

                        ContainerFile.ChangeFileSize(fileCopy.FileNumber, fromStream.Length);

                        long fromStreamLength = fromStream.Length;

                        while (fromStream.Position < fromStreamLength)
                        {
                                long remainingData = fromStreamLength - fromStream.Position;

                                long amountToCopy = COPY_CHUNK_SIZE < remainingData ? COPY_CHUNK_SIZE : remainingData;

                                toStream.Write(fromStream.Read(amountToCopy));
                        }

                        return fileCopy;
        }
        private VirtualDirectory CopyInternal(VirtualDirectory targetDirectory, string newName, HashSet<uint> copies)
        {
            if (copies.Contains(FileNumber)) return null;

                        VirtualItem[] items = ReadAllItems().ToArray();

                        int copyNumber = 0;
                        string baseName = newName;
                        VirtualItem[] targetItems = targetDirectory.ReadAllItems().ToArray();
                        while (targetItems.Any(item => item.Name.Equals(baseName)))
                        {
                                baseName = newName + ++copyNumber;
                        }

                        VirtualDirectory directoryCopy = targetDirectory.AddDirectory(baseName);

                        copies.Add(directoryCopy.FileNumber);

                        foreach (VirtualDirectory directory in items.OfType<VirtualDirectory>())
                        {
                                directory.CopyInternal(directoryCopy, directory.Name, copies);
                        }

                        foreach (VirtualFile file in items.OfType<VirtualFile>())
                        {
                                file.Copy(directoryCopy, file.Name);
                        }

                        return directoryCopy;
        }
 /// <summary>
 ///         constructor.
 /// </summary>
 /// <param name="fileNumber">the block index the file begins at in the parent container file.</param>
 /// <param name="name">the name of this virtual item (file name or directory name).</param>
 /// <param name="parentDirectory">an instance of the parent directory.</param>
 /// <param name="containerFile">an instance of the parent container file.</param>
 internal VirtualDirectory(uint fileNumber, string name, VirtualDirectory parentDirectory,
     ContainerFile containerFile)
     : base(fileNumber, name, parentDirectory, containerFile)
 {
 }
        /// <summary>
        ///         /// copies the directory into the target directory with a given name.
        /// </summary>
        /// <param name="targetDirectory">the target directory this directory should be copied to</param>
        /// <param name="newName">the new name the copied directory should take after copying.</param>
        /// <returns>the created copy.</returns>
        public override VirtualItem Copy(VirtualDirectory targetDirectory, string newName)
        {
            if (!ValidName(newName))
                        {
                                throw new ArgumentException("newName invalid");
                        }

                        return CopyInternal(targetDirectory, newName, new HashSet<uint>());
        }
 /// <summary>
 ///         copies this item into the target directory with a given name.
 /// </summary>
 /// <param name="targetDirectory">the target directory this item should be copied to</param>
 /// <param name="newName">the new name the copied item should take after copying.</param>
 /// <returns>the created copy.</returns>
 public abstract VirtualItem Copy(VirtualDirectory targetDirectory, string newName);
        /// <summary>
        ///         moves the item into the target directory.
        /// </summary>
        /// <param name="targetDirectory">the directory this item should be moved to.</param>
        public void Move(VirtualDirectory targetDirectory)
        {
            if (targetDirectory == null)
                        {
                                throw new ArgumentException("targetDirectory must not be null");
                        }

                        if (ParentDirectory == null)
                        {
                                throw new ArgumentException("cannot move root");
                        }

                        ParentDirectory.RemoveItem(this);

                        ParentDirectory = targetDirectory;

                        targetDirectory.AddItem(this);
        }
 /// <summary>
 ///         constructor.
 /// </summary>
 /// <param name="firstBlockIndex">the block index the file begins at in the parent container file.</param>
 /// <param name="name">the name of this virtual item (file name or directory name).</param>
 /// <param name="parentDirectory">an instance of the parent directory.</param>
 /// <param name="containerFile">an instance of the parent container file.</param>
 internal VirtualFile(uint firstBlockIndex, string name, VirtualDirectory parentDirectory, ContainerFile containerFile)
     : base(firstBlockIndex, name, parentDirectory, containerFile)
 {
 }