protected override void DoDeleteItem(JsonItem item)
    {
      Assert.ArgumentNotNull(item, nameof(item));

      // no need in lock
      if (item.ParentID == this.ItemID)
      {
        this.ItemChildren.Remove(item);
      }
      else
      {
        var parentID = item.ParentID;
        var parent = this.ItemsCache[parentID];
        Assert.IsNotNull(parent, "parent");

        parent.Children.Remove(item);
      }
    }
 protected override bool IgnoreItem(JsonItem item)
 {
   return false;
 }
    public override bool CreateItem(ID itemID, string itemName, ID templateID, ID parentID)
    {
      Assert.ArgumentNotNull(itemID, nameof(itemID));
      Assert.ArgumentNotNull(itemName, nameof(itemName));
      Assert.ArgumentNotNull(templateID, nameof(templateID));
      Assert.ArgumentNotNull(parentID, nameof(parentID));

      if (this.ReadOnly)
      {
        return false;
      }

      JsonItem parent = null;

      if (this.ItemID != parentID)
      {
        parent = this.GetItem(parentID);
        if (parent == null || this.IgnoreItem(parent))
        {
          return false;
        }
      }

      var item = new JsonItem(itemID, parentID)
      {
        Name = itemName,
        TemplateID = templateID
      };

      Lock.EnterWriteLock();
      try
      {
        this.ItemsCache[item.ID] = item;

        if (parent != null)
        {
          parent.Children.Add(item);
        }
        else
        {
          this.ItemChildren.Add(item);
        }
      }
      finally
      {
        Lock.ExitWriteLock();
      }

      this.Commit();

      return true;
    }
    public bool CreateItem([NotNull] ID itemID, [NotNull] string itemName, [NotNull] ID templateID, [NotNull] ID parentID)
    {
      Assert.ArgumentNotNull(itemID, "itemID");
      Assert.ArgumentNotNull(itemName, "itemName");
      Assert.ArgumentNotNull(templateID, "templateID");
      Assert.ArgumentNotNull(parentID, "parentID");

      JsonItem parent = null;
      if (this.RootID != parentID)
      {
        parent = this.Items.FirstOrDefault(x => x.ID == parentID);
        if (parent == null)
        {
          return false;
        }
      }

      var item = new JsonItem(itemID, parentID)
        {
          Name = itemName,
          TemplateID = templateID
        };

      lock (this.SyncRoot)
      {
        this.Items.Add(item);

        if (parent != null)
        {
          parent.Children.Add(item);
        }
        else
        {
          this.RootItems.Add(item);
        }

        this.Commit();
      }

      return true;
    }
    public override bool CreateItem(ID itemID, string itemName, ID templateID, ID parentID)
    {
      Assert.ArgumentNotNull(itemID, nameof(itemID));
      Assert.ArgumentNotNull(itemName, nameof(itemName));
      Assert.ArgumentNotNull(templateID, nameof(templateID));
      Assert.ArgumentNotNull(parentID, nameof(parentID));

      if (this.ReadOnly)
      {
        return false;
      }

      var parent = this.GetItemRaw(parentID);

      Lock.EnterWriteLock();
      try
      {
        // no need to check: parent.ParentID == ID.Null
        if (parent == null)
        {
          parent = this.AddRootItem(parentID);
        }

        var item = new JsonItem(itemID, parentID)
        {
          Name = itemName,
          TemplateID = templateID
        };

        this.ItemsCache[item.ID] = item;

        parent.Children.Add(item);
      }
      finally
      {
        Lock.ExitWriteLock();
      }

      this.Commit();

      return true;
    }
 protected override bool IgnoreItem(JsonItem item)
 {
   return item.ParentID == ID.Null;
 }
    private JsonItem AddRootItem([NotNull] ID itemID)
    {
      Assert.ArgumentNotNull(itemID, nameof(itemID));

      var rootItem = new JsonItem(itemID, ID.Null)
      {
        Name = "$default-mapping"
      };

      // no need to lock 
      this.ItemChildren.Add(rootItem);
      this.ItemsCache[rootItem.ID] = rootItem;

      return rootItem;
    }
    protected JsonItem DoCopy(ID sourceItemID, ID destinationItemID, ID copyID, string copyName, CallContext context)
    {
      var source = context.DataManager.Database.GetItem(sourceItemID);
      var item = new JsonItem(copyID, destinationItemID)
      {
        Name = copyName,
        TemplateID = source.TemplateID
      };

      var sharedIds = source.Template.Fields.Where(x => x.IsShared).Select(x => x.ID).ToArray();
      foreach (var fieldId in sharedIds)
      {
        if (JsonDataProvider.IgnoreFields.Keys.Contains(fieldId))
        {
          continue;
        }

        var field = source.Fields[fieldId];
        var value = field.GetValue(false, false, false, false);
        if (value == null)
        {
          continue;
        }

        item.Fields.Shared[fieldId] = value;
      }

      var unversionedIds = source.Template.Fields.Where(x => x.IsUnversioned).Select(x => x.ID).ToArray();
      foreach (var language in source.Languages)
      {
        var version = source.Versions.GetLatestVersion(language);
        var json = item.Fields.Unversioned[language];
        foreach (var fieldId in unversionedIds)
        {
          if (JsonDataProvider.IgnoreFields.Keys.Contains(fieldId))
          {
            continue;
          }

          var field = version.Fields[fieldId];
          var value = field.GetValue(false, false, false, false);
          if (value == null)
          {
            continue;
          }

          json[fieldId] = value;
        }
      }

      var versionedIds = source.Template.Fields.Where(x => !x.IsShared && !x.IsUnversioned).Select(x => x.ID).ToArray();
      foreach (var language in source.Languages)
      {
        var sourceVersion = source.Versions.GetLatestVersion(language);
        var jsonVersions = item.Fields.Versioned[language];
        foreach (var version in sourceVersion.Versions.GetVersions())
        {
          var json = new JsonFieldsCollection();
          foreach (var fieldId in versionedIds)
          {
            if (JsonDataProvider.IgnoreFields.Keys.Contains(fieldId))
            {
              continue;
            }

            var field = version.Fields[fieldId];
            var value = field.GetValue(false, false, false, false);
            if (value == null)
            {
              continue;
            }

            json[fieldId] = value;
          }

          jsonVersions.Add(version.Version.Number, json);
        }
      }

      return item;
    }