using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlServerCe;
using System.IO;
using Foo.DataAccessLayer.DataTypes;

namespace Foo.DataAccessLayer
{
    public class dArtifacts
    {
        /// <summary>
        /// Checks to see if this artifact is already in the system. The Location is the UniqueID
        /// so no other artifact may exist that has the exact same location
        /// </summary>
        /// <param name="artifactItem">Artifact To Check (Location Needed Only)</param>
        /// <returns>true if found, false otherwise</returns>
        public bool DoesArtifactExistInSystem(ArtifactItem artifactItem)
        {
            // Check Artifact Integrity
            if ((artifactItem == null) || 
                !artifactItem.IsLocationValid)
                 return false;

            object obj = null;
            lock (this)
            {
                string sql = "SELECT [UID] FROM Artifacts WHERE [Location] = @location";
                SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
                obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
            }
            return (obj != null);
        }

        /// <summary>
        /// Searches all Artifact's Names & Notes for the specified SearchQuery using SQL's Like stmt
        /// </summary>
        /// <param name="SearchQuery">string to use in 'Like' (Must be less than 75 Characters)</param>
        /// <param name="SortOrder">Specify Sort Order</param>
        /// <returns>returns ArtifactItem[] of all found artifacts</returns>
        public ArtifactItem[] SearchArtifactsInTheSystem(string SearchQuery, SortOrderForArtifacts SortOrder)
        {
            if (!String.IsNullOrEmpty(SearchQuery) && (SearchQuery.Length <= 75))
            {
                lock (this)
                {
                    DataSet dataset = SearchArtifactsInTheSystemIntoDataSet(SearchQuery, SortOrder);                    
                    if (!DataTypeValidation.IsEmptyDataSet(dataset))
                    {
                        int nRows = dataset.Tables[0].Rows.Count;
                        ArtifactItem[] resultArtifacts = new ArtifactItem[nRows];

                        for (int i = 0; i < nRows; ++i)
                        {
                            DataRow datarow = dataset.Tables[0].Rows[i];
                            resultArtifacts[i] = new ArtifactItem();

                            // Add Artifact Fields
                            resultArtifacts[i].Name = datarow["Name"].ToString();
                            resultArtifacts[i].SetType(datarow["Type"].ToString());
                            resultArtifacts[i].Location = datarow["Location"].ToString();
                            resultArtifacts[i].Note = datarow["Note"].ToString();
                            resultArtifacts[i].SnapshotFile = datarow["SnapShotFile"].ToString();

                            if (!String.IsNullOrEmpty(datarow["LastAccessed"].ToString()))
                                resultArtifacts[i].SetLastAccessed(DateTime.Parse(datarow["LastAccessed"].ToString()));

                            if (!String.IsNullOrEmpty(datarow["AccessCounter"].ToString()))
                                resultArtifacts[i].AccessCounter = int.Parse(datarow["AccessCounter"].ToString());
                        }
                        return resultArtifacts;
                    }
                }
            }

            // return Blank Item
            return DataTypeHelpers.EmptyArtifactItemGroup(); 
        }

        /// <summary>
        /// Searches all Artifact's Names & Notes for the specified SearchQuery using SQL's Like stmt
        /// </summary>
        /// <param name="SearchQuery">string to use in 'Like' (Must be less than 75 Characters)</param>
        /// <param name="SortOrder">Specify Sort Order</param>
        /// <returns>returns DataSet of all found artifacts</returns>
        public DataSet SearchArtifactsInTheSystemIntoDataSet(string SearchQuery, SortOrderForArtifacts SortOrder)
        {
            if (!String.IsNullOrEmpty(SearchQuery) && (SearchQuery.Length <= 75))
            {
                lock (this)
                {
                    string sql = "SELECT [Name],[Type],[Location],[Note],[SnapShotFile],[LastAccessed],[AccessCounter] FROM Artifacts";
                    sql = sql + String.Format(" WHERE [Name] LIKE '%{0}%' OR [Note] LIKE '%{0}%' OR [Location] LIKE '%{0}%'", SearchQuery);
                    sql = SortOrderSQLHelpers.SortOrderForArtifactsHelper(sql, SortOrder);
                    DataSet dataset = DB.RunSQLTextFillDataSet(sql);
                    return dataset;
                }
            }
            return new DataSet(); // empty dataset
        }

