/// <summary>
        /// Retrieve an existing rule for editing. If none is found then a default, bare-bones rule is returned for creating new
        /// A new rule is not persisted until it is saved. Distinct Rules are defined by the combination key of deviceID and ruleId
        /// 
        /// Use this method if you are not sure the desired rule exists
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="ruleId"></param>
        /// <returns></returns>
        public async Task<DeviceRule> GetDeviceRuleOrDefaultAsync(string deviceId, string ruleId)
        {
            List<DeviceRule> rulesForDevice = await _deviceRulesRepository.GetAllRulesForDeviceAsync(deviceId);
            foreach(DeviceRule rule in rulesForDevice)
            {
                if(rule.RuleId == ruleId)
                {
                    return rule;
                }
            }

            var createdRule = new DeviceRule();
            createdRule.InitializeNewRule(deviceId);
            return createdRule;
        }
        /// <summary>
        /// Save a rule to the data store. This method should be used for new rules as well as updating existing rules
        /// </summary>
        /// <param name="updatedRule"></param>
        /// <returns></returns>
        public async Task<TableStorageResponse<DeviceRule>> SaveDeviceRuleAsync(DeviceRule updatedRule)
        {
            //Enforce single instance of a rule for a data field for a given device
            List<DeviceRule> foundForDevice = await _deviceRulesRepository.GetAllRulesForDeviceAsync(updatedRule.DeviceID);
            foreach(DeviceRule rule in foundForDevice)
            {
                if(rule.DataField == updatedRule.DataField && rule.RuleId != updatedRule.RuleId)
                {
                    var response = new TableStorageResponse<DeviceRule>();
                    response.Entity = rule;
                    response.Status = TableStorageResponseStatus.DuplicateInsert;

                    return response;
                }
            }

            return await _deviceRulesRepository.SaveDeviceRuleAsync(updatedRule);
        }
        public async void SaveDeviceRuleAsyncTest()
        {
            var deviceId = fixture.Create<string>();
            var rules = fixture.Create<List<DeviceRule>>();
            rules.ForEach(x => x.DeviceID = deviceId);
            _deviceRulesRepositoryMock.Setup(x => x.GetAllRulesForDeviceAsync(deviceId)).ReturnsAsync(rules);
            _deviceRulesRepositoryMock.Setup(x => x.SaveDeviceRuleAsync(It.IsNotNull<DeviceRule>()))
                .ReturnsAsync(new TableStorageResponse<DeviceRule>());

            var newRule = new DeviceRule();
            newRule.InitializeNewRule(deviceId);
            newRule.DataField = rules[0].DataField;
            var ret = await deviceRulesLogic.SaveDeviceRuleAsync(newRule);
            Assert.NotNull(ret.Entity);
            Assert.Equal(TableStorageResponseStatus.DuplicateInsert, ret.Status);

            newRule.InitializeNewRule(deviceId);
            newRule.DataField = "New data in DataField";
            ret = await deviceRulesLogic.SaveDeviceRuleAsync(newRule);
            Assert.NotNull(ret);
        }
 public async Task<HttpResponseMessage> SaveDeviceRuleAsync(DeviceRule updatedRule)
 {
     return await GetServiceResponseAsync<TableStorageResponse<DeviceRule>>(async () =>
     {
         return await _deviceRulesLogic.SaveDeviceRuleAsync(updatedRule);
     });
 }
        /// <summary>
        /// Generate a new rule with bare-bones configuration. This new rule can then be conigured and sent
        /// back through the SaveDeviceRuleAsync method to persist.
        /// </summary>
        /// <param name="deviceId"></param>
        /// <returns></returns>
        public async Task<DeviceRule> GetNewRuleAsync(string deviceId)
        {
            return await Task.Run(() =>
            {
                var rule = new DeviceRule();
                rule.InitializeNewRule(deviceId);

                return rule;
            }); 
        }
        private EditDeviceRuleModel CreateEditModelFromDeviceRule(DeviceRule rule)
        {
            EditDeviceRuleModel editModel = new EditDeviceRuleModel();
            editModel.RuleId = rule.RuleId;
            editModel.DataField = rule.DataField;
            editModel.DeviceID = rule.DeviceID;
            editModel.EnabledState = rule.EnabledState;
            editModel.Etag = rule.Etag;
            editModel.Operator = rule.Operator;
            editModel.RuleOutput = rule.RuleOutput;
            if (rule.Threshold != null)
            {
                editModel.Threshold = rule.Threshold.ToString();
            }

            return editModel;
        }
        private DeviceRule CreateDeviceRuleFromEditModel(EditDeviceRuleModel editModel)
        {
            DeviceRule rule = new DeviceRule(editModel.RuleId);
            rule.DataField = editModel.DataField;
            rule.DeviceID = editModel.DeviceID;
            rule.EnabledState = editModel.EnabledState;
            rule.Etag = editModel.Etag;
            rule.Operator = editModel.Operator;
            rule.RuleOutput = editModel.RuleOutput;
            if (!string.IsNullOrWhiteSpace(editModel.Threshold))
            {
                rule.Threshold =
                    double.Parse(
                        editModel.Threshold,
                        NumberStyles.Float,
                        CultureInfo.CurrentCulture);
            }

            return rule;
        }
        private DeviceRule BuildRuleFromTableEntity(DeviceRuleTableEntity tableEntity)
        {
            if(tableEntity == null)
            {
                return null;
            }

            var updatedRule = new DeviceRule(tableEntity.RuleId)
            {
                DeviceID = tableEntity.DeviceId,
                DataField = tableEntity.DataField,
                Threshold = tableEntity.Threshold,
                EnabledState = tableEntity.Enabled,
                Operator = ">",
                RuleOutput = tableEntity.RuleOutput,
                Etag = tableEntity.ETag
            };

            return updatedRule;
        }
        /// <summary>
        /// Save a Device Rule to the server. This may be either a new rule or an update to an existing rule. 
        /// </summary>
        /// <param name="updateContainer"></param>
        /// <returns></returns>
        public async Task<TableStorageResponse<DeviceRule>> SaveDeviceRuleAsync(DeviceRule updatedRule)
        {
            DeviceRuleTableEntity incomingEntity = 
                new DeviceRuleTableEntity(updatedRule.DeviceID, updatedRule.RuleId)
            {
                DataField = updatedRule.DataField,
                Threshold = (double)updatedRule.Threshold,
                Enabled = updatedRule.EnabledState,
                RuleOutput = updatedRule.RuleOutput
            };
            
            if(!string.IsNullOrWhiteSpace(updatedRule.Etag))
            {
                incomingEntity.ETag = updatedRule.Etag;
            }

            TableStorageResponse<DeviceRule> result = 
                await AzureTableStorageHelper.DoTableInsertOrReplace<DeviceRule, DeviceRuleTableEntity>(incomingEntity, BuildRuleFromTableEntity, 
                _storageAccountConnectionString, _deviceRulesNormalizedTableName); 

            // Build up a new blob to push up
            List<DeviceRuleBlobEntity> blobList = await BuildBlobEntityListFromTableRows();
            await PersistRulesToBlobStorageAsync(blobList);

            return result;
        }
        private DeviceRuleTableEntity BuildTableEntityFromRule(DeviceRule incomingRule)
        {
            DeviceRuleTableEntity tableEntity =
                new DeviceRuleTableEntity(incomingRule.DeviceID, incomingRule.RuleId)
                {
                    DataField = incomingRule.DataField,
                    Threshold = (double)incomingRule.Threshold,
                    Enabled = incomingRule.EnabledState,
                    RuleOutput = incomingRule.RuleOutput
                };

            if (!string.IsNullOrWhiteSpace(incomingRule.Etag))
            {
                tableEntity.ETag = incomingRule.Etag;
            }

            return tableEntity;
        }
        public async Task<TableStorageResponse<DeviceRule>> DeleteDeviceRuleAsync(DeviceRule ruleToDelete)
        {
            DeviceRuleTableEntity incomingEntity = BuildTableEntityFromRule(ruleToDelete);

            TableStorageResponse<DeviceRule> result =
                await AzureTableStorageHelper.DoDeleteAsync<DeviceRule, DeviceRuleTableEntity>(incomingEntity, BuildRuleFromTableEntity,
                _storageAccountConnectionString, _deviceRulesNormalizedTableName);

            if (result.Status == TableStorageResponseStatus.Successful)
            {
                // Build up a new blob to push up for ASA job ref data
                List<DeviceRuleBlobEntity> blobList = await BuildBlobEntityListFromTableRows();
                await PersistRulesToBlobStorageAsync(blobList);
            }

            return result;
        }