/// <summary>
        /// Adds an entity to the queue list. This provides circular reference checking as
        /// well as ensuring that proper order is maintained for all entities.
        /// </summary>
        /// <param name="entity">The entity that is to be included in the export.</param>
        /// <param name="path">The entity path that lead to this entity being encoded.</param>
        /// <param name="entityIsCritical">True if the entity is critical, that is referenced directly.</param>
        /// <param name="exporter">The exporter that will handle processing for this entity.</param>
        protected void EnqueueEntity(IEntity entity, EntityPath path, bool entityIsCritical, IExporter exporter)
        {
            //
            // These are system generated rows, we should never try to backup or restore them.
            //
            if (entity.TypeName == "Rock.Model.EntityType" || entity.TypeName == "Rock.Model.FieldType")
            {
                return;
            }

            //
            // If the entity is already in our path that means we are beginning a circular
            // reference so we can just ignore this one.
            //
            if (path.Where(e => e.Entity.Guid == entity.Guid).Any())
            {
                return;
            }

            //
            // Find the entities that this entity references, in other words entities that must
            // exist before this one can be created, and queue them up.
            //
            var referencedEntities = FindReferencedEntities(entity, path, exporter);

            foreach (var r in referencedEntities)
            {
                if (r.Value != null)
                {
                    var refPath = path + new EntityPathComponent(entity, r.Key);
                    EnqueueEntity(r.Value, refPath, true, exporter);
                }
            }

            //
            // If we already know about the entity, add a reference to it and return.
            //
            var queuedEntity = Entities.Where(e => e.Entity.Guid == entity.Guid).FirstOrDefault();

            if (queuedEntity == null)
            {
                queuedEntity = new QueuedEntity(entity, path.Clone());
                Entities.Add(queuedEntity);
            }
            else
            {
                //
                // We have already visited this entity from the same parent. Not sure why we are here.
                //
                if (path.Any() && queuedEntity.ReferencePaths.Where(r => r.Any() && r.Last().Entity.Guid == path.Last().Entity.Guid).Any())
                {
                    return;
                }

                queuedEntity.AddReferencePath(path.Clone());
            }

            //
            // Add any new referenced properties/entities that may have been supplied for this
            // entity, as it's possible that has changed based on the path we took to get here.
            //
            foreach (var r in referencedEntities)
            {
                if (!queuedEntity.ReferencedEntities.Any(e => e.Key == r.Key && e.Value == r.Value))
                {
                    queuedEntity.ReferencedEntities.Add(new KeyValuePair <string, IEntity>(r.Key, r.Value));
                }
            }

            //
            // Mark the entity as critical if it's a root entity or is otherwise specified as critical.
            //
            if (path.Count == 0 || entityIsCritical || exporter.IsPathCritical(path))
            {
                queuedEntity.IsCritical = true;
            }

            //
            // Mark the entity as requiring a new Guid value if so indicated.
            //
            if (exporter.DoesPathNeedNewGuid(path))
            {
                queuedEntity.RequiresNewGuid = true;
            }

            //
            // Find the entities that this entity has as children. This is usually the many side
            // of a one-to-many reference (such as a Workflow has many WorkflowActions, this would
            // get a list of the WorkflowActions).
            //
            var children = FindChildEntities(entity, path, exporter);

            children.ForEach(e => EnqueueEntity(e.Value, path + new EntityPathComponent(entity, e.Key), false, exporter));

            //
            // Allow the exporter a chance to add custom reference values.
            //
            var userReferences = exporter.GetUserReferencesForPath(entity, path);

            if (userReferences != null && userReferences.Any())
            {
                foreach (var r in userReferences)
                {
                    queuedEntity.UserReferences.AddOrReplace(r.Property, r);
                }
            }
        }
        /// <summary>
        /// Export the given entity into an EncodedEntity object. This can be used later to
        /// reconstruct the entity.
        /// </summary>
        /// <param name="entity">The entity to be exported.</param>
        /// <returns>The exported data that can be imported.</returns>
        protected EncodedEntity Export(QueuedEntity queuedEntity)
        {
            EncodedEntity encodedEntity = new EncodedEntity();
            Type          entityType    = GetEntityType(queuedEntity.Entity);

            encodedEntity.Guid       = queuedEntity.Entity.Guid;
            encodedEntity.EntityType = entityType.FullName;

            //
            // Generate the standard properties and references.
            //
            foreach (var property in GetEntityProperties(queuedEntity.Entity))
            {
                //
                // Don't encode IEntity properties, we should have the Id encoded instead.
                //
                if (typeof(IEntity).IsAssignableFrom(property.PropertyType))
                {
                    continue;
                }

                //
                // Don't encode IEnumerable properties. Those should be included as
                // their own entities to be encoded later.
                //
                if (property.PropertyType.GetInterface("IEnumerable") != null &&
                    property.PropertyType.GetGenericArguments().Length == 1 &&
                    typeof(IEntity).IsAssignableFrom(property.PropertyType.GetGenericArguments()[0]))
                {
                    continue;
                }

                encodedEntity.Properties.Add(property.Name, property.GetValue(queuedEntity.Entity));
            }

            //
            // Run any post-process transforms.
            //
            foreach (var processor in FindEntityProcessors(entityType))
            {
                var data = processor.ProcessExportedEntity(queuedEntity.Entity, encodedEntity, this);

                if (data != null)
                {
                    encodedEntity.AddTransformData(processor.Identifier.ToString(), data);
                }
            }

            //
            // Generate the references to other entities.
            //
            foreach (var x in queuedEntity.ReferencedEntities)
            {
                encodedEntity.MakePropertyIntoReference(x.Key, x.Value);
            }

            //
            // Add in the user references.
            //
            encodedEntity.References.AddRange(queuedEntity.UserReferences.Values);

            return(encodedEntity);
        }