using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Foo.DataAccessLayer;
using Foo.DataAccessLayer.DataTypes;
using DataAccessLayer.TestData;
using System.Threading;
using System.IO;
using System.Diagnostics;

namespace DataAccessLayer.TestData
{
    public static class TestData
    {
        // Project / Directory Constants
        private const string PROJECT_NAME = "DataAccessLayer";
        private const string TEST_DATADIR_NAME = "TestData";
        private const string TEST_DATADIRFILES_NAME = "Files";
        private const string TEST_DATADIREFILESSNAPSHOT_NAME = "Snapshots";
        private const string TEST_DATADIRFILESDUPFILESDIR = "DupFiles";
        
        // Internally calculated locations
        private static string _TestDataDirFilesLocation = "";
        private static string _TestDataDirFilesSnapshotLocation = "";             

        /// <summary>
        /// Static Constructor is responsible for setting up the locationpaths
        /// </summary>
        static TestData()
        {
            _TestDataDirFilesLocation = GetTestDataFilesDirectoryFromRunningAssembly(Assembly.GetExecutingAssembly().Location);
            if (!String.IsNullOrEmpty(_TestDataDirFilesLocation))
                _TestDataDirFilesSnapshotLocation = _TestDataDirFilesLocation + "\\" + TEST_DATADIREFILESSNAPSHOT_NAME;

            // Now Load our File Name Map
            LoadTestDataFilesIntoOurList();
        }

        /// <summary>
        /// Private Data struct useful for our TestData Files
        /// </summary>
        private class TestDataFile
        {
            public string Name { get; set; }
            public string File { get; set; }
            public string Type { get; set; }
            public TestDataFile(string Name, string File, string Type)
            {
                this.Name = Name;
                this.File = File;
                this.Type = Type;
            }
        }

        // Holds all our TestData Files
        private static List<TestDataFile> _testDataFiles = new List<TestDataFile>();

        // Get a new Random Number
        private static int RandomNumber(int min, int max)
        {
            Random random = new Random();
            return random.Next(min, max); 
        }

