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

namespace Foo.DataAccessLayer.DataTypes
{
    // ArtifactTypes
    public enum ArtifactTypes
    {
        File,
        Url
    }

    // Artifacts
    public enum SortOrderForArtifacts
    {
        None,
        Ascending,
        Descending,
        LocationAscending,
        LocationDescending,
        LastAccessedAscending,
        LastAccessedDescending,
        MostFrequentlyAccessedAscending,
        MostFrequentlyAccessedDescending
    }

    // Workspaces
    public enum SortOrderForWorkspaces
    {
        None,
        Ascending,
        Descending,
        LastAccessedAscending,
        LastAccessedDescending,
        MostFrequentlyAccessedAscending,
        MostFrequentlyAccessedDescending
    }

    /// <summary>
    /// This class holds the SortOrder Helper SQL functions for the SortOrder Enums listed above
    /// </summary>
    public class SortOrderSQLHelpers
    {
        /// <summary>
        /// Use this to create the OrderBy Clause for the Workspace SortOrder Function
        /// </summary>
        /// <param name="sql">sql string to add sortOrder to</param>
        /// <param name="sortOrder">the Workspace SortOrder Enum</param>
        /// <returns>modified SQL String</returns>
        public static string SortOrderForArtifactsHelper(string sql, SortOrderForArtifacts sortOrder)
        {
            switch (sortOrder)
            {
                case SortOrderForArtifacts.None:
                    break;

                case SortOrderForArtifacts.Ascending:
                    sql = sql + " ORDER BY [Artifacts].[Name] ASC";
                    break;

                case SortOrderForArtifacts.Descending:
                    sql = sql + " ORDER BY [Artifacts].[Name] DESC";
                    break;                

                case SortOrderForArtifacts.LastAccessedAscending:
                    sql = sql + " ORDER BY [Artifacts].[LastAccessed] ASC";
                    break;

                case SortOrderForArtifacts.LastAccessedDescending:
                    sql = sql + " ORDER BY [Artifacts].[LastAccessed] DESC";
                    break;

                case SortOrderForArtifacts.LocationAscending:
                    sql = sql + " ORDER BY [Artifacts].[Location] ASC";
                    break;

                case SortOrderForArtifacts.LocationDescending:
                    sql = sql + " ORDER BY [Artifacts].[Location] DESC";
                    break;

                case SortOrderForArtifacts.MostFrequentlyAccessedAscending:
                    sql = sql + " ORDER BY [Artifacts].[AccessCounter] ASC";
                    break;

                case SortOrderForArtifacts.MostFrequentlyAccessedDescending:
                    sql = sql + " ORDER BY [Artifacts].[AccessCounter] DESC";
                    break;
            }       
            return sql;
        }

        /// <summary>
        /// Use this to create the OrderBy Clause for the Workspace SortOrder Function
        /// </summary>
        /// <param name="sql">sql string to add sortOrder to</param>
        /// <param name="sortOrder">the Workspace SortOrder Enum</param>
        /// <returns>modified SQL String</returns>
        public static string SortOrderForWorkspacesHelper(string sql, SortOrderForWorkspaces sortOrder)
        {
            switch (sortOrder)
            {
                case SortOrderForWorkspaces.None:
                    break;

                case SortOrderForWorkspaces.Ascending:
                    sql = sql + " ORDER BY [Workspaces].[Name] ASC";
                    break;

                case SortOrderForWorkspaces.Descending:
                    sql = sql + " ORDER BY [Workspaces].[Name] DESC";
                    break;

                case SortOrderForWorkspaces.LastAccessedAscending:
                    sql = sql + " ORDER BY [Workspaces].[LastAccessed] ASC";
                    break;

                case SortOrderForWorkspaces.LastAccessedDescending:
                    sql = sql + " ORDER BY [Workspaces].[LastAccessed] DESC";
                    break;

                case SortOrderForWorkspaces.MostFrequentlyAccessedAscending:
                    sql = sql + " ORDER BY [Workspaces].[AccessCounter] ASC";
                    break;

                case SortOrderForWorkspaces.MostFrequentlyAccessedDescending:
                    sql = sql + " ORDER BY [Workspaces].[AccessCounter] DESC";
                    break;
            }
            return sql;
        }
    }

    /// <summary>
    /// Validation Classes
    /// </summary>
    public class DataTypeValidation
    {
        /// <summary>
        /// Checks the logistics of the WorkspaceName (not the DB)
        /// </summary>
        /// <returns>true if valid logistically, false otherwise</returns>
        public static bool IsValidWorkspaceName(string WorkspaceName) 
        {
            if ((String.IsNullOrEmpty(WorkspaceName)) ||
                (WorkspaceName.Length < 1) ||
                (WorkspaceName.Length > 75))
                return false;
            else
                return true; 
        }
        
        /// <summary>
        /// Use this to check the return of an ArtifactItemGroup
        /// </summary>
        /// <param name="artifactItems">ArtifactGroup</param>
        /// <returns>true if ArtifactItemGroup is Empty, false otherwise</returns>
        public static bool IsEmptyArtifactItemGroup(ArtifactItem[] artifactItems)
        {
            if ((artifactItems.Length == 1) && !artifactItems[0].IsLocationValid)
                return true;
            else               
                return false;
        }