        /// <summary>
        /// Returns an ArtifactItem[] of all Artifacts in the System (WorkspaceLinkProperties won't be filled in)
        /// </summary>
        /// <param name="SortOrder">Specify Sort Order</param>
        /// <returns>returns ArtifactItem[] of all artifacts</returns>
        public ArtifactItem[] GetAllArtifactsInTheSystem(SortOrderForArtifacts SortOrder)
        {
            lock (this)
            {
                DataSet dataset = GetAllArtifactsInTheSystemIntoDataSet(SortOrder);
                if (!DataTypeValidation.IsEmptyDataSet(dataset))
                {
                    int nRows = dataset.Tables[0].Rows.Count;
                    ArtifactItem[] resultArtifacts = new ArtifactItem[nRows];

                    for (int i = 0; i < nRows; ++i)
                    {
                        DataRow datarow = dataset.Tables[0].Rows[i];
                        resultArtifacts[i] = new ArtifactItem();

                        // Add Artifact Fields
                        resultArtifacts[i].Name = datarow["Name"].ToString();
                        resultArtifacts[i].Type = (ArtifactTypes) Enum.Parse(typeof(ArtifactTypes), datarow["Type"].ToString(), true);
                        resultArtifacts[i].Location = datarow["Location"].ToString();
                        resultArtifacts[i].Note = datarow["Note"].ToString();
                        resultArtifacts[i].SnapshotFile = datarow["SnapShotFile"].ToString();

                        if (!String.IsNullOrEmpty(datarow["LastAccessed"].ToString()))
                            resultArtifacts[i].SetLastAccessed(DateTime.Parse(datarow["LastAccessed"].ToString()));

                        if (!String.IsNullOrEmpty(datarow["AccessCounter"].ToString()))
                            resultArtifacts[i].AccessCounter = int.Parse(datarow["AccessCounter"].ToString());
                    }
                    return resultArtifacts;
                }
            }

            // return Blank Item
            return DataTypeHelpers.EmptyArtifactItemGroup();  
        }

        /// <summary>
        /// Returns a DataSet of All Artifacts in the System (WorkspaceLinkProperties won't be filled in)
        /// </summary>
        /// <param name="SortOrder">Specify Sort Order</param>
        /// <returns>returns DataSet of all artifacts</returns>
        public DataSet GetAllArtifactsInTheSystemIntoDataSet(SortOrderForArtifacts SortOrder)
        {
            lock (this)
            {
                string sql = "SELECT [Name],[Type],[Location],[Note],[SnapShotFile],[LastAccessed],[AccessCounter] FROM Artifacts";
                sql = SortOrderSQLHelpers.SortOrderForArtifactsHelper(sql, SortOrder);
                DataSet dataset = DB.RunSQLTextFillDataSet(sql);
                return dataset;
            }
        }

        /// <summary>
        /// Increments the access counter and sets LastAccessed for the 
        /// specified artifact. Call this whenever you have launched an Artifact.
        /// </summary>
        /// <param name="artifactItem">Artifact To Check (Location Needed Only)</param>
        /// <returns>true if successful set the internal counters, false otherwise</returns>
        public bool ArtifactWasLaunched(ArtifactItem artifactItem)
        {
            // Check Artifact Validity
            if ((artifactItem == null) ||
                !artifactItem.IsLocationValid)
                return false;            

            lock (this)
            {
                // existence check
                if (!DoesArtifactExistInSystem(artifactItem))
                    return false;

                // First Step - is to get the AccessCounter already in the db
                string sql = "SELECT [AccessCounter] FROM Artifacts WHERE [Location]=@location";
                SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };

                int accesscount = 1;
                object obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
                if (obj != null)
                {
                    accesscount = int.Parse(obj.ToString());
                    accesscount = accesscount + 1; // increment by 1
                }

                // Second Step - is to set the access counter and today's date for the artifact
                string sql2 = "UPDATE Artifacts SET [LastAccessed]=@lastaccessed,[AccessCounter]=@accesscounter WHERE [Location]=@location";
                SqlCeParameter[] sqlparams2 = new SqlCeParameter[]
                {
                    new SqlCeParameter("@lastaccessed", DateTime.Now),
                    new SqlCeParameter("@accesscounter", accesscount),
                    new SqlCeParameter("@location", artifactItem.Location),
                };

                int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
                return (nResult == 1);
            }
        }

