/// Responds to a cstore request, which kicks off a StreamToRules task
        public DicomCStoreResponse OnCStoreRequest(DicomCStoreRequest request)
        {
            var taskID = _taskManager.NewTaskID();

            var taskInfo =
                $"task: {taskID} messageID: {request.MessageID} connection: {((DICOMConnection)(base.UserState)).name}";

            try
            {
                var fromConnection = _connectionFinder.GetDicomConnectionToLocalAETitle(_profileStorage.Current, Association.CalledAE);

                if (fromConnection == null)
                {
                    //We have an inbound Association.CalledAE that we aren't configured for
                    logger.Log(LogLevel.Warning, $"{taskInfo} There is no connection defined where the LocalAETitle matches the Association.CalledAE: {Association.CalledAE}");
                    return(new DicomCStoreResponse(request, DicomStatus.ProcessingFailure));
                }

                logger.Log(LogLevel.Information, $"{taskInfo} CStoreRequest from {fromConnection.name}");

                var conn = ((DICOMConnection)(base.UserState));
                // var dir = profile.tempPath + Path.DirectorySeparatorChar + ((DICOMConnection)(base.UserState)).name + Path.DirectorySeparatorChar + "toRules";
                // Directory.CreateDirectory(dir);
                // var filename = dir + Path.DirectorySeparatorChar + System.Guid.NewGuid();
                // LifeImageLite.Logger.logger.Log(TraceEventType.Verbose, $"{taskInfo} Moving from {request.File.File.Name} to {filename}");
                // request.File.File.Move(dstFileName: filename);
                RoutedItem routedItem = new RoutedItem(
                    fromConnection: fromConnection.name,
                    sourceFileName: request.File.File.Name,
                    taskID: taskID)
                {
                    type = RoutedItem.Type.DICOM
                };

                request.Dataset.TryGetValue <string>(DicomTag.PatientID, 0, out routedItem.PatientID);
                request.Dataset.TryGetValue <string>(DicomTag.AccessionNumber, 0, out routedItem.AccessionNumber);
                request.Dataset.TryGetValue <string>(DicomTag.StudyInstanceUID, 0, out routedItem.Study);
                request.Dataset.TryGetValue <string>(DicomTag.StudyID, 0, out routedItem.StudyID);

                foreach (var item in request.Command)
                {
                    logger.Log(LogLevel.Debug, $"Command tag: {item.Tag} value: {item.ValueRepresentation}");
                }

                routedItem.id =
                    $"PID:{routedItem.PatientID}, AN:{routedItem.AccessionNumber}"; // , UID:{routedItem.Study}";

                //profile.rules.SendToRules(routedItem).Wait();
                routedItem.priority = _util.GetPriority((ushort)request.Priority);

                _routedItemManager.Init(routedItem);
                _routedItemManager.Enqueue(conn, conn.toRules, nameof(conn.toRules), copy: true);
                DicomStatus status = DicomStatus.Success;

                DicomCStoreResponse response = new DicomCStoreResponse(request, status)
                {
                    //Dataset = request.Dataset
                };
                response.Command.AddOrUpdate(DicomTag.AffectedSOPInstanceUID,
                                             request.Dataset.GetValue <string>(DicomTag.SOPInstanceUID, 0));
                response.Command.AddOrUpdate(DicomTag.AffectedSOPClassUID,
                                             request.Dataset.GetValue <string>(DicomTag.SOPClassUID, 0));
                return(response);
            }
            catch (Exception e)
            {
                logger.Log(LogLevel.Critical, $"{taskInfo} {e.Message} {e.StackTrace}");

                if (e.InnerException != null)
                {
                    logger.Log(LogLevel.Critical, $"Inner Exception: {e.InnerException}");
                }

                request.Dataset.AddOrUpdate(DicomTag.AffectedSOPInstanceUID,
                                            request.Dataset.GetValue <string>(DicomTag.SOPInstanceUID, 0));
                return(new DicomCStoreResponse(request,
                                               new DicomStatus(DicomStatus.ProcessingFailure,
                                                               $"CStore Response Exception: {e.Message} {e.StackTrace}"))); //out of resources not much flexibility here
            }
            finally
            {
            }
        }
        public void CFind(RoutedItem routedItem, DICOMConnection Connection, int taskID)
        {
            var taskInfo  = $"task: {taskID} connection: {Connection.name}";
            var stopWatch = new Stopwatch();

            stopWatch.Start();

            try
            {
                LiCloudRequest cFindParams = LiCloudRequest.FromJson(routedItem.request, _logger);
                foreach (var tag in cFindParams.searchTags)
                {
                    _logger.Log(LogLevel.Debug, $"{taskInfo} id: {routedItem.id} tag: {tag.Key} {tag.Value}");
                }

                DicomCFindRequest cFind      = null;
                string            cfindlevel = "";
                cFindParams.searchTags.TryGetValue("0008,0052", out cfindlevel);

                switch (cfindlevel)
                {
                case "SERIES":
                    cFind = new DicomCFindRequest(DicomQueryRetrieveLevel.Series);
                    break;

                case "IMAGE":
                    cFind = new DicomCFindRequest(DicomQueryRetrieveLevel.Image);
                    break;

                case "PATIENT":
                    cFind = new DicomCFindRequest(DicomQueryRetrieveLevel.Patient);
                    break;

                case "WORKLIST":
                case "NA":
                    cFind = new DicomCFindRequest(DicomQueryRetrieveLevel.NotApplicable);
                    break;

                case "STUDY":
                default:
                    cFind = new DicomCFindRequest(DicomQueryRetrieveLevel.Study);
                    break;
                }

                _logger.Log(LogLevel.Information, $"{taskInfo} Request id: {routedItem.id} MessageID: {cFind.MessageID} attempt: {routedItem.attempts}");

                //default return tags

                // Encoding encoding = DicomEncoding.GetEncoding(cFindCharacterSet);
                // if(cFindCharacterSet != null){
                //     cFind.Dataset.AddOrUpdate(DicomTag.SpecificCharacterSet, cFindCharacterSet);
                // }
                // cFind.Dataset.AddOrUpdate(DicomTag.PatientID, encoding, "");
                // cFind.Dataset.AddOrUpdate(DicomTag.PatientName, encoding, "");
                // cFind.Dataset.AddOrUpdate(DicomTag.PatientBirthDate, encoding, "");
                // cFind.Dataset.AddOrUpdate(DicomTag.PatientSex, encoding, "");
                // cFind.Dataset.AddOrUpdate(DicomTag.StudyDate, encoding, "");
                // cFind.Dataset.AddOrUpdate(DicomTag.AccessionNumber, encoding, "");
                // cFind.Dataset.AddOrUpdate(DicomTag.StudyID, encoding, "");
                // cFind.Dataset.AddOrUpdate(DicomTag.ModalitiesInStudy, encoding, "");
                // cFind.Dataset.AddOrUpdate(DicomTag.StudyInstanceUID, encoding, "");
                // cFind.Dataset.AddOrUpdate(DicomTag.NumberOfStudyRelatedInstances, encoding, "");
                // cFind.Dataset.AddOrUpdate(DicomTag.NumberOfSeriesRelatedInstances, encoding, "");
                // cFind.Dataset.AddOrUpdate(DicomTag.StudyDescription, encoding, "");
                // cFind.Dataset.AddOrUpdate(DicomTag.ModalitiesInStudy, encoding, "");

                cFind.Dataset.AddOrUpdate(DicomTag.AccessionNumber, "");
                cFind.Dataset.AddOrUpdate(DicomTag.NumberOfStudyRelatedInstances, "");
                cFind.Dataset.AddOrUpdate(DicomTag.NumberOfSeriesRelatedInstances, "");
                cFind.Dataset.AddOrUpdate(DicomTag.Modality, "");
                cFind.Dataset.AddOrUpdate(DicomTag.ModalitiesInStudy, "");
                cFind.Dataset.AddOrUpdate(DicomTag.PatientID, "");
                cFind.Dataset.AddOrUpdate(DicomTag.PatientName, "");
                cFind.Dataset.AddOrUpdate(DicomTag.PatientBirthDate, "");
                cFind.Dataset.AddOrUpdate(DicomTag.PatientSex, "");
                cFind.Dataset.AddOrUpdate(DicomTag.StudyDate, "");
                cFind.Dataset.AddOrUpdate(DicomTag.StudyID, "");
                cFind.Dataset.AddOrUpdate(DicomTag.StudyInstanceUID, "");
                cFind.Dataset.AddOrUpdate(DicomTag.StudyDescription, "");
                // add the search tags
                foreach (KeyValuePair <string, string> tag in cFindParams.searchTags)
                {
                    try
                    {
                        // if(cFindCharacterSet != null){
                        //         Encoding iso = DicomEncoding.GetEncoding(cFindCharacterSet);
                        //         Encoding utf8 = Encoding.UTF8;
                        //         byte[] utfBytes = utf8.GetBytes(tag.Value);
                        //         byte[] isoBytes = Encoding.Convert(utf8, iso, utfBytes);
                        //         string value = iso.GetString(isoBytes);
                        //         //cFind.Dataset.AddOrUpdate(DicomTag.Parse(tag.Key), value);
                        //         cFind.Dataset.AddOrUpdate(DicomTag.Parse(tag.Key), Encoding.ASCII, value);

                        // } else {
                        cFind.Dataset.AddOrUpdate(DicomTag.Parse(tag.Key), tag.Value);

                        //                }
                    }
                    catch (Exception e)
                    {
                        _logger.LogFullException(e, taskInfo);
                    }
                }

                //connect the cFind to the RoutedItem that originated the request
                //the cache was already primed in GetRequests
                cFind.UserState           = routedItem;
                routedItem.MessageId      = cFind.MessageID;
                routedItem.fromConnection = Connection.name;
                routedItem.toConnections.Clear();
                routedItem.status = RoutedItem.Status.PENDING;

                // var riToCache = (RoutedItem)routedItem.Clone();
                // riToCache.Enqueue(this, toRules, nameof(toRules));

                cFind.OnResponseReceived = (DicomCFindRequest request, DicomCFindResponse response) =>
                {
                    RoutedItem ri = (RoutedItem)request.UserState;

                    _logger.Log(LogLevel.Information, $"{taskInfo} Response id: {ri.id} MessageID: {request.MessageID} status: {response.Status} elapsed: {stopWatch.Elapsed}");

                    //DICOMConnection dicomConn = LITE.profile.GetDicomConnectionToLocalAETitle(Connection.localAETitle);
                    DICOMConnection dicomConn = _connectionFinder.GetDicomConnectionToLocalAETitle(_profileStorage.Current, Connection.localAETitle);

                    Dictionary <string, string> returnTagData = new Dictionary <string, string>
                    {
                        { "StatusCode", response.Status.Code.ToString() },
                        { "StatusDescription", response.Status.Description },
                        { "StatusErrorComment", response.Status.ErrorComment },
                        { "StatusState", response.Status.State.ToString() }
                    };
                    if (response.Completed != 0 || response.Remaining != 0)
                    {
                        returnTagData.Add("Completed", response.Completed.ToString());
                        returnTagData.Add("Remaining", response.Remaining.ToString());
                    }

                    string key = "response";
                    Dictionary <string, Dictionary <string, string> > results = new Dictionary <string, Dictionary <string, string> >();
                    if (response.Dataset != null)
                    {
                        // Copy into a map, DicomDataset wont serialize
                        foreach (var dicomItem in response.Dataset)
                        {
                            _logger.Log(LogLevel.Debug, $"{taskInfo} Response id: {ri.id} MessageID: {request.MessageID}, {dicomItem.Tag.ToString()} {response.Dataset.GetValueOrDefault<string>(dicomItem.Tag, 0, "")}");
                            if (dicomItem.Tag.ToString() == "(0008,0054)") //BOUR-940 mask AETitle with conn name
                            {
                                returnTagData.Add(dicomItem.Tag.ToString(), Connection.name);
                            }
                            else
                            {
                                returnTagData.Add(dicomItem.Tag.ToString(), response.Dataset.GetValueOrDefault <string>(dicomItem.Tag, 0, ""));
                            }
                            if (dicomItem.Tag == DicomTag.StudyInstanceUID)
                            {
                                key = response.Dataset.GetValueOrDefault <string>(dicomItem.Tag, 0, "");
                            }
                        }
                        results.Add(key, returnTagData);
                    }

                    if ((results.Count == 0 && ri.response.Count == 0) || (results.Count > 0))
                    {
                        string jsonResults = JsonSerializer.Serialize(results);

                        // set results in RoutedItem
                        ri.response.Add(jsonResults);
                    }
                    switch (response.Status.ToString())
                    {
                    case "Success":
                        ri.status      = RoutedItem.Status.COMPLETED;
                        ri.resultsTime = DateTime.Now;

                        _routedItemManager.Init(ri);
                        _routedItemManager.Dequeue(Connection, Connection.toDicom, nameof(Connection.toDicom), error: false);
                        //var toCache = (RoutedItem)ri.Clone();
                        var toCache = _routedItemManager.Clone();
                        toCache.fromConnection = Connection.name;
                        toCache.toConnections.Clear();     //BOUR-863 the toConnections on the toCache object weren't being cleared before rules so it contained DICOMConnection which
                        toCache.attempts    = 0;
                        toCache.lastAttempt = DateTime.MinValue;

                        _routedItemManager.Init(toCache);
                        _routedItemManager.Enqueue(Connection, Connection.toRules, nameof(Connection.toRules));
                        break;

                    case "Pending":
                        break;

                    default:
                        _routedItemManager.Init(ri);
                        _routedItemManager.Dequeue(Connection, Connection.toDicom, nameof(Connection.toDicom), error: true);
                        break;
                    }
                };

                dicomClient.AddRequest(cFind);
            }
            catch (DicomDataException e)
            {
                _logger.Log(LogLevel.Warning, $"{taskInfo} query: {routedItem} {e.Message} {e.StackTrace} ");

                routedItem.status      = RoutedItem.Status.FAILED;
                routedItem.resultsTime = DateTime.Now;

                Dictionary <string, string> returnTagData = new Dictionary <string, string>
                {
                    { "StatusCode", "-1" },
                    { "StatusDescription", $"Error: {e.Message}" },
                    { "StatusErrorComment", $"Error: {e.StackTrace}" },
                    { "StatusState", "" }
                };

                string key = "response";

                Dictionary <string, Dictionary <string, string> > results = new Dictionary <string, Dictionary <string, string> >
                {
                    { key, returnTagData }
                };

                string jsonResults = JsonSerializer.Serialize(results);
                routedItem.response.Add(jsonResults);

                _routedItemManager.Init(routedItem);
                _routedItemManager.Dequeue(Connection, Connection.toDicom, nameof(Connection.toDicom), true);
                routedItem.fromConnection = Connection.name;
                routedItem.toConnections.Clear();

                _routedItemManager.Enqueue(Connection, Connection.toRules, nameof(Connection.toRules));
            }
            catch (Exception e)
            {
                _logger.LogFullException(e, taskInfo);

                Dictionary <string, string> returnTagData = new Dictionary <string, string>
                {
                    { "StatusCode", "-1" },
                    { "StatusDescription", $"Error: {e.Message}" },
                    { "StatusErrorComment", $"Error: {e.StackTrace}" },
                    { "StatusState", "" }
                };

                string key = "response";

                Dictionary <string, Dictionary <string, string> > results = new Dictionary <string, Dictionary <string, string> >
                {
                    { key, returnTagData }
                };

                string jsonResults = JsonSerializer.Serialize(results);
                routedItem.response.Add(jsonResults);
                if (routedItem.attempts > Connection.maxAttempts)
                {
                    routedItem.status      = RoutedItem.Status.FAILED;
                    routedItem.resultsTime = DateTime.Now;
                    _logger.Log(LogLevel.Debug, $"{taskInfo} id: {routedItem.id} exceeded max attempts.");

                    _routedItemManager.Init(routedItem);
                    _routedItemManager.Dequeue(Connection, Connection.toDicom, nameof(Connection.toDicom), true);
                }
                routedItem.fromConnection = Connection.name;
                routedItem.toConnections.Clear();

                _routedItemManager.Init(routedItem);
                _routedItemManager.Enqueue(Connection, Connection.toRules, nameof(Connection.toRules));
            }
        }