        /// <summary>
        /// Use this to check the return of an WorkspaceItemGroup
        /// </summary>
        /// <param name="artifactItems">WorkspaceItemGroup</param>
        /// <returns>true if WorkspaceItemGroup is Empty, false otherwise</returns>
        public static bool IsEmptyWorkspaceItemGroup(WorkspaceItem[] workspaceItems)
        {
            if ((workspaceItems.Length == 1) && !workspaceItems[0].IsValid)
                return true;
            else
                return false;
        }

        /// <summary>
        /// Uset this for quick and easy DataSet Validation
        /// </summary>
        /// <param name="dataset">a dataset object</param>
        /// <returns>true if dataset is empty, false otherwise</returns>
        public static bool IsEmptyDataSet(DataSet dataset)
        {
            if ((dataset == null) ||
                (dataset.Tables.Count == 0) ||
                ((dataset.Tables.Count == 1) && (dataset.Tables[0].Rows.Count <= 0)))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// For internal use only - Check if the TableName entered is Valid
        /// </summary>
        /// <param name="TableName">a table name</param>
        /// <returns>true if valid logistically, false otherwise</returns>
        internal static bool IsValidTableName(string TableName)
        {
            if ((String.IsNullOrEmpty(TableName)) ||
                (TableName.Length < 1) ||
                (TableName.Length > 75))
                return false;
            else
                return true;
        }

        /// <summary>
        /// For internal use only - Check to see if Version information is valid
        /// </summary>
        /// <param name="VersionInformation">Version Information for a table</param>
        /// <returns>true if valid logistically, false otherwise</returns>
        internal static bool IsValidVersionInformation(string VersionInformation)
        {
            bool bIsValid = (!String.IsNullOrEmpty(VersionInformation) && (VersionInformation.Length == 8));
            if (bIsValid)
            {
                string[] versionEntities = VersionInformation.Split('.');
                bIsValid = (versionEntities.Length == 3);
            }
            return (bIsValid);
        }
    }

    /// <summary>
    /// Helper Classes
    /// </summary>
    public class DataTypeHelpers
    {
        /// <summary>
        /// Many Artifact Checking Functions (Except for Insert/modify) Only need the location,
        /// So if you have a location, use this function to create a quick Artifact to use in those
        /// checking functions
        /// </summary>
        /// <param name="location"></param>
        /// <returns></returns>
        public static ArtifactItem CreateLocationOnlyArtifact(string location)
        {
            ArtifactItem artifactItem = new ArtifactItem()
            {
                Location = location
            };
            return artifactItem;
        }

        /// <summary>
        /// Use this to create an empty ArtifactItemGroup (should only be used internally)
        /// </summary>
        /// <returns>An Empty ArtifactItemGroups</returns>
        internal static ArtifactItem[] EmptyArtifactItemGroup()
        {
            ArtifactItem[] artifactItems = new ArtifactItem[] { new ArtifactItem() { Location = "" } };
            return artifactItems;
        }

        /// <summary>
        /// Use this to create an empty WorkspaceItemGroup (should only be used internally)
        /// </summary>
        /// <returns>An Empty WorkspaceItemGroups</returns>
        internal static WorkspaceItem[] EmptyWorkspaceItemGroup()
        {
            WorkspaceItem[] workspaceItems = new WorkspaceItem[] { new WorkspaceItem() { Name = "" } };
            return workspaceItems;
        }

    }

    /// <summary>
    /// Use this class for some of our Workspace Methods. Holds Workspace Information as well
    /// as performs Validation. 
    /// </summary>
    public class WorkspaceItem
    {
        public string Name { get; set; }
        public DateTime LastAccessed { get; private set; }
        public int AccessCounter { get; set; }

        // Needed to make sure that dateTime is within limits of SQL,
        // Otherwise SQL stmt may generate an error
        public bool SetLastAccessed(DateTime dateTime)
        {
            if (dateTime >= SqlDateTime.MinValue.Value &&
                dateTime <= SqlDateTime.MaxValue.Value)
            {
                LastAccessed = dateTime;
                return true;
            }
            return false;
        }

        // *Custom Tag Property * To be used by Callers to tag the object
        public string Tag { get; set; }

        // default
        public WorkspaceItem()
        {
            Name = "";
            LastAccessed = SqlDateTime.MinValue.Value;
            AccessCounter = 0;

            // Tag
            Tag = "";
        }

