﻿//Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Microsoft.WindowsAPICodePack.Shell
{
    /// <summary>
    /// Represents a registered file system Known Folder
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "This will complicate the class hierarchy and naming convention used in the Shell area")]
    public class FileSystemKnownFolder : ShellFileSystemFolder, IKnownFolder, IDisposable
    {
        #region Private Fields

        private IKnownFolderNative knownFolderNative;
        private KnownFolderSettings knownFolderSettings = null;

        #endregion

        #region Internal Constructors

        internal FileSystemKnownFolder(IShellItem2 shellItem)
            : base(shellItem)
        {
        }

        internal FileSystemKnownFolder(IKnownFolderNative kf)
        {
            Debug.Assert(kf != null);
            knownFolderNative = kf;

            // Set the native shell item
            // and set it on the base class (ShellObject)
            Guid guid = new Guid(ShellIIDGuid.IShellItem2);
            knownFolderNative.GetShellItem(0, ref guid, out nativeShellItem);
        }

        #endregion

        #region Private Members

        private KnownFolderSettings KnownFolderSettings
        {
            get
            {
                if (knownFolderNative == null)
                {
                    // We need to get the PIDL either from the NativeShellItem,
                    // or from base class's property (if someone already set it on us).
                    // Need to use the PIDL to get the native IKnownFolder interface.

                    // Get teh PIDL for the ShellItem
                    if (nativeShellItem != null && base.PIDL == IntPtr.Zero)
                        base.PIDL = ShellHelper.PidlFromShellItem(nativeShellItem);

                    // If we have a valid PIDL, get the native IKnownFolder
                    if (base.PIDL != IntPtr.Zero)
                        knownFolderNative = KnownFolderHelper.FromPIDL(base.PIDL);

                    Debug.Assert(knownFolderNative != null);
                }
                
                // If this is the first time this property is being called,
                // get the native Folder Defination (KnownFolder properties)
                if (knownFolderSettings == null)
                    knownFolderSettings = new KnownFolderSettings(knownFolderNative);

                return knownFolderSettings;
            }
        }

        #endregion

        #region IKnownFolder Members

        /// <summary>
        /// Gets the path for this known folder.
        /// </summary>
        /// <value>A <see cref="System.String"/> object.</value>
        public override string Path
        {
            get { return KnownFolderSettings.Path; }
        }

        /// <summary>
        /// Gets the category designation for this known folder.
        /// </summary>
        /// <value>A <see cref="FolderCategory"/> value.</value>
        public FolderCategory Category
        {
            get { return KnownFolderSettings.Category; }
        }

        /// <summary>
        /// Gets this known folder's canonical name.
        /// </summary>
        /// <value>A <see cref="System.String"/> object.</value>
        public string CanonicalName
        {
            get { return KnownFolderSettings.CanonicalName; }
        }

        /// <summary>
        /// Gets this known folder's description.
        /// </summary>
        /// <value>A <see cref="System.String"/> object.</value>
        public string Description
        {
            get { return KnownFolderSettings.Description; }
        }

        /// <summary>
        /// Gets the unique identifier for this known folder's parent folder.
        /// </summary>
        /// <value>A <see cref="System.Guid"/> value.</value>
        public Guid ParentId
        {
            get { return KnownFolderSettings.ParentId; }
        }

        /// <summary>
        /// Gets this known folder's relative path.
        /// </summary>
        /// <value>A <see cref="System.String"/> object.</value>
        public string RelativePath
        {
            get { return KnownFolderSettings.RelativePath; }
        }

        /// <summary>
        /// Gets this known folder's parsing name.
        /// </summary>
        /// <value>A <see cref="System.String"/> object.</value>
        public override string ParsingName
        {
            get { return base.ParsingName; }
        }

        /// <summary>
        /// Gets this known folder's tool tip text.
        /// </summary>
        /// <value>A <see cref="System.String"/> object.</value>
        public string Tooltip
        {
            get { return KnownFolderSettings.Tooltip; }
        }
        /// <summary>
        /// Gets the resource identifier for this 
        /// known folder's tool tip text.
        /// </summary>
        /// <value>A <see cref="System.String"/> object.</value>
        public string TooltipResourceId
        {
            get { return KnownFolderSettings.TooltipResourceId; }
        }

        /// <summary>
        /// Gets this known folder's localized name.
        /// </summary>
        /// <value>A <see cref="System.String"/> object.</value>
        public string LocalizedName
        {
            get { return KnownFolderSettings.LocalizedName; }
        }
        /// <summary>
        /// Gets the resource identifier for this 
        /// known folder's localized name.
        /// </summary>
        /// <value>A <see cref="System.String"/> object.</value>
        public string LocalizedNameResourceId
        {
            get { return KnownFolderSettings.LocalizedNameResourceId; }
        }

        /// <summary>
        /// Gets this known folder's security attributes.
        /// </summary>
        /// <value>A <see cref="System.String"/> object.</value>
        public string Security
        {
            get { return KnownFolderSettings.Security; }
        }

        /// <summary>
        /// Gets this known folder's file attributes, 
        /// such as "read-only".
        /// </summary>
        /// <value>A <see cref="System.IO.FileAttributes"/> value.</value>
        public System.IO.FileAttributes FileAttributes
        {
            get { return KnownFolderSettings.FileAttributes; }
        }

        /// <summary>
        /// Gets an value that describes this known folder's behaviors.
        /// </summary>
        /// <value>A <see cref="DefinitionOptions"/> value.</value>
        public DefinitionOptions DefinitionOptions
        {
            get { return KnownFolderSettings.DefinitionOptions; }
        }

        /// <summary>
        /// Gets the unique identifier for this known folder's type.
        /// </summary>
        /// <value>A <see cref="System.Guid"/> value.</value>
        public Guid FolderTypeId
        {
            get { return KnownFolderSettings.FolderTypeId; }
        }

        /// <summary>
        /// Gets a string representation of this known folder's type.
        /// </summary>
        /// <value>A <see cref="System.String"/> object.</value>
        public string FolderType
        {
            get { return KnownFolderSettings.FolderType; }
        }
        /// <summary>
        /// Gets the unique identifier for this known folder.
        /// </summary>
        /// <value>A <see cref="System.Guid"/> value.</value>
        public Guid FolderId
        {
            get { return KnownFolderSettings.FolderId; }
        }

        /// <summary>
        /// Gets a value that indicates whether this known folder's path exists on the computer. 
        /// </summary>
        /// <value>A bool<see cref="System.Boolean"/> value.</value>
        /// <remarks>If this property value is <b>false</b>, 
        /// the folder might be a virtual folder (<see cref="Category"/> property will
        /// be <see cref="FolderCategory.Virtual"/> for virtual folders)</remarks>
        public bool PathExists
        {
            get { return KnownFolderSettings.PathExists; }
        }

        /// <summary>
        /// Gets a value that states whether this known folder 
        /// can have its path set to a new value, 
        /// including any restrictions on the redirection.
        /// </summary>
        /// <value>A <see cref="RedirectionCapabilities"/> value.</value>
        public RedirectionCapabilities Redirection
        {
            get { return KnownFolderSettings.Redirection; }
        }
   
        #endregion

        #region IDisposable Members

        /// <summary>
        /// Release resources
        /// </summary>
        /// <param name="disposing">Indicates that this mothod is being called from Dispose() rather than the finalizer.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                knownFolderSettings = null;
            }

            if (knownFolderNative != null)
            {
                Marshal.ReleaseComObject(knownFolderNative);
                knownFolderNative = null;
            }

            base.Dispose(disposing);
        }

        #endregion
    }
}