        /// <summary>
        /// Loads our TestFiles Into our Private Map
        /// </summary>
        private static void LoadTestDataFilesIntoOurList()
        {
            _testDataFiles.Add(new TestDataFile("Albin likes apples", "Albin likes apples.doc", "doc"));
            _testDataFiles.Add(new TestDataFile("Book1", "Book1.xls", "xls"));
            _testDataFiles.Add(new TestDataFile("Book1", "Book1.xlsx", "xlsx"));
            _testDataFiles.Add(new TestDataFile("Book2", "Book2.xls", "xls"));
            _testDataFiles.Add(new TestDataFile("Book2", "Book2.xlsx", "xlsx"));
            _testDataFiles.Add(new TestDataFile("Book3", "Book3.xls", "xls"));
            _testDataFiles.Add(new TestDataFile("Book3", "Book4.xls", "xls"));
            _testDataFiles.Add(new TestDataFile("DatabaseBills", "DatabaseBills.accdb", "accdb"));
            _testDataFiles.Add(new TestDataFile("DatabaseReceits", "DatabaseReceits.accdb", "accdb"));
            _testDataFiles.Add(new TestDataFile("Doc1", "Doc1.rtf", "rtf"));
            _testDataFiles.Add(new TestDataFile("Doc2", "Doc2.rtf", "rtf"));

            //// Artifacts used in ThreadProc13 *Begin*
            _testDataFiles.Add(new TestDataFile("Document1", "Document1.docx", "docx"));
            _testDataFiles.Add(new TestDataFile("Document2", "Document2.doc", "doc"));
            _testDataFiles.Add(new TestDataFile("Document3", "Document3.docx", "docx"));
            _testDataFiles.Add(new TestDataFile("Document4", "Document4.doc", "doc"));
            _testDataFiles.Add(new TestDataFile("Document5", "Document5.docx", "docx"));
            _testDataFiles.Add(new TestDataFile("Document6", "Document6.docx", "docx"));
            _testDataFiles.Add(new TestDataFile("Document7", "Document7.docx", "docx"));
            _testDataFiles.Add(new TestDataFile("Doris liks apples", "Doris likes apples.doc", "doc"));
            _testDataFiles.Add(new TestDataFile("Doris", "Doris.docx", "docx"));
            _testDataFiles.Add(new TestDataFile("Doris", "Doris.xlsx", "xlsx"));
            _testDataFiles.Add(new TestDataFile("Doris2", "Doris2.docx", "docx"));
            _testDataFiles.Add(new TestDataFile("Drawing1", "Drawing1.vsd", "vsd"));
            _testDataFiles.Add(new TestDataFile("Drawing2", "Drawing2.vsd", "vsd"));
            _testDataFiles.Add(new TestDataFile("Map1", "Map1.mmap", "mmap"));
            _testDataFiles.Add(new TestDataFile("Map2", "Map2.mmap", "mmap"));
            //// Artifacts used in ThreadProc13 *End*

            _testDataFiles.Add(new TestDataFile("MoreDefects", "MoreDefects.txt", "txt"));
            _testDataFiles.Add(new TestDataFile("New Mindmap1", "New Mindmap1.mm", "mm"));
            _testDataFiles.Add(new TestDataFile("New Mindmap2", "New Mindmap2.mm", "mm"));
            _testDataFiles.Add(new TestDataFile("OogyKeepInMind", "OogyKeepInMind.txt", "txt"));
            _testDataFiles.Add(new TestDataFile("Presentation1", "Presentation1.ppt", "ppt"));
            _testDataFiles.Add(new TestDataFile("Presentation2", "Presentation2.ppt", "ppt"));
            _testDataFiles.Add(new TestDataFile("Publication1", "Publication1.pub", "pub"));
            _testDataFiles.Add(new TestDataFile("Publication2", "Publication2.pub", "pub"));
            _testDataFiles.Add(new TestDataFile("textfile1", "textfile1.txt", "txt"));

            // Sort the List by File Type
            _testDataFiles.Sort(delegate(TestDataFile t1, TestDataFile t2) { return t1.Type.CompareTo(t2.Type); });
        }

        /// <summary>
        /// Fills Default Database with Test Data
        /// </summary>
        public static void FillDBWithTestData()
        {
            if (!String.IsNullOrEmpty(_TestDataDirFilesLocation) && !String.IsNullOrEmpty(_TestDataDirFilesSnapshotLocation))
            {

                #region File Type Workspaces
                ////
                // First Let's Create a workspace for each file Type
                ////
                string FileType = String.Empty;
                string strWorkspaceName = String.Empty;
                foreach (TestDataFile dataFile in _testDataFiles)
                {
                    bool bFileTypeIsSet = false;
                    if (String.IsNullOrEmpty(FileType))
                    {
                        FileType = dataFile.Type;
                        bFileTypeIsSet = true;
                    }
                    else if (FileType != dataFile.Type)
                    {
                        FileType = dataFile.Type;
                        bFileTypeIsSet = true;
                    }

                    // Create New FileType Based Workspace
                    if (bFileTypeIsSet)
                    {
                        strWorkspaceName = "FileType Workspace for ." + FileType;
                        Debug.Assert(Data.Workspace.InsertWorkspaceName(strWorkspaceName));
                    }

                    // Add the Artifact to the corresponding Workspace
                    Debug.Assert(AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, strWorkspaceName, 1));
                }
                #endregion

                #region Simple Word and Excel
                ////
                // Let's create a Simple Word and Excel Workspace
                ////
                Debug.Assert(Data.Workspace.InsertWorkspaceName("Office Simple doc & xls"));
                foreach (TestDataFile dataFile in _testDataFiles)
                {
                    if (dataFile.Type == "doc" ||
                        dataFile.Type == "xls")
                    {
                        // Add the Artifact to the corresponding Workspace
                        Debug.Assert(AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, "Office Simple doc & xls", 1));
                    }
                }
                #endregion