        /// <summary>
        /// Performs basic Type Validity Tests
        /// </summary>
        public bool IsValid
        {
            get
            {
                if ((Name.Length > 1) &&
                    (Name.Length <= 75) &&
                    (AccessCounter >= 0) &&
                    (LastAccessed != SqlDateTime.MinValue.Value)
                    )
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        #region ICloneable Members
        public object Clone()
        {
            return this.MemberwiseClone();
        }
        #endregion
    }

    /// <summary>
    /// Use this Class for all our Artifact Methods. Holds Artifact Information as well
    /// as performs Validation. Use IsValidFileIntegrity() for IO validation
    /// </summary>
    public class ArtifactItem : ICloneable
    {
        public String Name { get; set; }
        public ArtifactTypes Type { get; set; }
        public String Location { get; set; }
        public String Note { get; set; }
        public String SnapshotFile { get; set; }
        public DateTime LastAccessed { get; private set; }
        public int AccessCounter { get; set; }

        // Needed to make sure that dateTime is within limits of SQL,
        // Otherwise SQL stmt may generate an error
        public bool SetLastAccessed(DateTime dateTime)
        {
            if (dateTime >= SqlDateTime.MinValue.Value &&
                dateTime <= SqlDateTime.MaxValue.Value)
            {
                LastAccessed = dateTime;
                return true;
            }
            return false;
        }

        // default
        public ArtifactItem()
        { 
            SetAsFileType();
            Name = "";
            Location = "";
            Note = "";
            SnapshotFile = "";

            // LinkProperties            
            WindowTop = 0;
            WindowLeft = 0;
            WindowHeight = 0;
            WindowWidth = 0;

            // Access properties
            LastAccessed = SqlDateTime.MinValue.Value;
            AccessCounter = 0;

            // Tag
            Tag = "";
        }

        // Type Check
        public bool IsUrl { get { return Type == ArtifactTypes.Url; } }
        public bool IsFile { get { return Type == ArtifactTypes.File; } }

        // Type Helpers
        public string FileName
        {
            get
            {
                if (IsFile)
                {
                    int nIndex = Location.LastIndexOf('\\');
                    if (nIndex > 0 && nIndex < Location.Length)
                        return Location.Substring((nIndex + 1));
                }
                return String.Empty;
            }            
        }
        public string FileLocation
        {
            get
            {
                if (IsFile)
                {
                    int nIndex = Location.LastIndexOf('\\');
                    if (nIndex > 0 && nIndex < Location.Length)
                        return Location.Substring(0,nIndex);
                }
                return String.Empty;
            }
        }

        // Type Setting
        public void SetAsFileType() { Type = ArtifactTypes.File; }
        public void SetAsUrlType() { Type = ArtifactTypes.Url; }
        public bool SetType(string strType)
        {
            if (strType.ToUpper() == "FILE")
            {
                SetAsFileType();
                return true;
            }
            else if (strType.ToUpper() == "URL")
            {
                SetAsUrlType();
                return true;
            }
            else
            {
                return false;
            }
        }

        // Setters
        public bool SetFile(string fileNameAndLocation)
        {
            if ((fileNameAndLocation.Length > 1) && File.Exists(fileNameAndLocation))
            {
                SetAsFileType();
                Location = fileNameAndLocation;
                return true;
            }
            return false;
        }
        public bool SetUrl(string Url)
        {
            if ((Url.Length > 1)) // To Do - Better Url Checking
            {
                SetAsUrlType();
                Location = Url;
                return true;
            }
            return false;
        }

        // *Custom Tag Property * To be used by Callers to tag the object
        public string Tag { get; set; }

        /// <summary>
        /// This Information is used by the link in the Workspace.
        /// ~This information is only filed in the artifact when being retrieved
        ///  from a workspace which has link information
        /// </summary>
        public int WindowTop { get; set; }
        public int WindowLeft { get; set; }
        public int WindowHeight { get; set; }
        public int WindowWidth { get; set; }

        /// <summary>
        /// Use this function to do proper validation of the Link Properties
        /// </summary>
        public bool AreWorkspaceLinkPropertiesValid
        {
            get
            {
                if ((WindowHeight > 0) &&
                    (WindowWidth > 0))
                    return true;
                else
                    return false;
            }
        }
             
        /// <summary>
        /// Performs basic Type Validity Tests
        /// </summary>
        public bool IsValid 
        { 
            get 
            {
                if((Name.Length > 1) &&
                   (Name.Length <= 150) &&
                   (Location.Length > 1) &&
                   (Location.Length <= 300) &&
                   (Note.Length <= 3000) && 
                   (SnapshotFile.Length > 1) &&
                   (SnapshotFile.Length <= 300) &&
                   (AccessCounter >= 0) //&&
                   //(LastAccessed != SqlDateTime.MinValue.Value)
                  )
                {                                       
                    return true;
                }
                else
                {
                    return false;
                }
            } 
        }

        /// <summary>
        /// Since Artifact Location is our main source of determining
        /// existence (this provides an easy check only for valid location)
        /// </summary>
        public bool IsLocationValid
        {
            get
            {
                if ((Location.Length > 1) &&
                    (Location.Length <= 300))
                    return true;
                else
                    return false;
            }
        }

        /// <summary>
        /// Performs Advanced File Validity Tests
        /// </summary>
        public bool IsValidFileIntegrity
        {
            get
            {
                if (IsFile && !File.Exists(Location))
                    return false;

                // To Do * Check if is Valid Url *

                if (!File.Exists(SnapshotFile))
                    return false;                

                return true;
            }
        }

        #region ICloneable Members
        public object Clone()
        {            
            return this.MemberwiseClone();
        }
        #endregion
    }
    
}
