public void RemoveRoles(Guid id, int version, params AccountData[] accounts)
        {
            var filter = Builders <ProcessDefinitionPersistence> .Filter.And(
                Builders <ProcessDefinitionPersistence> .Filter.Eq(r => r.Id, id),
                Builders <ProcessDefinitionPersistence> .Filter.Eq(r => r.Version, version)
                );

            ProcessDefinitionPersistence persistence = _collection.FindSync(filter).FirstOrDefault();

            if (persistence == null)
            {
                throw new ArgumentException($"Process definition Id={id} Version={version} not found.");
            }
            List <AccountData> data = new List <AccountData>();

            data.AddRange(persistence.Accounts);
            foreach (AccountData accountData in accounts)
            {
                data.Remove(accountData);
            }
            UpdateDefinition <ProcessDefinitionPersistence> updatedef =
                Builders <ProcessDefinitionPersistence> .Update.Set(r => r.Accounts, data);

            _collection.FindOneAndUpdate(filter, updatedef);
        }
        /// <summary>
        /// Add new roles to the workflow
        /// </summary>
        /// <param name="id"></param>
        /// <param name="version"></param>
        /// <param name="accounts"></param>
        public void AddRoles(Guid id, int version, params AccountData[] accounts)
        {
            var filter = Builders <ProcessDefinitionPersistence> .Filter.And(
                Builders <ProcessDefinitionPersistence> .Filter.Eq(r => r.Id, id),
                Builders <ProcessDefinitionPersistence> .Filter.Eq(r => r.Version, version)
                );

            ProcessDefinitionPersistence persistence = _collection.FindSync(filter).FirstOrDefault();

            if (persistence == null)
            {
                throw new ArgumentException($"Process definition Id={id} Version={version} not found.");
            }
            List <AccountData> data = new List <AccountData>();

            data.AddRange(persistence.Accounts);
            foreach (AccountData accountData in accounts)
            {
                if (data.Any(d => d.Id == accountData.Id ||
                             string.Equals(d.Name, accountData.Name, StringComparison.InvariantCultureIgnoreCase)))
                {
                    _logger.Debug($"skipping {accountData.Id}:{accountData.Name}");
                    continue;
                }
                data.Add(accountData);
            }
            UpdateDefinition <ProcessDefinitionPersistence> updatedef =
                Builders <ProcessDefinitionPersistence> .Update.Set(r => r.Accounts, data);

            _collection.FindOneAndUpdate(filter, updatedef);
        }
        /// <summary>
        /// Ceate process definition
        /// </summary>
        /// <param name="definition"></param>
        /// <param name="status"></param>
        /// <param name="version"></param>
        /// <param name="accounts"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void Create(ProcessDefinition definition, ProcessDefStatusEnum status, int version, params AccountData[] accounts)
        {
            Md5CalcVisitor visitor = new Md5CalcVisitor();

            definition.Accept(visitor);
            string md5 = visitor.CalculateMd5();

            if (_collection.Find(f => f.FlowId == definition.FlowId && string.Equals(f.Md5, md5)).Count() != 0)
            {
                throw new ArgumentException($"Persistend Workflow definition FlowId={definition.FlowId} Md5={md5} already exists.");
            }
            List <AccountData> accountsList = new EditableList <AccountData>();

            if (accounts != null)
            {
                accountsList.AddRange(accounts);
            }
            ProcessDefinitionPersistence pd = new ProcessDefinitionPersistence
            {
                Id                    = definition.Id,
                FlowId                = definition.FlowId,
                Version               = version,
                Name                  = definition.Name,
                Description           = definition.Description,
                LastModified          = DateTime.UtcNow,
                Status                = (int)status,
                Md5                   = md5,
                JsonProcessDefinition = ToBase64(JsonConvert.SerializeObject(definition)),
                Accounts              = accountsList
            };

            _collection.InsertOne(pd);
        }
        /// <summary>
        /// Try find a workflow definition
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="definition"></param>
        /// <param name="status"></param>
        /// <param name="accounts"></param>
        /// <returns></returns>
        public bool TryFind(FilterDefinition <ProcessDefinitionPersistence> filter, out ProcessDefinition definition, out ProcessDefStatusEnum status,
                            out AccountData[] accounts)
        {
            status     = ProcessDefStatusEnum.NotActive;
            definition = null;
            accounts   = new AccountData[] {};
            ProcessDefinitionPersistence pd = _collection.Find(filter).SingleOrDefault();

            if (pd != null)
            {
                string v = FromBase64(pd.JsonProcessDefinition);
                definition = JsonConvert.DeserializeObject <ProcessDefinition>(FromBase64(pd.JsonProcessDefinition));
                status     = (ProcessDefStatusEnum)pd.Status;
                accounts   = pd.Accounts?.ToArray();
            }
            return(pd != null);
        }