        /// <summary>
        /// Check to see if the artifact is part of the workspace
        /// </summary>
        /// <param name="WorkspaceName">WorskpaceName to check the Artifact against</param>
        /// <param name="artifactItem">Artifact To Check (Location Needed Only)</param>
        /// <returns>true, if part of the specified workspace, false otherwise</returns>
        public bool IsArtifactPartOfWorkspace(string WorkspaceName, ArtifactItem artifactItem)
        {
            // Check Artifact & Workspace Validity
            if ((artifactItem == null) || 
                !artifactItem.IsLocationValid ||
                !DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
                return false;

            object obj = null;
            lock (this)
            {
                // Check to make sure that this is a valid WorkspaceName
                if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
                    return false;

                // First Step - Get the UID of the Artifact to look up in the Links table
                string sql = "SELECT [UID] FROM Artifacts WHERE [Location] = @location";
                SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
                obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
                
                if (obj != null)
                {
                    int uid = int.Parse(obj.ToString());

                    // Second Step - Lookup if there is any item in the Links table that matches the uid and workspace name
                    string sql2 = "SELECT [UID] FROM WorkspaceLinks WHERE [AID] = @aid AND [WorkspaceName] = @workspacename";
                    SqlCeParameter[] sqlparams2 = new SqlCeParameter[] 
                    { 
                        new SqlCeParameter("@aid", uid),
                        new SqlCeParameter("@workspacename", WorkspaceName),
                    };

                    obj = DB.RunSQLCommandTextExecuteScalar(sql2, sqlparams2);
                    return (obj != null);
                }
            }
            return false;
        }

        /// <summary>
        /// Uses The workspace stored in the State Table and determines if the Artifact is part of that Workspace
        /// </summary>
        /// <param name="artifactItem">Artifact To Check (Location Needed Only)</param>
        /// <returns>true, if part of the current workspace in the state table, false otherwise</returns>
        public bool IsArtifactPartOfCurrentWorkspaceState(ArtifactItem artifactItem)
        {
            // Check validity of the Artifact
            if ((artifactItem == null) || 
                !artifactItem.IsLocationValid)
                return false;

            lock(this)
            {
                string CurrentWorkspace = Data.State.GetCurrentWorkspaceName();
                if (!String.IsNullOrEmpty(CurrentWorkspace))
                {
                    return IsArtifactPartOfWorkspace(CurrentWorkspace, artifactItem);
                }
            }
            return false;
        }

        /// <summary>
        /// Use this when you have an Artifact that doesn't have any WorkspaceLink Properties and you
        /// want to fill the Artifact's WorkspaceLink properties with the first artifact that matches the
        /// specified workspace sort order
        /// </summary>
        /// <param name="artifactItem">artifactItem without WorkspaceLink Properties (Location Needed Only)</param>
        /// <param name="sortOrder">SortOrder of workspace to use when filling the first found artifact that matches</param>
        /// <returns>an artifact item with workspaceLink properties filled out if successfull</returns>
        public ArtifactItem GetWorkspaceLinkPropertiesForArtifact(ArtifactItem artifactItem, SortOrderForWorkspaces sortOrder)
        {
            // ensure artifact integrity
            if ((artifactItem == null) ||
               !(artifactItem.IsLocationValid))
                return artifactItem; // nothing filled out

            lock (this)
            {
                // First Step - Get the UID of the artifact
                string sql = "SELECT [UID] FROM Artifacts WHERE [Location] = @location";
                SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
                object obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);

                if (obj != null)
                {
                    int aid = int.Parse(obj.ToString());
                    
                    // Second Step - is to get the WorkspaceLink that matches the artifact by the sort order
                    string sql2 = "SELECT [WorkspaceLinks].[WindowTop], [WorkspaceLinks].[WindowLeft],[WorkspaceLinks].[WindowHeight], [WorkspaceLinks].[WindowWidth]"; 
                    sql2 = sql2 + " FROM [WorkspaceLinks] , [Workspaces] WHERE [WorkspaceLinks].[WorkspaceName] = [Workspaces].[Name] AND [WorkspaceLinks].[AID]=@aid";

                    // Add WorkspacesSortOrder
                    sql2 = SortOrderSQLHelpers.SortOrderForWorkspacesHelper(sql2, sortOrder);

                    SqlCeParameter[] sqlparams2 = new SqlCeParameter[] { new SqlCeParameter("@aid", aid) };
                    
                    DataSet dataset = DB.RunSQLTextFillDataSet(sql2, sqlparams2);
                    if (!DataTypeValidation.IsEmptyDataSet(dataset))
                    {                                                
                        // Just get the first item
                        DataRow datarow = dataset.Tables[0].Rows[0];

                        // Clone the original artifact
                        ArtifactItem resultArtifact = (ArtifactItem) artifactItem.Clone();                                               
                        
                        // Add Artifact Fields
                        resultArtifact.WindowTop = int.Parse(datarow["WindowTop"].ToString());
                        resultArtifact.WindowLeft = int.Parse(datarow["WindowLeft"].ToString());
                        resultArtifact.WindowHeight = int.Parse(datarow["WindowHeight"].ToString());
                        resultArtifact.WindowWidth = int.Parse(datarow["WindowWidth"].ToString());                                                
                        return resultArtifact;
                    }
                }
            }

            // nothing filled out
            return artifactItem;
        }