                #region Advanced Word and Excel
                ////
                // Let's create a Advanced Word and Excel Workspace
                ////
                Debug.Assert(Data.Workspace.InsertWorkspaceName("Office Advanced docx & xlsx"));
                foreach (TestDataFile dataFile in _testDataFiles)
                {
                    if (dataFile.Type == "docx" ||
                        dataFile.Type == "xlsx")
                    {
                        // Add the Artifact to the corresponding Workspace
                        Debug.Assert(AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, "Office Advanced docx & xlsx", 1));
                    }
                }
                #endregion

                #region PowerPoint and Text Files
                ////
                // Let's create a Ppt and Txt files workspace for now
                ////
                Debug.Assert(Data.Workspace.InsertWorkspaceName("PowerPoint and Text Files"));
                foreach (TestDataFile dataFile in _testDataFiles)
                {
                    if (dataFile.Type == "ppt" ||
                        dataFile.Type == "txt")
                    {
                        // Add the Artifact to the corresponding Workspace
                        Debug.Assert(AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, "PowerPoint and Text Files", 1));
                    }
                }
                #endregion

                #region ShuffleWorkspace1 - 7 Items
                Debug.Assert(Data.Workspace.InsertWorkspaceName("ShuffleWorkspace1 - 7 Items"));
                for (int i = 0; i < 7; ++i)
                {
                    TestDataFile dataFile = _testDataFiles[RandomNumber(0, _testDataFiles.Count)];
                    AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, "ShuffleWorkspace1 - 7 Items", 1);
                }
                #endregion

                #region ShuffleWorkspace2 - 6 Items
                Debug.Assert(Data.Workspace.InsertWorkspaceName("ShuffleWorkspace2 - 6 Items"));
                for (int i = 0; i < 6; ++i)
                {
                    TestDataFile dataFile = _testDataFiles[RandomNumber(0, _testDataFiles.Count)];
                    AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, "ShuffleWorkspace2 - 6 Items", 1);
                }
                #endregion

                #region ShuffleWorkspace3 - 5 Items
                Debug.Assert(Data.Workspace.InsertWorkspaceName("ShuffleWorkspace3 - 5 Items"));
                for (int i = 0; i < 5; ++i)
                {
                    TestDataFile dataFile = _testDataFiles[RandomNumber(0, _testDataFiles.Count)];
                    AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, "ShuffleWorkspace3 - 5 Items", 1);
                }
                #endregion                

                #region DuplicateWorkspace1
                int nNumberOfArtifacts1 = RandomNumber(3, 10);
                string strDupWkspace1 = "DuplicateWorkspace1 - " + nNumberOfArtifacts1.ToString() + " Items";
                Debug.Assert(Data.Workspace.InsertWorkspaceName(strDupWkspace1));
                for (int i = 0; i < nNumberOfArtifacts1; ++i )
                {
                    int nDuplicates = RandomNumber(1, 3);
                    int nArtifact = RandomNumber(0, _testDataFiles.Count);

                    // Add Duplicates
                    for (int j = 1; j <= nDuplicates; ++j)
                         AddTestArtifactToWorkspace(_testDataFiles[nArtifact].Name, _testDataFiles[nArtifact].File, strDupWkspace1 , j);
                }
                #endregion

                #region DuplicateWorkspace2
                int nNumberOfArtifacts2 = RandomNumber(3, 10);
                string strDupWkspace2 = "DuplicateWorkspace2 - " + nNumberOfArtifacts2.ToString() + " Items";
                Debug.Assert(Data.Workspace.InsertWorkspaceName(strDupWkspace2));
                for (int i = 0; i < nNumberOfArtifacts2; ++i)
                {
                    int nDuplicates = RandomNumber(1, 3);
                    int nArtifact = RandomNumber(0, _testDataFiles.Count);

                    // Add Duplicates
                    for (int j = 1; j <= nDuplicates; ++j)
                        AddTestArtifactToWorkspace(_testDataFiles[nArtifact].Name, _testDataFiles[nArtifact].File, strDupWkspace2, j);
                }
                #endregion

                #region DuplicateWorkspace3
                int nNumberOfArtifacts3 = RandomNumber(3, 10);
                string strDupWkspace3 = "DuplicateWorkspace3 - " + nNumberOfArtifacts3.ToString() + " Items";
                Debug.Assert(Data.Workspace.InsertWorkspaceName(strDupWkspace3));
                for (int i = 0; i < nNumberOfArtifacts3; ++i)
                {
                    int nDuplicates = RandomNumber(1, 3);
                    int nArtifact = RandomNumber(0, _testDataFiles.Count);

                    // Add Duplicates
                    for (int j = 1; j <= nDuplicates; ++j)
                        AddTestArtifactToWorkspace(_testDataFiles[nArtifact].Name, _testDataFiles[nArtifact].File, strDupWkspace3, j);
                }
                #endregion
            }
        }

        /// <summary>
        /// Quick Helper Function to add Test Artifacts to a Workspace
        /// </summary>
        /// <param name="ArtifactName">Name of the artifact you would like to give</param>
        /// <param name="FileName">name of the file such as File1.jpg</param>
        /// <param name="WorkspaceName">name of workspace to add to</param>
        /// <param name="DupFileDir">pass in a number from 1 - 3 (i have 3 dup directories)</param>
        /// <returns>true, if successfully added, false otherwise</returns>
        public static bool AddTestArtifactToWorkspace(string ArtifactName, string FileName, string WorkspaceName, int DupFileDirIndex)
        {
            if (!String.IsNullOrEmpty(_TestDataDirFilesLocation) && !String.IsNullOrEmpty(_TestDataDirFilesSnapshotLocation))
            {                
                ArtifactItem artifactItem = new ArtifactItem()
                {
                    Name = ArtifactName,
                    Location = _TestDataDirFilesLocation + "\\" + TEST_DATADIRFILESDUPFILESDIR + DupFileDirIndex.ToString() + "\\" + FileName,
                    SnapshotFile = _TestDataDirFilesSnapshotLocation + "\\" + "c9f487bd-7cef-4f45-8238-08a4be0a3ba3.png",
                    Note = "",                
                    WindowLeft = 100,
                    WindowTop = 100,
                    WindowHeight = 400,
                    WindowWidth = 400,     
                };
                
                artifactItem.SetAsFileType();
                return Data.Artifacts.AddArtifactToWorkspace(WorkspaceName, artifactItem);
            }
            return false;
        }

        /// <summary>
        /// Iterate and find the TestData Directory in the executing path
        /// </summary>
        /// <param name="AssemblyLocation">location of currently executing assembly</param>
        /// <returns>valid path string to test data or "" if not found</returns>
        private static string GetTestDataFilesDirectoryFromRunningAssembly(string AssemblyLocation)
        {
            DirectoryInfo directory = new DirectoryInfo(Path.GetDirectoryName(AssemblyLocation));

            ////
            // Iterate the executing Assembly Directory upward to find the testData or Project Directory
            ////
            bool bFindTestData = false;
            while (!bFindTestData && (directory != null) && directory.Exists)
            {

                // First Check to see if this Directory has the ProjectName as a SubDir
                DirectoryInfo[] dirProjectNameDirs = directory.GetDirectories(PROJECT_NAME, SearchOption.TopDirectoryOnly);

                if(dirProjectNameDirs.Length == 1)
                {
                    // Check if there is a TestData Dir Underneath (return if there is)
                    DirectoryInfo[] dirTestDataDirs = dirProjectNameDirs[0].GetDirectories(TEST_DATADIR_NAME, SearchOption.TopDirectoryOnly);

                    if(dirTestDataDirs.Length == 1)
                    {
                        // Now Check for the Files Directory
                        DirectoryInfo[] dirTestDataFilesDirs = dirTestDataDirs[0].GetDirectories(TEST_DATADIRFILES_NAME, SearchOption.TopDirectoryOnly);

                        if (dirTestDataFilesDirs.Length == 1)
                            return dirTestDataFilesDirs[0].FullName;
                    }
                }
               
                // Keep going up the chain
                directory = directory.Parent;
            }
            return String.Empty;
        }
    }
}
