private async void RenameCurrentCloudFile()
        {
            if (!HasGottenFolder())
            {
                return;
            }
            Cloud_Elements_API.CloudFile currentRow = null;
            if (!HasCurrentCloudFile(ref currentRow))
            {
                return;
            }
            if (currentRow.name == tsTxtObjectName.Text)
            {
                StatusMsg("Name not changed, ignored");
            }
            string oldName = currentRow.name;

            Cloud_Elements_API.CloudElementsConnector.DirectoryEntryType ceType = Cloud_Elements_API.CloudElementsConnector.DirectoryEntryType.File;
            if (currentRow.directory)
            {
                ceType = Cloud_Elements_API.CloudElementsConnector.DirectoryEntryType.Folder;
            }
            currentRow.path = txtFolderPath.Text + tsTxtObjectName.Text;
            Cloud_Elements_API.CloudFile Result = await APIConnector.PatchDocEntryMetaData(ceType, Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.ID, currentRow.id, currentRow);

            StatusMsg(string.Format("Renamed [{0}] to {1}", oldName, Result.name));
            Task refresh = RefreshCurrentFolder();
        }
        async private Task uploadFile(System.IO.FileInfo sourceFile, string targetPath, List <String> tagList, string description)
        {
            var      MIMEType  = Cloud_Elements_API.Tools.FileTypeToMimeContentType(System.IO.Path.GetExtension(sourceFile.Name));
            DateTime StartedAt = DateTime.Now;

            StatusMsg("Uploading " + sourceFile.Name);

            string SourceFileName = System.IO.Path.GetFileName(sourceFile.Name);

            if (!targetPath.EndsWith("/"))
            {
                targetPath += "/";
            }
            targetPath += SourceFileName;
            //System.IO.FileInfo fInfo = new System.IO.FileInfo(sourceFileName);

            var sizeInBytes = sourceFile.Length;


            Cloud_Elements_API.CloudFile Result = await APIConnector.PostFile(sourceFile.OpenRead(), MIMEType,
                                                                              targetPath, description,
                                                                              tagList.ToArray(), false, sizeInBytes);

            sourceFile = null;
            double uploadSeconds = DateTime.Now.Subtract(StartedAt).TotalSeconds;

            StatusMsg(string.Format("Uploaded {0} in {1:F1}s, {2:F1} mb/s ", SourceFileName, uploadSeconds, (sizeInBytes / 1024.0) / uploadSeconds));
        }
        private async void tsRemoveEmptyFolders_Click(object sender, EventArgs e)
        {
            if (!HasGottenFolder())
            {
                return;
            }
            Cloud_Elements_API.CloudFile currentRow = null;
            if (!HasCurrentCloudFile(ref currentRow))
            {
                return;
            }
            frmEmptyFolderScanOptions emptyOptions = new frmEmptyFolderScanOptions();

            if (emptyOptions.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
            {
                return;
            }
            ScanOptions = emptyOptions.ScanOptions;

            APIConnector.EndpointMaxRequestsPerSecond = 2;
            CountOfFoldersRemoved = 0;
            StatusMsg("Starting folder scan...");
            await scanForEmptyFolders(ScanOptions, currentRow);

            StatusMsg("Folder scan ended, see test log for results.");
            TestStatusMsg(string.Format("Folders Removed: {0}", CountOfFoldersRemoved));
        }
        /// <summary>
        /// Asynchronously download a files, with progress messages to status bar
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks>You can have multiple simultaneous downloads</remarks>
        private async void tsGetFileMenuItem_Click(object sender, EventArgs e)
        {
            cmdGetFolderContents.Enabled = false;
            try
            {
                Cloud_Elements_API.CloudFile currentRow = null;
                if (!HasCurrentCloudFile(ref currentRow))
                {
                    return;
                }

                StatusMsg("Requesting...");
                DateTime startAt = DateTime.Now;
                Cloud_Elements_API.FileContent Result = await APIConnector.GetFile(currentRow);

                StatusMsg(string.Format(">> Get File Result: {2:F1}s for content-length: {0}; disposition: [{1}]", Result.ContentLength, Result.Disposition, DateTime.Now.Subtract(startAt).TotalSeconds));
                string fn = System.IO.Path.Combine(WorkPath, Result.Disposition);
                if (Result.Disposition.Length == 0)
                {
                    fn += currentRow.name;
                }
                if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(fn)))
                {
                    System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(fn));
                }
                if (System.IO.File.Exists(fn))
                {
                    // HINT: would be better to check this before downloading...but we are using the response disposition to illustrate its existence....
                    if (System.Windows.Forms.MessageBox.Show(string.Format("Download will replace existing file {0}\n\nOkay?", fn), "Confirmation", System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.No)
                    {
                        Result.ContentStream.Close();
                        return;
                    }
                    System.IO.File.Delete(fn);
                }

                System.IO.Stream Target = new System.IO.FileStream(fn, System.IO.FileMode.Create, System.Security.AccessControl.FileSystemRights.FullControl, System.IO.FileShare.None, 16384, System.IO.FileOptions.Asynchronous, null);

                StatusMsg("Receiving...");
                //error handling here would be nice...
                Cloud_Elements_API.Tools.Progress += Tools_Progress;
                await Cloud_Elements_API.Tools.StreamCopyWithProgress(Result.ContentStream, Target, Result.ContentLength);

                Result.ContentStream.Close();
                Target.Seek(0, System.IO.SeekOrigin.Begin);

                StatusMsg(string.Format("Downloaded content for {1}: MD5={0}", Cloud_Elements_API.Tools.HashForBuffer(Target, "MD5"), System.IO.Path.GetFileName(fn)));
                Target.Seek(0, System.IO.SeekOrigin.Begin);
                StatusMsg(string.Format("Downloaded content for {1}: SHA1={0}", Cloud_Elements_API.Tools.HashForBuffer(Target, "SHA1"), System.IO.Path.GetFileName(fn)));
                Target.Close();
                Cloud_Elements_API.Tools.Progress -= Tools_Progress;
                StatusMsg(string.Format("Stored {1}: {0}", Cloud_Elements_API.Tools.SizeInBytesToString(Result.ContentLength), System.IO.Path.GetFileName(fn)));
            }
            finally
            {
                cmdGetFolderContents.Enabled = true;
            }
        }
        private async void cmdGetID_Click(object sender, EventArgs e)
        {
            frmGetCloudFileID frmGet = new frmGetCloudFileID();

            cmdGetID.Enabled = false;
            if (frmGet.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Cloud_Elements_API.CloudElementsConnector.TraceLevel diagTraceWas = Cloud_Elements_API.CloudElementsConnector.DiagOutputLevel;
                try
                {
                    TestStatusMsg("Checking: " + frmGet.FileID);
                    Cloud_Elements_API.CloudFile CloudFileInfoByID;
                    Cloud_Elements_API.CloudElementsConnector.DiagOutputLevel = Cloud_Elements_API.CloudElementsConnector.TraceLevel.All;
                    CloudFileInfoByID = await Cloud_Elements_API.FileOperations.GetCloudFileInfo(APIConnector, Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.ID, frmGet.FileID);

                    if (CloudFileInfoByID == null)
                    {
                        StatusMsg("Nothing Returned!  (not expecting not found)");
                    }
                    else
                    {
                        if (CloudFileInfoByID.directory)
                        {
                            txtFolderPath.Text = CloudFileInfoByID.path;
                        }
                        else
                        {
                            txtFolderPath.Text = CloudFileInfoByID.path.Substring(0, CloudFileInfoByID.path.LastIndexOf("/"));
                        }
                        TestStatusMsg("Getting: " + CloudFileInfoByID.path);
                        Task refresh = RefreshCurrentFolder();

                        await refresh;
                        //dgFolderContents.SelectedRows.Clear();
                        foreach (DataGridViewRow gridRow in dgFolderContents.Rows)
                        {
                            Cloud_Elements_API.CloudFile itemrow = (Cloud_Elements_API.CloudFile)gridRow.DataBoundItem;
                            if (itemrow.id == frmGet.FileID)
                            {
                                gridRow.Selected             = true;
                                dgFolderContents.CurrentCell = dgFolderContents.Rows[gridRow.Index].Cells[0];
                                break;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    StatusMsg(string.Format("FAILED: {0}", ex.Message));
                }
                finally
                {
                    Cloud_Elements_API.CloudElementsConnector.DiagOutputLevel = diagTraceWas;
                }
            }
            cmdGetID.Enabled = true;
        }
 private void tsGetPriorFolder_Click(object sender, EventArgs e)
 {
     Cloud_Elements_API.CloudFile currentRow = null;
     if (!HasCurrentCloudFile(ref currentRow))
     {
         return;
     }
     GetPriorFolder_Click(sender, e);
 }
        private bool HasCurrentCloudFile(ref Cloud_Elements_API.CloudFile currentRow)
        {
            currentRow = GetCurrentFolderContentRow();
            bool result = !(currentRow == null);

            if (!result)
            {
                StatusMsg("No current row");
            }
            return(result);
        }
        private async void tsGetThisFolder_Click(object sender, EventArgs e)
        {
            Cloud_Elements_API.CloudFile currentRow = null;
            if (!HasCurrentCloudFile(ref currentRow))
            {
                return;
            }

            txtFolderPath.Text = currentRow.path;
            await RefreshCurrentFolder();
        }
        private async void deleteThisFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!HasGottenFolder())
            {
                return;
            }
            try
            {
                Cloud_Elements_API.CloudFile currentRow = null;

                if (!HasCurrentCloudFile(ref currentRow))
                {
                    return;
                }

                if (currentRow.directory)
                {
                    if (currentRow.size > 0)
                    {
                        if (System.Windows.Forms.MessageBox.Show(string.Format("Folder is not empty!  Delete [{0}] anyway?", currentRow.path), "Confirmation", System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.No)
                        {
                            return;
                        }
                    }

                    StatusMsg(string.Format("Deleting {0}, size={1}", currentRow.path, Cloud_Elements_API.Tools.SizeInBytesToString(currentRow.size)));
                    bool Result = await APIConnector.DeleteFolder(Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.Path, currentRow.path, false);
                }
                else
                {
                    if (currentRow.size > 0)
                    {
                        if (System.Windows.Forms.MessageBox.Show(string.Format("File is not empty!  Delete [{0}] anyway?", currentRow.path), "Confirmation", System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.No)
                        {
                            return;
                        }
                    }

                    StatusMsg(string.Format("Deleting {0}, size={1}", currentRow.path, Cloud_Elements_API.Tools.SizeInBytesToString(currentRow.size)));
                    bool Result = await APIConnector.DeleteFile(Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.ID, currentRow.id, false);
                }

                StatusMsg("Done.");
                await this.RefreshCurrentFolder();
            }
            finally
            {
                cmdGetFolderContents.Enabled = true;
            }
        }
        private Cloud_Elements_API.CloudFile GetCurrentFolderContentRow()
        {
            //BindingManagerBase grdBinding = this.BindingContext(dgFolderContents.DataSource, dgFolderContents.DataMember);

            Cloud_Elements_API.CloudFile currentRow = null;
            if (dgFolderContents.CurrentRow != null)
            {
                if (dgFolderContents.CurrentRow.DataBoundItem is Cloud_Elements_API.CloudFile)
                {
                    currentRow = (Cloud_Elements_API.CloudFile)dgFolderContents.CurrentRow.DataBoundItem;
                }
            }
            return(currentRow);
        }
        private void FolderRowContextMenu_Opening(object sender, CancelEventArgs e)
        {
            Cloud_Elements_API.CloudFile currentRow = null;
            if (!HasCurrentCloudFile(ref currentRow))
            {
                return;
            }

            tsGetThisFolder.Enabled  = currentRow.directory;
            tsGetPriorFolder.Enabled = (FolderPathHistory.Count > 1);

            tsDeleteFolderMenuItem.Enabled = true;
            tsGetFileMenuItem.Enabled      = !currentRow.directory;
            if (currentRow.directory)
            {
                tsDeleteFolderMenuItem.Text = "Delete this folder...";
            }
            else
            {
                tsDeleteFolderMenuItem.Text = "Delete this file...";
            }

            tsTxtObjectName.Text          = currentRow.name;
            tsFileTagInfoMenuItem.Text    = "Tags (not requested)";
            tsFileTagInfoMenuItem.Enabled = chkWithTags.Checked;



            if (tsFileTagInfoMenuItem.Enabled)
            {
                tsFileTagInfoMenuItem.DropDownItems.Clear();
                if (currentRow.tags != null)
                {
                    tsFileTagInfoMenuItem.Text = string.Format("{0} Tags ", currentRow.tags.Length);
                    foreach (string tag in currentRow.tags)
                    {
                        tsFileTagInfoMenuItem.DropDownItems.Add(tag);
                    }
                }
                else
                {
                    tsFileTagInfoMenuItem.Text    = string.Format("No Tags ", 0);
                    tsFileTagInfoMenuItem.Enabled = false;
                }
            }
        }
 private void dgFolderContents_DoubleClick(object sender, EventArgs e)
 {
     Cloud_Elements_API.CloudFile currentRow = null;
     if (!HasCurrentCloudFile(ref currentRow))
     {
         return;
     }
     if (currentRow.directory)
     {
         tsGetThisFolder_Click(sender, e);
     }
     else
     {
         if (System.Windows.Forms.MessageBox.Show(string.Format("Download {0}", currentRow.path), "Confirmation", System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
         {
             tsGetFileMenuItem_Click(sender, e);
         }
     }
 }
        private async void toolStripButton1_Click_1(object sender, EventArgs e)
        {
            if (!HasGottenFolder())
            {
                return;
            }
            Cloud_Elements_API.CloudFile currentRow = null;
            if (!HasCurrentCloudFile(ref currentRow))
            {
                return;
            }

            string TagToSet = tstxtTagData.Text;

            //Type the tag to add.  If includes an = is treated as a KV pair; Try: *TestTag for a random tag or sfKey=* for a guid tag
            if (TagToSet == "*TestTag")
            {
                TagToSet = "Day-" + DateTime.Today.DayOfWeek.ToString();
            }
            if (TagToSet.StartsWith("sfKey="))
            {
                TagToSet = string.Format("sfKey={0}", Guid.NewGuid());
            }

            if (!chkWithTags.Checked || !currentRow.HasTags)
            {
                StatusMsg("Getting current Tag(s).... ");
                currentRow = await APIConnector.GetDocEntryMetaData(currentRow.EntryType, Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.ID, currentRow.id, false);
            }

            StatusMsg("Storing Tag: " + TagToSet);

            await Cloud_Elements_API.TagOperations.SetTag(APIConnector, currentRow, TagToSet);

            if (!chkWithTags.Checked)
            {
                chkWithTags.Checked = true;
            }
            await RefreshCurrentFolder();
        }
        private async void tsBtnNewFolder_Click(object sender, EventArgs e)
        {
            if (!HasGottenFolder())
            {
                return;
            }
            if (tsTxtFolderName.Text.Length > 0)
            {
                Cloud_Elements_API.CloudFile newFolder = new Cloud_Elements_API.CloudFile();
                newFolder.path = CurrentFolderPath;
                if (!tsTxtFolderName.Text.StartsWith("/"))
                {
                    newFolder.path += "/";
                }
                newFolder.path += tsTxtFolderName.Text;
                newFolder.tags  = new string[] { "sfCE.NET" };
                Cloud_Elements_API.CloudFile Result = await APIConnector.CreateFolder(newFolder);

                StatusMsg(string.Format("Created {0}, id={1}", Result.path, Result.id));
                Task ignoredRefreshFolderTask = RefreshCurrentFolder(); // very naughty, ignore exceptions; ref http://stackoverflow.com/questions/14903887/warning-this-call-is-not-awaited-execution-of-the-current-method-continues
            }
        }
        async private Task uploadFolder(string sourcePath, string targetPath)
        {
            List <String> TagList = new List <String>();  // unchanged in this method

            TagList.Add("sfCETest.NET");
            var HTMLMIMEType = Cloud_Elements_API.Tools.FileTypeToMimeContentType(".htm");

            System.Text.StringBuilder FileList = new System.Text.StringBuilder();
            foreach (var fn in System.IO.Directory.GetFiles(sourcePath))
            {
                System.IO.FileInfo fInfo = new System.IO.FileInfo(fn);
                FileList.AppendFormat("<tr><td>{0}</td><td>{1:d} {1:t}</td><td>{2:d} {2:t}</td></tr>", fInfo.Name, fInfo.CreationTime, fInfo.LastWriteTime);
                await uploadFile(fInfo, targetPath, TagList, "");
            }
            if (FileList.Length > 0)
            {
                System.Text.StringBuilder FolderMarker = new System.Text.StringBuilder();
                FolderMarker.AppendFormat("<!DOCTYPE html><html><head><title>{0}</title></head><body>\n", targetPath);
                FolderMarker.Append("<h2>Original Creation and Modification dates for this folder</h2><hr /><table style='width:88%;'>");
                FolderMarker.AppendFormat("<tr style='font-weight:bold;'><td>{0}</td><td>{1}</td><td>{2}</td></tr>", "File Name", "Created", "Last Write");
                FolderMarker.Append(FileList);
                FolderMarker.AppendFormat("</table><span style='font-size: 0.6em'>Uploaded {0:d} at {0:t}</span>", DateTime.Now);
                FolderMarker.AppendLine("</body></html>");
                byte[] ByteBuffer = System.Text.Encoding.ASCII.GetBytes(FolderMarker.ToString());
                System.IO.MemoryStream       logFileStream = new System.IO.MemoryStream(ByteBuffer);
                Cloud_Elements_API.CloudFile Result        = await APIConnector.PostFile(logFileStream, HTMLMIMEType,
                                                                                         targetPath + "/Uploaded File Date Information.html", "",
                                                                                         TagList.ToArray(), false, ByteBuffer.Length);
            }

            string nestedPath;

            foreach (var folderName in System.IO.Directory.GetDirectories(sourcePath))
            {
                nestedPath = string.Format("{0}/{1}", targetPath, new System.IO.DirectoryInfo(folderName).Name);
                await uploadFolder(folderName, nestedPath);
            }
        }
        private async void getMetadataByIDToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!HasGottenFolder())
            {
                return;
            }
            Cloud_Elements_API.CloudFile currentRow        = null;
            Cloud_Elements_API.CloudFile CloudFileInfoByID = null;
            if (!HasCurrentCloudFile(ref currentRow))
            {
                return;
            }
            Cloud_Elements_API.CloudElementsConnector.TraceLevel diagTraceWas = Cloud_Elements_API.CloudElementsConnector.DiagOutputLevel;
            try
            {
                Cloud_Elements_API.CloudElementsConnector.DiagOutputLevel = Cloud_Elements_API.CloudElementsConnector.TraceLevel.All;
                CloudFileInfoByID = await Cloud_Elements_API.FileOperations.GetCloudFileInfo(APIConnector, Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.ID, currentRow.id);

                if (CloudFileInfoByID == null)
                {
                    StatusMsg("Nothing Returned!  (not expecting not found)");
                }
                else
                {
                    StatusMsg(string.Format("OK: ID is {0}, by [{2}], hash {1}", CloudFileInfoByID.id, Cloud_Elements_API.FileOperations.ContentHash(APIConnector, CloudFileInfoByID),
                                            Cloud_Elements_API.FileOperations.LastWrittenBy(APIConnector, CloudFileInfoByID)));
                }
            }
            catch (Exception ex)
            {
                StatusMsg(string.Format("FAILED: {0}", ex.Message));
            }
            finally
            {
                Cloud_Elements_API.CloudElementsConnector.DiagOutputLevel = diagTraceWas;
            }
        }
        private async void tsGetFileLink_Click(object sender, EventArgs e)
        {
            if (!HasGottenFolder())
            {
                return;
            }
            Cloud_Elements_API.CloudFile currentRow = null;
            if (!HasCurrentCloudFile(ref currentRow))
            {
                return;
            }
            if (currentRow.directory)
            {
                StatusMsg("API does not support a link to a folder");
            }

            Cloud_Elements_API.CloudLink Result = await APIConnector.FileLinks(Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.ID, currentRow.id);

            StatusMsg(string.Format("ceLink: {0}", Result.cloudElementsLink));
            StatusMsg(string.Format("Provider View Link: {0}", Result.providerViewLink));
            StatusMsg(string.Format("Provider Link: {0}", Result.providerLink));

            StatusMsg("See log for links...");
        }
        private async Task RunUnitTest()
        {
            TestStatusMsg("Beginning test suite...");
            TestStatusMsg("Testing with " + toolStripTxtConnectionNow.Text);
            string basepath = txtFolderPath.Text;

            SerializeGetFileMetadataRequests          = chkSerializeGetFileInfoReq.Checked;
            APIConnector.EndpointMaxRequestsPerSecond = (int)spnRequestsPerSecond.Value;

            if (basepath.EndsWith("/"))
            {
                basepath.TrimEnd(new char[] { '/' });
            }
            string tfoldername = basepath + "/Cloud Elements API Test Folder";

            AsyncBasePath = tfoldername;

            Boolean  remnant   = false;
            Boolean  fremnant  = false;
            DateTime StartTime = DateTime.Now;

            Cloud_Elements_API.CloudFile TestFileStore;

            //FIRST TEST: Check for folder. If no folder, create test folder.
            try
            {
                // List<Cloud_Elements_API.CloudFile> fe = await APIConnector.ListFolderContents(Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.Path, tfoldername, chkWithTags.Checked);
                Cloud_Elements_API.CloudFile Result = await Cloud_Elements_API.FileOperations.GetCloudFileInfo(APIConnector, Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.Path, tfoldername);

                if (Result != null)
                {
                    remnant = true;
                    TestStatusMsg("Using existing test folder");
                }
                else
                {
                    remnant = false;
                }
            }
            //catch (System.Net.Http.HttpRequestException e)
            //{
            //    //NOTE: handle different http exceptions!
            //    remnant = false;
            //}
            catch (Exception ex)
            {
                TestStatusMsg("Problem checking if test folder exists: " + ex.Message);
                throw ex;
            }
            if (!remnant)
            {
                TestStatusMsg("Test: Creating folder...");
                try
                {
                    Cloud_Elements_API.CloudFile newFolder = new Cloud_Elements_API.CloudFile();
                    newFolder.path = tfoldername;
                    //newFolder.tags = new string[] { "sfCE.NET" };
                    Cloud_Elements_API.CloudFile Result = await APIConnector.CreateFolder(newFolder);

                    TestStatusMsg(string.Format("Created {0}, id={1}", Result.path, Result.id));
                    Task ignoredRefreshFolderTask = RefreshCurrentFolder(); // very naughty, ignore exceptions; ref http://stackoverflow.com/questions/14903887/warning-this-call-is-not-awaited-execution-of-the-current-method-continues
                }
                catch (Exception ec)
                {
                    TestStatusMsg("Create Folder failed: " + ec.Message);
                    throw ec;
                }
            }

            TestStatusMsg("Checking for test file...");
            try
            {
                string TargetPath = tfoldername + "/SFCE_test_file_prime.txt";
                Cloud_Elements_API.CloudFile Result = await Cloud_Elements_API.FileOperations.GetCloudFileInfo(APIConnector, Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.Path, TargetPath);

                if (Result != null)
                {
                    TestStatusMsg(string.Format("Test file exists: {0}, id={1}", Result.path, Result.id));
                    fremnant      = true;
                    TestFileStore = Result;
                }
                else
                {
                    TestStatusMsg("Test file not found"); TestFileStore = null;
                }
            }
            catch (Exception ec)
            {
                TestStatusMsg("Check for file failed: " + ec.Message);
                TestFileStore = null;
                //     throw ec;
            }

            double UploadRequiredMS = 0d;

            if (!fremnant)
            {
                //SECOND TEST: Create file.
                TestStatusMsg("Test: Uploading file...");
                try
                {
                    using (System.IO.Stream teststream = GenerateStreamFromString("This is a dummy test file; its diminutive size is quite reasonable."))
                    {
                        string        MIMEType              = Cloud_Elements_API.Tools.FileTypeToMimeContentType("txt");
                        List <String> TagList               = new List <String>();
                        var           sizeInBytes           = teststream.Length;
                        string        TargetPath            = tfoldername + "/SFCE_test_file_prime.txt";
                        DateTime      Started               = DateTime.Now;
                        Cloud_Elements_API.CloudFile Result = await APIConnector.PostFile(teststream, MIMEType,
                                                                                          TargetPath, "Temporary test file",
                                                                                          TagList.ToArray(), false, sizeInBytes);

                        UploadRequiredMS = DateTime.Now.Subtract(Started).TotalMilliseconds;
                        TestStatusMsg(string.Format("Uploaded {0}, id={1}", Result.path, Result.id));

                        TestFileStore = Result;
                    }
                }
                catch (Exception eu)
                {
                    TestStatusMsg("Upload file failed: " + eu.Message);
                    TestFileStore = null;
                }
            }
            else
            {
                TestStatusMsg("Skipping file upload");
            }

            //THIRD TEST: Copy File.
            TestStatusMsg("Test: Copying file...");
            double CopyRequiredMS = 0d;

            try
            {
                if (TestFileStore == null)
                {
                    TestFileStore = await Cloud_Elements_API.FileOperations.GetCloudFileInfo(APIConnector, Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.Path, tfoldername + "/SFCE_test_file_prime.txt");
                }
                string CopyFileName = tfoldername + "/SFCE_test_file_copy.txt";
                Cloud_Elements_API.CloudFile currentRow = TestFileStore;
                DateTime Started = DateTime.Now;
                Cloud_Elements_API.CloudFile Result = await Cloud_Elements_API.FileOperations.Copy(APIConnector, currentRow, CopyFileName);

                if (Result == null)
                {
                    TestStatusMsg(string.Format("?? Copy did not return CloudFile object ", 0));
                }
                else
                {
                    CopyRequiredMS = DateTime.Now.Subtract(Started).TotalMilliseconds;
                    TestStatusMsg(string.Format("Copied [{0}] to {1}", currentRow.name, Result.path));
                    if (UploadRequiredMS > 0)
                    {
                        TestStatusMsg(string.Format("Comparison: Upload {0:F1}ms; Copy {1:F1}ms; Pct {2:P2} ", UploadRequiredMS, CopyRequiredMS, CopyRequiredMS / UploadRequiredMS));
                    }
                }
            }
            catch (Exception ecopy)
            {
                TestStatusMsg("Copy File failed: " + ecopy.Message);
            }


            //FOURTH TEST: Rename File.
            TestStatusMsg("Test: Renaming file (by path)...");
            try
            {
                string oldName = "SFCE_test_file_prime.txt";
                string oldPath = tfoldername + "/" + oldName;
                Cloud_Elements_API.CloudElementsConnector.DirectoryEntryType ceType = Cloud_Elements_API.CloudElementsConnector.DirectoryEntryType.File;
                Cloud_Elements_API.CloudFile currentRow = TestFileStore;
                currentRow.path = tfoldername + "/SFCE_test_file_rename_path.txt";
                Cloud_Elements_API.CloudFile Result = await APIConnector.PatchDocEntryMetaData(ceType, Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.Path, oldPath, currentRow);

                TestStatusMsg(string.Format("Renamed [{0}] to {1}", oldName, Result.name));
                TestFileStore = Result;
            }
            catch (Exception er)
            {
                TestStatusMsg("Rename file by path failed: " + er.Message);
            }
            TestStatusMsg("Test: Renaming file (by ID)...");
            try
            {
                Cloud_Elements_API.CloudElementsConnector.DirectoryEntryType ceType = Cloud_Elements_API.CloudElementsConnector.DirectoryEntryType.File;
                Cloud_Elements_API.CloudFile currentRow = TestFileStore;
                string oldName = TestFileStore.name;
                currentRow.path = tfoldername + "/SFCE_test_file_rename_id.txt";

                Cloud_Elements_API.CloudFile PatchData = new Cloud_Elements_API.CloudFile();
                PatchData.id   = currentRow.id;
                PatchData.path = currentRow.path;
                Cloud_Elements_API.CloudFile Result = await APIConnector.PatchDocEntryMetaData(ceType, Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.ID, TestFileStore.id, PatchData);

                TestStatusMsg(string.Format("Renamed [{0}] to {1}", oldName, Result.name));
                TestFileStore = Result;
            }
            catch (Exception er)
            {
                TestStatusMsg("Rename file failed: " + er.Message);
            }

            //FIFTH TEST: Add two Tags
            TestStatusMsg("Test: Adding Tags...");

            try
            {
                for (int i = 1; i <= 2; i++)
                {
                    string TagToSet = "API Test Tag #" + i.ToString();
                    Cloud_Elements_API.CloudFile currentRow = TestFileStore;
                    TestFileStore = await Cloud_Elements_API.TagOperations.SetTag(APIConnector, currentRow, TagToSet);

                    TestStatusMsg(string.Format("Tag <{0}> added to [{1}] ", TagToSet, currentRow.name));
                }
            }
            catch (Exception etag)
            {
                TestStatusMsg("Add Tag failed: " + etag.Message);
            }

            //SIXTH TEST: Remove a Tag
            TestStatusMsg("Test: Deleting Tags...");

            try
            {
                for (int i = 1; i <= 2; i++)
                {
                    string TagToDel = "API Test Tag #" + i.ToString();
                    Cloud_Elements_API.CloudFile currentRow = TestFileStore;
                    TestFileStore = await Cloud_Elements_API.TagOperations.DeleteTag(APIConnector, currentRow, TagToDel);

                    TestStatusMsg(string.Format("Tag <{0}> removed from [{1}] ", TagToDel, currentRow.name));
                }
            }
            catch (Exception edt)
            {
                TestStatusMsg("Delete Tag failed: " + edt.Message);
            }

            //SEVENTH TEST: Async Uploads
            TestStatusMsg("Test: Multiple ASYNC uploads...");
            NumberOfFilesAlreadyUploaded = 0;
            bool AsyncUploadPassed = false;

            System.Func <Task <string> > UploadTestAction;
            Task <Task <string> >        AsyncUploadTest = null;
            Task <string> FinalAwaitableTestTask         = null;

            System.Runtime.CompilerServices.ConfiguredTaskAwaitable <Task <string> > AwaitableTestTask;
            try
            {
                string info;
                // we need to run away from the UI
                UploadTestAction = new System.Func <Task <string> >(TestMultiFileAsyncUploads);

                AsyncUploadTest = new Task <Task <string> >(UploadTestAction);
                AsyncUploadTest.Start();
                AwaitableTestTask      = AsyncUploadTest.ConfigureAwait(false);
                FinalAwaitableTestTask = await AwaitableTestTask;
                info = await FinalAwaitableTestTask;
                TestStatusMsg(info);
                AsyncUploadPassed = true;

                NumberOfFilesAlreadyUploaded = 8;
            }
            catch (Exception eu)
            {
                TestStatusMsg("Async Uploads   failed: " + eu.Message);
            }

            if (AsyncUploadPassed)
            {
                //SEVENTH TEST: repeat Async Uploads
                UploadTestAction = new System.Func <Task <string> >(TestMultiFileAsyncUploads);
                AsyncUploadTest  = new Task <Task <string> >(UploadTestAction);
                TestStatusMsg("Test: Repeat Multiple ASYNC uploads, without waiting...");
                AsyncUploadTest.Start();
                AwaitableTestTask = AsyncUploadTest.ConfigureAwait(false);
            }

            //EIGHTH TEST: Download File
            TestStatusMsg("Test: Downloading file...");
            System.IO.Stream Target = null;
            try
            {
                string TargetPath = tfoldername + string.Format("/SFCE_test_file_{0}.txt", "1");
                Cloud_Elements_API.CloudFile FileRow = await Cloud_Elements_API.FileOperations.GetCloudFileInfo(APIConnector, Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.Path, TargetPath);

                if (FileRow != null)
                {
                    Cloud_Elements_API.FileContent Result = await APIConnector.GetFile(FileRow);

                    string fn = System.IO.Path.Combine(WorkPath, Result.Disposition);
                    if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(fn)))
                    {
                        System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(fn));
                    }
                    if (System.IO.File.Exists(fn))
                    {
                        System.IO.File.Delete(fn);
                    }
                    Target = new System.IO.FileStream(fn, System.IO.FileMode.Create, System.Security.AccessControl.FileSystemRights.FullControl, System.IO.FileShare.None, 16384, System.IO.FileOptions.Asynchronous, null);
                    await Cloud_Elements_API.Tools.StreamCopyWithProgress(Result.ContentStream, Target, Result.ContentLength);

                    Result.ContentStream.Close();
                    Result.Dispose();
                    Target.Close();
                    Target = null;
                    System.IO.FileInfo finfo = new System.IO.FileInfo(fn);
                    TestStatusMsg(string.Format("Stored {1}: {0}", Cloud_Elements_API.Tools.SizeInBytesToString(finfo.Length), Result.Disposition));
                    int DownloadedHash = Cloud_Elements_API.Tools.FileToString(fn).GetHashCode();
                    if (DownloadedHash != DownloadTestExpectedHash)
                    {
                        TestStatusMsg(string.Format("Warning: Hash of {0} does not match", fn));
                    }
                }
                else
                {
                    TestStatusMsg(string.Format("Could not find file to download ({0})", TargetPath));
                }
            }
            catch (Exception ed)
            {
                TestStatusMsg("*** >>>> File download failed: " + ed.Message);
            }
            finally
            {
                if (Target != null)
                {
                    Target.Close();
                }
            }


            if (AsyncUploadPassed)
            {
                //NINETH TEST: Async Meta Info
                TestStatusMsg("Test: Multiple ASYNC File Meta Info reads ...");
                NumberOfFilesAlreadyUploaded = 0;
                System.Func <Task <string> > TestMetaInfoAction;
                Task <Task <string> >        AsyncMetaInfoTest = null;
                Task <string> FinalAwaitableMetaInfoTask       = null;
                System.Runtime.CompilerServices.ConfiguredTaskAwaitable <Task <string> > AwaitableMetaInfoTask;
                try
                {
                    // we need to run away from the UI
                    TestMetaInfoAction = new System.Func <Task <string> >(TestAsyncGetFileMeta);

                    AsyncMetaInfoTest = new Task <Task <string> >(TestMetaInfoAction);
                    AsyncMetaInfoTest.Start();
                    AwaitableMetaInfoTask      = AsyncMetaInfoTest.ConfigureAwait(false);
                    FinalAwaitableMetaInfoTask = await AwaitableMetaInfoTask;
                }
                catch (Exception eu)
                {
                    TestStatusMsg("Async Meta Info    failed: " + eu.Message);
                }


                AwaitableTestTask      = AsyncUploadTest.ConfigureAwait(false);
                FinalAwaitableTestTask = await AwaitableTestTask;
                string FinalInfo = await FinalAwaitableTestTask;
                TestStatusMsg(FinalInfo);
                FinalInfo = await FinalAwaitableMetaInfoTask;
                TestStatusMsg(FinalInfo);
            }



            TestStatusMsg(string.Format("Test suite complete: Elapsed time: {0:F1}s", DateTime.Now.Subtract(StartTime).TotalSeconds));
        }
        async Task <string> TestMultiFileAsyncUploads()
        {
            string tfoldername = AsyncBasePath; // set at start of tests

            System.Collections.Generic.Queue <Task <Cloud_Elements_API.CloudFile> >     UploadTasks    = new System.Collections.Generic.Queue <Task <Cloud_Elements_API.CloudFile> >();
            System.Collections.Generic.List <Cloud_Elements_API.CloudElementsConnector> ConnectorsUsed = new System.Collections.Generic.List <Cloud_Elements_API.CloudElementsConnector>();


            DateTime Started     = DateTime.Now;
            int      uploadCount = 0;

            System.IO.Stream teststream;
            string           RandomContent = GenerateRandomContent(256 * 1024 * 8);

            if (NumberOfFilesAlreadyUploaded == 0)
            {
                DownloadTestExpectedHash = RandomContent.GetHashCode();
            }
            long TotalBytes = 0;

            for (int i = 1; i <= 8; i++)
            {
                teststream    = GenerateStreamFromString(RandomContent);
                RandomContent = RandomContent.Substring(RandomContent.Length / 2);
                string        MIMEType    = Cloud_Elements_API.Tools.FileTypeToMimeContentType("txt");
                List <String> TagList     = new List <String>();
                long          sizeInBytes = teststream.Length;
                TotalBytes += sizeInBytes;
                string TargetPath = tfoldername + string.Format("/SFCE_test_file_{0}.txt", i + NumberOfFilesAlreadyUploaded);
                Cloud_Elements_API.CloudElementsConnector ViaConnector = APIConnector.Clone();
                ConnectorsUsed.Add(ViaConnector);
                Task <Cloud_Elements_API.CloudFile> AnUpload = ViaConnector.PostFile(teststream, MIMEType,
                                                                                     TargetPath, "Temporary test file",
                                                                                     TagList.ToArray(), false, sizeInBytes);
                //System.Runtime.CompilerServices.ConfiguredTaskAwaitable<Cloud_Elements_API.CloudFile> AwaitableUpload;
                //AwaitableUpload                  =    AnUpload.ConfigureAwait(false);

                UploadTasks.Enqueue(AnUpload);
                uploadCount += 1;
            }

            int rewaitCnt = 0;

            System.Text.StringBuilder Summary = new System.Text.StringBuilder();
            while (UploadTasks.Count > 0)
            {
                Task <Cloud_Elements_API.CloudFile> AnUpload = UploadTasks.Dequeue();

                if (AnUpload.GetAwaiter().IsCompleted)
                {
                    try
                    {
                        Cloud_Elements_API.CloudFile Result = await AnUpload;
                        Summary.AppendFormat("\t{5}: Task {2} Uploaded {4:F1}KB to {0}, id={1}, ok={3} \r\n", Result.name, Result.id, AnUpload.Id, !AnUpload.IsFaulted,
                                             Result.size / 1024d, Cloud_Elements_API.Tools.TraceTimeNow());
                    }
                    catch (Exception ex)
                    {
                        Summary.AppendFormat("\t{5}: Task {2} Upload Exception {0}, ok={3} \r\n", ex.Message, 0, AnUpload.Id, !AnUpload.IsFaulted,
                                             0, Cloud_Elements_API.Tools.TraceTimeNow());
                    }
                }
                else
                {
                    //   if (AnUpload.Status == TaskStatus.WaitingForActivation) AnUpload.ci
                    UploadTasks.Enqueue(AnUpload);
                    rewaitCnt += 1;
                    System.Threading.Thread.Sleep(128);
                }
            }

            foreach (Cloud_Elements_API.CloudElementsConnector ViaConnector in ConnectorsUsed)
            {
                ViaConnector.Close();
            }
            ConnectorsUsed.Clear();

            Summary.AppendFormat("\t{0}: Finished \r\n", Cloud_Elements_API.Tools.TraceTimeNow());
            double RequiredMS = DateTime.Now.Subtract(Started).TotalMilliseconds;

            Summary.Insert(0, string.Format("Uploaded {0} files in {1:F2}s, average {2:F2}s / file, {4:F2}ms/KB; Async Waits: {3} \r\n", uploadCount, RequiredMS / 1000d, RequiredMS / (1000d * uploadCount),
                                            rewaitCnt, (RequiredMS) / (TotalBytes / 1024d)));
            return(Summary.ToString());
        }
        async Task <string> TestAsyncGetFileMeta()
        {
            string tfoldername = AsyncBasePath; // as set at start of tests

            System.Collections.Generic.Queue <Task <Cloud_Elements_API.CloudFile> >     MetaTasks      = new System.Collections.Generic.Queue <Task <Cloud_Elements_API.CloudFile> >();
            System.Collections.Generic.List <Cloud_Elements_API.CloudElementsConnector> ConnectorsUsed = new System.Collections.Generic.List <Cloud_Elements_API.CloudElementsConnector>();
            DateTime Started   = DateTime.Now;
            int      MetaCount = 0;

            for (int rr = 1; rr <= 4; rr++)
            {
                for (int i = 1; i <= 16; i++)
                {
                    string TargetPath = tfoldername + string.Format("/SFCE_test_file_{0}.txt", i);
                    Cloud_Elements_API.CloudElementsConnector ViaConnector = null;
                    ViaConnector = APIConnector.Clone();
                    Task <Cloud_Elements_API.CloudFile> OneMeta = Cloud_Elements_API.FileOperations.GetCloudFileInfo(ViaConnector, Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.Path, TargetPath);
                    ConnectorsUsed.Add(ViaConnector);
                    MetaTasks.Enqueue(OneMeta);
                    if (SerializeGetFileMetadataRequests)
                    {
                        OneMeta.Wait();
                    }
                    MetaCount += 1;
                }
            }

            int rewaitCnt = 0;

            System.Text.StringBuilder Summary = new System.Text.StringBuilder();
            while (MetaTasks.Count > 0)
            {
                Task <Cloud_Elements_API.CloudFile> AnUpload = MetaTasks.Dequeue();

                if (AnUpload.GetAwaiter().IsCompleted)
                {
                    try
                    {
                        Cloud_Elements_API.CloudFile Result = await AnUpload;
                        if (Result != null)
                        {
                            Summary.AppendFormat("\t{5}: Task {2} File Info for {0}, id={1}, ok={3} \r\n", Result.name, Result.id, AnUpload.Id, !AnUpload.IsFaulted,
                                                 0, Cloud_Elements_API.Tools.TraceTimeNow());
                        }
                        else
                        {
                            Summary.AppendFormat("\t{5}: Task {2} did not obtain file Info for {0}, id={1}, ok={3} \r\n", "", "", AnUpload.Id, !AnUpload.IsFaulted,
                                                 0, Cloud_Elements_API.Tools.TraceTimeNow());
                        }
                    }
                    catch (Exception ex)
                    {
                        Summary.AppendFormat("\t{5}: Task {2} File Info Exception {0}, ok={3} \r\n", ex.Message, 0, AnUpload.Id, !AnUpload.IsFaulted,
                                             0, Cloud_Elements_API.Tools.TraceTimeNow());
                    }
                }
                else
                {
                    //   if (AnUpload.Status == TaskStatus.WaitingForActivation) AnUpload.ci
                    MetaTasks.Enqueue(AnUpload);
                    rewaitCnt += 1;
                    System.Threading.Thread.Sleep(128);
                }
            }

            foreach (Cloud_Elements_API.CloudElementsConnector ViaConnector in ConnectorsUsed)
            {
                ViaConnector.Close();
            }
            ConnectorsUsed.Clear();

            Summary.AppendFormat("\t{0}: Finished \r\n", Cloud_Elements_API.Tools.TraceTimeNow());
            double RequiredMS = DateTime.Now.Subtract(Started).TotalMilliseconds;

            Summary.Insert(0, string.Format("Got {0} file infos in {1:F2}s, average {2:F2}s / file; Async Waits: {3} \r\n", MetaCount, RequiredMS / 1000d, RequiredMS / (1000d * MetaCount),
                                            rewaitCnt, 0));
            return(Summary.ToString());
        }
        private async Task <bool> scanForEmptyFolders(EmptyFolderOptions scanOptions, Cloud_Elements_API.CloudFile currentRow)
        {
            //StatusMsg(string.Format("Scanning folder {0}", currentRow.name));
            Cloud_Elements_API.CloudElementsConnector ViaConnector = APIConnector.Clone();
            bool deletedAnything = false;

            try
            {
                if (currentRow.directory)
                {
                    List <Cloud_Elements_API.CloudFile> ResultList = null;
                    if (currentRow.size > 0)
                    {
                        ResultList = await ViaConnector.ListFolderContents(Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.Path, currentRow.path, chkWithTags.Checked);

                        TestStatusMsg(string.Format("FYI: Folder {1} contains {0} bytes in file(s)", currentRow.size, currentRow.path));

                        for (int i = 0; i < ResultList.Count; i++)
                        {
                            if (ResultList[i].directory)
                            {
                                deletedAnything = await scanForEmptyFolders(scanOptions, ResultList[i]);
                            }
                        }
                    }


                    // if anything was deleted by our recursive calls, we need to re-get the result list!
                    if (deletedAnything)
                    {
                        ResultList = await ViaConnector.ListFolderContents(Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.Path, currentRow.path, chkWithTags.Checked);

                        //TestStatusMsg(string.Format("FYI: Folder {1} now contains {0} bytes", currentRow.size, currentRow.path));
                        if (ResultList.Count > 1)
                        {
                            return(deletedAnything);
                        }
                    }

                    if ((currentRow.size > 0) && (scanOptions.SingleFileOK) && (ResultList.Count == 1) && !ResultList[0].directory)
                    {
                        double fileAge = -1;
                        if (ResultList[0].IsCreatedValid)
                        {
                            fileAge = DateTime.Now.Subtract(ResultList[0].WhenCreated()).TotalHours;
                        }
                        if ((ResultList[0].size <= scanOptions.SingleFileSizeUnder) &&
                            (!scanOptions.SingleFileTagRequired || ResultList[0].HasTags) &&
                            (ResultList[0].IsCreatedValid && (fileAge >= scanOptions.SingleFileAgeInHours)) &&
                            (ResultList[0].path.EndsWith(scanOptions.SingleFileType, StringComparison.CurrentCultureIgnoreCase)))
                        {
                            // single file is ok to ignored (removed message from here)
                        }
                        else
                        {
                            TestStatusMsg(string.Format("Kept {0} - folder contains {1}, {2} bytes; {3:F1} hours old", currentRow.path, ResultList[0].name, ResultList[0].size, fileAge));
                            return(deletedAnything);
                        }
                    }

                    if ((scanOptions.PathCheck) && (currentRow.path.IndexOf(scanOptions.PathMustContain, StringComparison.CurrentCultureIgnoreCase) < 0))
                    {
                        TestStatusMsg(string.Format("Kept {0} - folder path does not contain {1}", currentRow.path, scanOptions.PathMustContain));
                        return(deletedAnything);
                    }

                    TestStatusMsg(string.Format("Deleting {0}; (empty)", currentRow.path));
                    StatusMsg(string.Format("Deleting {0}, size={1}", currentRow.path, Cloud_Elements_API.Tools.SizeInBytesToString(currentRow.size)));
                    deletedAnything = await ViaConnector.DeleteFolder(Cloud_Elements_API.CloudElementsConnector.FileSpecificationType.Path, currentRow.path, false);

                    CountOfFoldersRemoved++;
                }
            }
            catch (Exception exep)
            {
                StatusMsg(string.Format("Problem! {0}", exep));
            }

            ViaConnector.Close();
            return(deletedAnything);
        }