        /// <summary>
        /// Retrieve all Artifacts associated with the specified Workspace (uses links table to determine which artifacts)
        /// </summary>
        /// <param name="WorkspaceName">The WorkspaceName for which to get all Artifacts</param>
        /// <param name="SortBy">Specify Sort Order</param>
        /// <returns>Group of Artifact Items, Could be Empty, use DataTypeValidator to check for Empty ArtifactGroup</returns>
        public ArtifactItem[] GetAllArtifactsForWorkspace(string WorkspaceName, SortOrderForArtifacts SortBy)
        {
            // Ensure Workspace Name Integrity
            if (!DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
                return DataTypeHelpers.EmptyArtifactItemGroup();  // return Blank Item

            lock (this)
            {
                // Check to make sure that this is a valid WorkspaceName (in DB)
                if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
                    return DataTypeHelpers.EmptyArtifactItemGroup(); // return Blank Item

                // First Step - Use a Join to get all the matching artifacts
                string sql = "SELECT [Artifacts].[Name], [Artifacts].[Type], [Artifacts].[Location], [Artifacts].[Note], [Artifacts].[SnapShotFile], [Artifacts].[LastAccessed], [Artifacts].[AccessCounter], [WorkspaceLinks].[WindowTop], "; 
                sql = sql + "[WorkspaceLinks].[WindowLeft], [WorkspaceLinks].[WindowHeight], [WorkspaceLinks].[WindowWidth], [WorkspaceLinks].[WorkspaceName] ";
                sql = sql + "FROM [WorkspaceLinks] , [Artifacts] ";
                sql = sql + "WHERE [WorkspaceLinks].[AID] = [Artifacts].[UID] AND [WorkspaceLinks].[WorkspaceName] = @workspacename ";

                // Add ArtifactsSortOrder
                sql = SortOrderSQLHelpers.SortOrderForArtifactsHelper(sql, SortBy);
                
                SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@workspacename", WorkspaceName) };
                
                DataSet dataset = DB.RunSQLTextFillDataSet(sql, sqlparams);
                if (!DataTypeValidation.IsEmptyDataSet(dataset))
                {                
                    int nRows = dataset.Tables[0].Rows.Count;
                    ArtifactItem[] resultArtifacts = new ArtifactItem[nRows];

                    for (int i = 0; i < nRows; ++i)
                    {
                        DataRow datarow = dataset.Tables[0].Rows[i];
                        resultArtifacts[i] = new ArtifactItem();

                        // Add Artifact Fields
                        resultArtifacts[i].Name = datarow["Name"].ToString();
                        resultArtifacts[i].Type = (ArtifactTypes)Enum.Parse(typeof(ArtifactTypes), datarow["Type"].ToString(), true);
                        resultArtifacts[i].Location = datarow["Location"].ToString();
                        resultArtifacts[i].Note = datarow["Note"].ToString();
                        resultArtifacts[i].SnapshotFile = datarow["SnapShotFile"].ToString();  
                        
                        if(!String.IsNullOrEmpty(datarow["LastAccessed"].ToString()))
                            resultArtifacts[i].SetLastAccessed(DateTime.Parse(datarow["LastAccessed"].ToString()));

                        if (!String.IsNullOrEmpty(datarow["AccessCounter"].ToString()))
                            resultArtifacts[i].AccessCounter = int.Parse(datarow["AccessCounter"].ToString());

                        resultArtifacts[i].WindowTop = int.Parse(datarow["WindowTop"].ToString());
                        resultArtifacts[i].WindowLeft = int.Parse(datarow["WindowLeft"].ToString());
                        resultArtifacts[i].WindowHeight = int.Parse(datarow["WindowHeight"].ToString());
                        resultArtifacts[i].WindowWidth = int.Parse(datarow["WindowWidth"].ToString());
                    }
                    return resultArtifacts;
                }                               
                                
            }

            // return Blank Item
            return DataTypeHelpers.EmptyArtifactItemGroup();
        }

        /// <summary>
        /// Get's the artifact link count for the passed in workspace
        /// </summary>
        /// <param name="WorkspaceName">The WorkspaceName for which to get all Artifact Links</param>
        /// <returns>0 or positive number for the number of records, -1 if error occurs</returns>
        public int GetArtifactLinkCountForWorkspace(string WorkspaceName)
        {
            // Ensure Workspace Name Integrity
            if (!DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
                return -1;  // return error

            lock (this)
            {
                // Check to make sure that this is a valid WorkspaceName (in DB)
                if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
                    return -1; // return Blank Item

                // First Step - Get the count of all artifacts for this workspace
                string sql = "SELECT COUNT([WorkspaceLinks].[AID]) FROM [WorkspaceLinks] WHERE [WorkspaceLinks].[WorkspaceName] = @workspacename";                
                SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@workspacename", WorkspaceName) };

                object obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
                if (obj != null)
                {
                    int i = int.Parse(obj.ToString());
                    return i;
                }
            }
            return -1; // return error
        }

        /// <summary>
        /// Get's the unique artifact link count for the passed in workspace (this means only artifact links
        /// that are unique to this workspace)
        /// </summary>
        /// <param name="WorkspaceName">The WorkspaceName for which to get all unique Artifact Links</param>
        /// <returns>0 or positive number for the number of records, -1 if error occurs</returns>
        public int GetUniqureArtifactsCountForWorkspace(string WorkspaceName)
        {
            // Ensure Workspace Name Integrity
            if (!DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
                return -1;  // return Blank Item

            lock (this)
            {
                // Check to make sure that this is a valid WorkspaceName (in DB)
                if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
                    return -1; // return Blank Item

                // First Step - We need all the links that are part of the workspace in the links table
                string sql2 = "SELECT [AID] FROM WorkspaceLinks WHERE [WorkspaceName]=@workspacename";
                SqlCeParameter[] sqlparams2 = new SqlCeParameter[] { new SqlCeParameter("@workspacename", WorkspaceName) };

                DataSet dataset = DB.RunSQLTextFillDataSet(sql2, sqlparams2);
                List<int> workspaceLinksListAIDs = new List<int>();

                if (!DataTypeValidation.IsEmptyDataSet(dataset))
                {
                    foreach (DataRow row in dataset.Tables[0].Rows)
                        workspaceLinksListAIDs.Add(int.Parse(row[0].ToString()));
                }

                // Second Step - We now should check which AIDs are not referenced anywhere else, those AIDS are
                //               counted as being unique to this workspace
                string sql4 = "SELECT [UID] FROM WorkspaceLinks WHERE [AID]=@aid AND [WorkspaceName]<>@workspacename";
                List<int> workspaceLinksListAIDsWithoutReferences = new List<int>();

                foreach (int aid in workspaceLinksListAIDs)
                {
                    SqlCeParameter[] sqlparams4 = new SqlCeParameter[] { new SqlCeParameter("@aid", aid), new SqlCeParameter("@workspacename", WorkspaceName) };
                    object obj = DB.RunSQLCommandTextExecuteScalar(sql4, sqlparams4);

                    if (obj == null) // this aid has no references
                        workspaceLinksListAIDsWithoutReferences.Add(aid);
                }

                return workspaceLinksListAIDsWithoutReferences.Count;                
            }
        }

        /// <summary>
        /// Adds an Artifact to a Workspace (shouldn't already be in that workspace)
        /// If the artifact already exists and the only thing being done is that the artifact is
        /// being added to a new workspace (a link will be created)
        /// </summary>
        /// <param name="WorkspaceName">WorkspaceName to insert Artifact into</param>
        /// <param name="artifactItem">the Artifact to Add (Must be complete - pass All Validations)</param>
        /// <returns>true if successful, false otherwise</returns>
        public bool AddArtifactToWorkspace(string WorkspaceName, ArtifactItem artifactItem)
        {
            // ensure artifact and workspace integrity
            if ((artifactItem == null) || 
               !(artifactItem.IsValid) || 
               !(artifactItem.IsLocationValid) ||
               !(artifactItem.IsValidFileIntegrity) ||
               !(artifactItem.AreWorkspaceLinkPropertiesValid) ||
               !DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
                return false;

            lock (this)
            {
                // Check to make sure that this is a valid WorkspaceName
                if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
                    return false;

                ////
                // Do a little more Integrity Checking, to know where we are at
                ////
                bool bExists = DoesArtifactExistInSystem(artifactItem);
                bool bAlreadyInWorkspace = false;

                if(bExists)
                   bAlreadyInWorkspace = IsArtifactPartOfWorkspace(WorkspaceName, artifactItem);

                // If we already have it in this workspace, just modify the
                // Artifact's Properties & Workspace Properties
                if (bAlreadyInWorkspace)
                    return ModifyExistingArtifactProperties(artifactItem, WorkspaceName); // * also modify workspacelink properties *

                // if it exists, but is not part of this workspace, then we should create a link for the artifact and
                // update any of the artifact's properties
                if (bExists && !bAlreadyInWorkspace)
                {
                    // First Step - Get the UID of the artifact
                    string sql = "SELECT [UID] FROM Artifacts WHERE [Location] = @location";
                    SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
                    object obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);

                    if (obj != null)
                    {
                        int aid = int.Parse(obj.ToString());
                        int uid = 0;

                        // Second Step - Is to get the Max UID for the Links table to Insert to
                        string sql2 = "SELECT MAX (UID) FROM WorkspaceLinks";
                        object obj2 = DB.RunSQLCommandTextExecuteScalar(sql2);

                        if (obj2 != null)
                        {
                            uid = int.Parse(obj2.ToString());
                            uid = uid + 1; // incr. by one
                        }

                        // Third Step - Create a new Entry for this workspace in the Links Table
                        string sql3 = "INSERT INTO WorkspaceLinks ([UID],[AID],[WorkspaceName],[WindowTop],[WindowLeft],[WindowHeight],[WindowWidth])";
                        sql3 = sql3 + " VALUES (@uid,@aid,@workspacename,@windowtop,@windowleft,@windowheight,@windowwidth)";
                        SqlCeParameter[] sqlparams3 = new SqlCeParameter[] 
                        { 
                            new SqlCeParameter("@uid", uid),
                            new SqlCeParameter("@aid", aid),
                            new SqlCeParameter("@workspacename", WorkspaceName),
                            new SqlCeParameter("@windowtop", artifactItem.WindowTop),
                            new SqlCeParameter("@windowleft", artifactItem.WindowLeft),
                            new SqlCeParameter("@windowheight", artifactItem.WindowHeight),
                            new SqlCeParameter("@windowwidth", artifactItem.WindowWidth),
                        };

                        int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql3, sqlparams3);
                        if (nResult != 1)
                            return false;

                        // Now we can just Modify the Artifact's Properties, in case they changed
                        return ModifyExistingArtifactProperties(artifactItem); // no need to modify workspace properties here - only modify artifact
                    }
                }
                else
                {
                            
                    // First Step - Is to get the Max UID for the Artifact table to Insert to
                    int uid = 0;
                    string sql = "SELECT MAX (UID) FROM Artifacts";
                    object obj = DB.RunSQLCommandTextExecuteScalar(sql);

                    if (obj != null)
                    {
                        uid = int.Parse(obj.ToString());
                        uid = uid + 1; // incr. by one
                    }

                    // Second Step - Is to Actually Insert the new Artifact into the Artifact Table
                    string sql3 = "INSERT INTO Artifacts ([UID],[Name],[Type],[Location],[Note],[SnapShotFile],[LastAccessed],[AccessCounter]) "; 
                    sql3 = sql3 + "VALUES (@uid,@name,@type,@location,@note,@snapshotfile,@accessed,@counter)";
                    SqlCeParameter[] sqlparams3 = new SqlCeParameter[] 
                    { 
                        new SqlCeParameter("@uid", uid),
                        new SqlCeParameter("@name", artifactItem.Name),
                        new SqlCeParameter("@type", artifactItem.Type.ToString()),
                        new SqlCeParameter("@location", artifactItem.Location),
                        new SqlCeParameter("@note", artifactItem.Note),
                        new SqlCeParameter("@snapshotfile", artifactItem.SnapshotFile),                        
                        new SqlCeParameter("@accessed", DateTime.Now),
                        new SqlCeParameter("@counter", "0"),
                    };

                    int nResult = 0;
                    nResult = DB.RunSQLCommandTextExecuteNonQuery(sql3, sqlparams3);
                    if (nResult != 1)
                        return false;

                    // Third Step - Get the highest UID for the Link table
                    int aid = uid; // save the uid of the artifact as the aid
                    uid = 0;
                    string sql4 = "SELECT MAX (UID) FROM WorkspaceLinks";
                    object obj4 = DB.RunSQLCommandTextExecuteScalar(sql4);

                    if (obj != null)
                    {
                        uid = int.Parse(obj4.ToString());
                        uid = uid + 1; // incr. by one
                    }                                                       

                    // Fourth Step - Is to Now Insert the Link to the Workspace into the Links Table
                    string sql5 = "INSERT INTO WorkspaceLinks ([UID],[AID],[WorkspaceName],[WindowTop],[WindowLeft],[WindowHeight],[WindowWidth]) VALUES (@uid,@aid,@workspacename,@windowtop,@windowleft,@windowheight,@windowwidth)";
                    SqlCeParameter[] sqlparams5 = new SqlCeParameter[] 
                        { 
                            new SqlCeParameter("@uid", uid),
                            new SqlCeParameter("@aid", aid),
                            new SqlCeParameter("@workspacename", WorkspaceName),
                            new SqlCeParameter("@windowtop", artifactItem.WindowTop),
                            new SqlCeParameter("@windowleft", artifactItem.WindowLeft),
                            new SqlCeParameter("@windowheight", artifactItem.WindowHeight),
                            new SqlCeParameter("@windowwidth", artifactItem.WindowWidth),
                        };

                    nResult = DB.RunSQLCommandTextExecuteNonQuery(sql5, sqlparams5);
                    if (nResult != 1)
                        return false;
                    else
                        return true;
                }
            }            
            return false;
        }

        /// <summary>
        /// Deletes Artifact from the workspace (if no more references exists),
        /// will delete the artifact entirely (in best scenario only a link will be deleted)
        /// </summary>
        /// <param name="WorkspaceName">WorkspaceName to Delete Artifact From</param>
        /// <param name="artifactItem">Artifact To Delete (Location Needed Only)</param>
        /// <returns>true if successful, false otherwise</returns>
        public bool DeleteArtifact(string WorkspaceName, ArtifactItem artifactItem)
        {
            // ensure artifact and workspace integrity
            if ((artifactItem == null) ||
               !(artifactItem.IsLocationValid) ||
               !DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
                return false;
            
            lock (this)
            {
                // Check to make sure that this is a valid Artifact
                if (!DoesArtifactExistInSystem(artifactItem))
                    return false;

                // Check to make sure that this is a valid WorkspaceName
                if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
                    return false;

                // First Step - Is to get the UID of the Artifact
                string sql1 = "SELECT [UID] FROM Artifacts WHERE [Location]=@location";
                SqlCeParameter[] sqlparams1 = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };

                object obj = DB.RunSQLCommandTextExecuteScalar(sql1, sqlparams1);
                if (obj != null)
                {
                    int uid = int.Parse(obj.ToString());

                    // Second Step - Is to Delete the Link in the Link Table
                    string sql2 = "DELETE FROM WorkspaceLinks WHERE [WorkspaceName]=@workspacename AND [AID]=@aid";
                    SqlCeParameter[] sqlparams2 = new SqlCeParameter[] 
                    { 
                        new SqlCeParameter("@workspacename", WorkspaceName) ,
                        new SqlCeParameter("@aid", uid) 
                    };

                    // We hope there at least one link in the links table (but we don't verify)
                    DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);                    

                    // Third Step - Next is to see if there are any other Links Left with this AID
                    string sql3 = "SELECT [UID] FROM WorkspaceLinks WHERE [AID]=@aid";
                    SqlCeParameter[] sqlparams3 = new SqlCeParameter[] { new SqlCeParameter("@aid", uid) };

                    object obj3 = DB.RunSQLCommandTextExecuteScalar(sql3, sqlparams3);
                    if (obj3 == null)
                    {
                        // Fourth Step - Only if there are no other more links, Delete the Actually Artifact from the 
                        //               Artifact Table
                        string sql4 = "DELETE From Artifacts WHERE [UID]=@uid";
                        SqlCeParameter[] sqlparams4 = new SqlCeParameter[] { new SqlCeParameter("@uid", uid) };

                        int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql4, sqlparams4);
                        if (nResult != 1)
                            return false;
                        else
                            return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// Forces Deletion of the Artifact and all Links / References in the System
        /// </summary>
        /// <param name="artifactItem">Artifact To Delete (Location Needed Only)</param>
        /// <returns>true if successful, false otherwise</returns>
        public bool DeleteArtifact(ArtifactItem artifactItem)
        {
            // ensure artifact integrity
            if ((artifactItem == null) ||
               !(artifactItem.IsLocationValid))
                return false;

            lock (this)
            {

                // Check to make sure that this is a valid Artifact
                if (!DoesArtifactExistInSystem(artifactItem))
                    return false;

                // First Step - Is to get the UID of the Artifact
                string sql1 = "SELECT [UID] FROM Artifacts WHERE [Location]=@location";
                SqlCeParameter[] sqlparams1 = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };

                object obj = DB.RunSQLCommandTextExecuteScalar(sql1, sqlparams1);
                if (obj != null)
                {
                    int uid = int.Parse(obj.ToString());

                    // Second Step - Is to Delete all the Links refering to the Artifact in the Links Table
                    string sql2 = "DELETE FROM WorkspaceLinks WHERE [AID]=@aid";
                    SqlCeParameter[] sqlparams2 = new SqlCeParameter[] { new SqlCeParameter("@aid", uid) };

                    DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
                    
                    // Third Step - Delete the Artifact from the Artifact Table
                    string sql3 = "DELETE From Artifacts WHERE [UID]=@uid";
                    SqlCeParameter[] sqlparams3 = new SqlCeParameter[] { new SqlCeParameter("@uid", uid) };

                    int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql3, sqlparams3);
                    if (nResult != 1)
                        return false;
                    else
                        return true;                    
                }                
            }
            return false;
        }

        /// <summary>
        /// Modify Properties of an Artifact. Artifact's Location is the Unique Key,
        /// it must already exist in the system for this update to work. 
        /// (this will only update Artifact Properties Not WorkspaceLink Properties)
        /// </summary>
        /// <param name="artifactItem">the Artifact to Modify (Must be complete - pass All Validations)</param>
        /// <returns>true if successful, false otherwise</returns>
        public bool ModifyExistingArtifactProperties(ArtifactItem artifactItem)
        {
            // ensure artifact integrity
            if ((artifactItem == null) ||
               !(artifactItem.IsValid) ||
               !(artifactItem.IsLocationValid) ||
               !(artifactItem.IsValidFileIntegrity))
                return false;
           
            object obj = null;
            lock (this)
            {
                // ensure existence
                if (!DoesArtifactExistInSystem(artifactItem))
                    return false;

                // First Step - Get the UID of the Artifact so that we can update it
                string sql = "SELECT [UID] FROM Artifacts WHERE [Location] = @location";
                SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
                obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);

                if (obj != null)
                {
                    int uid = int.Parse(obj.ToString());

                    // Second Step - Is to Create the Update Statement to update the Artifact                    
                    string sql2 = "UPDATE Artifacts SET [Name]=@name,[Type]=@type,[Location]=@location,[Note]=@note,[SnapShotFile]=@snapshotfile, [LastAccessed]=@accessed, [AccessCounter]=@counter ";
                    sql2 = sql2 + "WHERE [UID]=@uid";
                    SqlCeParameter[] sqlparams2 = new SqlCeParameter[] 
                    { 
                        new SqlCeParameter("@uid", uid),
                        new SqlCeParameter("@name", artifactItem.Name),
                        new SqlCeParameter("@type", artifactItem.Type.ToString()),
                        new SqlCeParameter("@location", artifactItem.Location),
                        new SqlCeParameter("@note", artifactItem.Note),
                        new SqlCeParameter("@snapshotfile", artifactItem.SnapshotFile),                        
                        new SqlCeParameter("@accessed", artifactItem.LastAccessed),
                        new SqlCeParameter("@counter", artifactItem.AccessCounter),            
                    };

                    int nResult = 0;
                    nResult = DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);

                    if (nResult != 1)
                        return false;
                    else
                        return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Modify Properties of an Artifact and the properties of a workspaceLink.
        /// Artifact's Location is the Unique Key, it must already exist in the system.
        /// </summary>
        /// <param name="artifactItem">the Artifact to Modify (Must be complete - pass All Validations)</param>
        /// <param name="WorkspaceName">the workspaceName whose Link properties to modify</param>
        /// <returns>true if successful, false otherwise</returns>
        public bool ModifyExistingArtifactProperties(ArtifactItem artifactItem, string WorkspaceName)
        {
            // ensure artifact and workspace integrity
            if ((artifactItem == null) ||
               !(artifactItem.IsValid) ||
               !(artifactItem.IsLocationValid) ||
               !(artifactItem.IsValidFileIntegrity) ||
               !(artifactItem.AreWorkspaceLinkPropertiesValid) ||
               !DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
                return false;

            lock (this)
            {                
                // First Step - modify the Artifact's Properties *if fails, return*
                if (!ModifyExistingArtifactProperties(artifactItem))
                    return false;

                // Now Check Validity of the Workspace Properties before continuing
                if (!artifactItem.AreWorkspaceLinkPropertiesValid)
                    return false;

                // Ensure existence of WorkspaceName
                if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
                    return false;

                // Second Step - get the AID for the Artifact                
                string sql = "SELECT [UID] FROM Artifacts WHERE [Location] = @location";
                SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
                object obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);

                if (obj != null)
                {
                    int uid = int.Parse(obj.ToString());

                    // Third Step - Is to Update the Workspace Link Properties
                    string sql2 = "UPDATE WorkspaceLinks SET [WindowTop]=@windowtop,[WindowLeft]=@windowleft,[WindowHeight]=@windowheight,[WindowWidth]=@windowwidth ";
                    sql2 = sql2 + "WHERE [AID]=@uid AND [WorkspaceName] = @workspacename";
                    SqlCeParameter[] sqlparams2 = new SqlCeParameter[] 
                    { 
                        new SqlCeParameter("@windowtop", artifactItem.WindowTop),
                        new SqlCeParameter("@windowleft", artifactItem.WindowLeft),
                        new SqlCeParameter("@windowheight", artifactItem.WindowHeight),
                        new SqlCeParameter("@windowwidth", artifactItem.WindowWidth),
                        new SqlCeParameter("@uid", uid),
                        new SqlCeParameter("@workspacename", WorkspaceName),                                            
                    };
                    
                    int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
                    if (nResult != 1)
                        return false;
                    else
                        return true;
                }
            }

            return false;
        }

    }
}
