/// <summary>
        /// helper function for adding items in the copy queue
        /// </summary>
        /// <param name="myCollection"></param>
        /// <param name="queueTHRESHOLD"></param>
        /// <param name="destError"></param>
        /// <param name="coFolder"></param>
        private void FillQueue(ConcurrentQueue <CopyOperation> myCollection, int queueTHRESHOLD, Exception destError, CopyOperation coFolder)
        {
            if (destError != null)
            {
                throw new ArgumentException("Thread Copy Destination has failed", destError);
            }

            while (myCollection.Count > queueTHRESHOLD)
            {
                if (forceExceptionalStop)
                {
                    return;
                }

                Thread.Sleep(100);
            }

            myCollection.Enqueue(coFolder);
        }
        /// <summary>
        /// Copy the source folder content into a destination folder
        /// </summary>
        /// <param name="srcPath">source folder</param>
        /// <param name="destPath">destination folder</param>
        /// <returns>true if success</returns>
        private bool CopyFolderAndFilesWithImpersonation(string configID, string srcPath, string domainSrc, string userSrc, string passSrc,
                                                         string destPath, string domainDest, string userDest, string passDest, out Exception outEx)
        {
            outEx        = null;
            myCollection = new ConcurrentQueue <CopyOperation>();

            byte[]    buffer    = new byte[bufferSize];
            bool      finished  = false;
            Exception srcError  = null;
            Exception destError = null;
            Thread    thSource  = new Thread(() =>
            {
                try
                {
                    //FileLogging.Log($"begin thSrc.", LogLevel.Info);
                    using (Impersonation.LogonUser(domainSrc, userSrc, passSrc, LogonType.Network))//LogonType.Interactive
                    {
                        WindowsIdentity wid_current = WindowsIdentity.GetCurrent();
                        //FileLogging.Log($"impersonated thSrc.  {wid_current.Name}", LogLevel.Info);
                        //scan all of the directories
                        var lstDirectories = Directory.GetDirectories(srcPath, "*", SearchOption.AllDirectories);
                        dirCount           = lstDirectories.LongCount();
                        foreach (string dirPath in lstDirectories)
                        {
                            CopyOperation coFolder = new CopyOperation
                            {
                                Operation = OperationType.WriteFolder,
                                Argument  = dirPath.Replace(srcPath, string.Empty)
                            };
                            FillQueue(myCollection, queueTHRESHOLD, destError, coFolder);
                            if (forceExceptionalStop)
                            {
                                return;
                            }
                            //FileLogging.Log($"q-d: {coFolder.Argument}", LogLevel.Info);
                        }
                        //scan all files
                        var lstFiles = Directory.GetFiles(srcPath, "*.*", SearchOption.AllDirectories);
                        fileCount    = lstFiles.LongCount();
                        foreach (string newPath in lstFiles)
                        {
                            using (FileStream fs = File.Open(newPath, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read))
                            {
                                int readB;
                                long offset = 0;
                                while ((readB = fs.Read(buffer, 0, bufferSize)) > 0)
                                {
                                    CopyOperation coFile = new CopyOperation
                                    {
                                        Operation = OperationType.WriteFile,
                                        Argument  = newPath.Replace(srcPath, string.Empty),
                                        Offset    = offset,
                                        Content   = buffer.SubArray(0, readB)
                                    };
                                    FillQueue(myCollection, queueTHRESHOLD, destError, coFile);
                                    if (forceExceptionalStop)
                                    {
                                        return;
                                    }
                                    //FileLogging.Log($"q-f: {coFile.Argument} - {coFile.Offset}", LogLevel.Info);
                                    offset += readB;
                                }
                            }
                        }
                        //YEY!
                        finished = true;

                        //wic.Undo();
                    }
                }
                catch (Exception err)
                {
                    srcError             = err;
                    forceExceptionalStop = true;
                    finished             = true;
                }
            });


            Thread thDest = new Thread(() =>
            {
                try
                {
                    //FileLogging.Log($"begin thDest.", LogLevel.Info);
                    Thread.Sleep(200);

                    long dirIndex     = 0, fileIndex = 0;
                    string lastFile   = string.Empty;
                    DateTime lastSent = DateTime.MinValue;
                    int copyPercent;
                    using (Impersonation.LogonUser(domainDest, userDest, passDest, LogonType.NewCredentials))//LogonType.NewCredentials
                    {
                        WindowsIdentity wid_current = WindowsIdentity.GetCurrent();
                        //FileLogging.Log($"impersonated thDest.  {wid_current.Name}", LogLevel.Info);
                        while (!finished || myCollection.Count > 0)
                        {
                            while (myCollection.Count == 0 && !forceExceptionalStop)
                            {
                                Thread.Sleep(100);
                            }
                            if (forceExceptionalStop)
                            {
                                return;
                            }

                            CopyOperation item = null;
                            if (myCollection.TryDequeue(out item))
                            {
                                switch (item.Operation)
                                {
                                case OperationType.WriteFolder:
                                    string newFolder = UncCombine(destPath, item.Argument);
                                    Directory.CreateDirectory(newFolder);
                                    dirIndex++;
                                    break;

                                case OperationType.WriteFile:
                                    string destFile = UncCombine(destPath, item.Argument);
                                    using (var fs = ((item.Offset == 0) && File.Exists(destFile)) ? File.Create(destFile) : File.OpenWrite(destFile))
                                    {
                                        fs.Seek(item.Offset, SeekOrigin.Begin);
                                        fs.Write(item.Content, 0, item.Content.Length);
                                    }
                                    if (destFile != lastFile)
                                    {
                                        fileIndex++;
                                        lastFile = destFile;
                                    }
                                    break;

                                default:
                                    break;
                                }
                                //update report status
                                DateTime now = DateTime.UtcNow;
                                if (now > lastSent)
                                {
                                    copyPercent = Convert.ToInt32(20 * (dirCount > 0 ? (double)dirIndex / dirCount : 1) + 80 * (fileCount > 0 ? (double)fileIndex / fileCount : 1));
                                    lastSent    = now + TimeSpan.FromMilliseconds(SignalRController.SIGNALR_REFRESH_INTERVAL);
                                    ReportAgentStatus(item.Operation == OperationType.WriteFolder ? StatusType.CopyFolders : StatusType.CopyFiles,
                                                      item.Operation == OperationType.WriteFolder ? $"Copy folders in progress {dirIndex}/{dirCount} ..." : $"Copy files in progress {fileIndex}/{fileCount} ..."
                                                      , copyPercent, configID);
                                }
                            }
                            else
                            {
                                throw new ArgumentException("Could not extract item from queue");
                            }
                        }
                    }
                }
                catch (Exception err)
                {
                    destError            = err;
                    forceExceptionalStop = true;
                }
            });

            //clear exception
            forceExceptionalStop = false;

            thDest.Start();
            thSource.Start();

            //wait to complete or fail
            thSource.Join();
            thDest.Join();


            myCollection = new ConcurrentQueue <CopyOperation>();


            if (srcError != null)
            {
                outEx = srcError;
                logger.Error($"srcErr: {srcError}");
                return(false);
            }
            if (destError != null)
            {
                outEx = destError;
                logger.Error($"destErr: {destError}");
                return(false);
            }
            if (externalError != null)
            {
                outEx = externalError;
                logger.Debug($"externalError: {destError}");
                return(false);
            }


            logger.Error($"LAN Copy completed!");

            return(true);
        }