private IEnumerable<EntityInstanceVm> Level1(Entity matchEntity, EntityInstance matchEntityInstance, int skip, int limit)
        {

            var entityMatchNode = matchEntity.MatchNode("entity");
            var entityInstanceMatchNode = matchEntityInstance == null ? new EntityInstance().NodeNameWithAlias("entityInstance") : matchEntityInstance.MatchNode("entityInstance");

            var query = StagedDbContext.Instance.GraphClient.Cypher
                .Match(string.Format("{0}<-[:INSTANCE_OF]-{1}", entityMatchNode, entityInstanceMatchNode))
                .With("entityInstance, entity, count(entityInstance) AS totalCount")
                .Skip(skip)
                .Limit(limit)
                .Match("(property:Property)<-[:HAS_PROPERTY]-(entity)")
                .With("entityInstance, entity, property, totalCount")
                .OptionalMatch("(property)-[:FOR_ENTITY]->(entityPropertyEntity:Entity)")
                .OptionalMatch("(entityInstance)-[:HAS_PROPERTY_VALUE]->(dataPropertyPropertyValue:PropertyValue)-[:IS_VALUE_FOR_PROPERTY]->(property)")
                .OptionalMatch("(entityInstance)-[:HAS_PROPERTY_VALUE]->(entityPropertyEntityInstance:EntityInstance)-[:IS_VALUE_FOR_PROPERTY]->(property)-[:FOR_ENTITY]->(entityPropertyEntity)")
                .Return((entity, entityInstance, property, entityPropertyEntity, dataPropertyPropertyValue, entityPropertyEntityInstance, totalCount) => new
                {

                    //for each entity asset
                    entity = (entity.As<Entity>()),
                    entityInstance = entityInstance.As<EntityInstance>(),

                    //for each property asset type
                    entityPropertyEntityInstance = entityPropertyEntityInstance.As<EntityInstance>(),
                    entityPropertyEntity = entityPropertyEntity.As<Entity>(),
                    dataPropertyPropertyValue = dataPropertyPropertyValue.As<PropertyValue>(),
                    property = property.As<Property>(),
                    totalCount = totalCount.As<int>()
                });



            var results = query.Results
                .GroupBy(x =>
                    new
                    {
                        entityInstanceGuid = x.entityInstance.guid,
                        entityName = x.entity.name,
                        entityGuid = x.entity.guid,
                    }
                )
                .Select(y => new
                    //asset
                    EntityInstanceVm
                {
                    guid = y.Key.entityInstanceGuid,
                    entity = new PartialEntityVm { name = y.Key.entityName, guid = y.Key.entityGuid },
                    dataProperties = y.GroupBy(az => new { 
                        propertyValue = az.dataPropertyPropertyValue,
                        dataProperty = az.property
                    })
                    .Where(ww => ww.Key.dataProperty.dataType != DataTypeEnum.EntityInstance)
                    .Select(bz => new DataPropertyInstanceVm { 
                        guid = bz.Key.dataProperty.guid,
                        name = bz.Key.dataProperty.name,
                        value = bz.Key.propertyValue == null ? null : bz.Key.propertyValue.value 
                    }),
                    entityProperties = y
                    .GroupBy(z =>
                        new
                        {
                            entityProperty = z.property,
                            entityInstance = z.entityPropertyEntityInstance,
                            entityInstanceEntity = z.entityPropertyEntity,

                        }
                    )
                    .Where(www => www.Key.entityProperty.dataType == DataTypeEnum.EntityInstance)
                    .Select(entityInstanceProperties =>
                        new EntityPropertyInstanceVm
                        {
                            guid = entityInstanceProperties.Key.entityProperty.guid,
                            name = entityInstanceProperties.Key.entityProperty.name,
                            //asset type
                            entity = new PartialEntityVm { guid = entityInstanceProperties.Key.entityInstanceEntity.guid, name = entityInstanceProperties.Key.entityInstanceEntity.name },
                            entityInstanceGuid = entityInstanceProperties.Key.entityInstance == null ? null : entityInstanceProperties.Key.entityInstance.guid
                           
                        }
                    )

                });

            return results;
        }
        private IEnumerable<EntityInstanceVm> Level3(Entity matchEntity, EntityInstance matchEntityInstance, int skip, int limit)
        {

            var entityMatchNode = matchEntity.MatchNode("entity");
            var entityInstanceMatchNode = matchEntityInstance == null ? new EntityInstance().NodeNameWithAlias("entityInstance") : matchEntityInstance.MatchNode("entityInstance");

            var query = StagedDbContext.Instance.GraphClient.Cypher
                .Match(string.Format("{0}<-[:INSTANCE_OF]-{1}", entityMatchNode, entityInstanceMatchNode))
                .With("entityInstance, entity, count(entityInstance) AS totalCount")
                .Skip(skip)
                .Limit(limit)
                .Match("(property:Property)<-[:HAS_PROPERTY]-(entity)")
                .With("entityInstance, entity, property, totalCount")

                .OptionalMatch("(property)-[:FOR_ENTITY]->(entityPropertyEntity:Entity)")
                .OptionalMatch("(entityInstance)-[:HAS_PROPERTY_VALUE]->(dataPropertyPropertyValue:PropertyValue)-[:IS_VALUE_FOR_PROPERTY]->(property)")
                .OptionalMatch("(entityInstance)-[:HAS_PROPERTY_VALUE]->(entityPropertyEntityInstance:EntityInstance)-[:IS_VALUE_FOR_PROPERTY]->(property)-[:FOR_ENTITY]->(entityPropertyEntity)")

                .OptionalMatch("(property2:Property)<-[:HAS_PROPERTY]-(entityPropertyEntity)<-[:INSTANCE_OF]-(entityPropertyEntityInstance)")

                .OptionalMatch("(property2)-[:FOR_ENTITY]->(entityPropertyEntity2:Entity)")
                .OptionalMatch("(entityPropertyEntityInstance)-[:HAS_PROPERTY_VALUE]->(dataPropertyPropertyValue2:PropertyValue)-[:IS_VALUE_FOR_PROPERTY]->(property2)")
                .OptionalMatch("(entityPropertyEntityInstance)-[:HAS_PROPERTY_VALUE]->(entityPropertyEntityInstance2:EntityInstance)-[:IS_VALUE_FOR_PROPERTY]->(property2)-[:FOR_ENTITY]->(entityPropertyEntity2)")

                .OptionalMatch("(property3:Property)<-[:HAS_PROPERTY]-(entityPropertyEntity2)<-[:INSTANCE_OF]-(entityPropertyEntityInstance2)")

                .OptionalMatch("(property3)-[:FOR_ENTITY]->(entityPropertyEntity3:Entity)")
                .OptionalMatch("(entityPropertyEntityInstance2)-[:HAS_PROPERTY_VALUE]->(dataPropertyPropertyValue3:PropertyValue)-[:IS_VALUE_FOR_PROPERTY]->(property3)")
                .OptionalMatch("(entityPropertyEntityInstance2)-[:HAS_PROPERTY_VALUE]->(entityPropertyEntityInstance3:EntityInstance)-[:IS_VALUE_FOR_PROPERTY]->(property3)-[:FOR_ENTITY]->(entityPropertyEntity3)")


                .Return((entity, entityInstance, 
                property, dataPropertyPropertyValue, entityPropertyEntityInstance, entityPropertyEntity,
                property2, dataPropertyPropertyValue2, entityPropertyEntityInstance2, entityPropertyEntity2,
                property3, dataPropertyPropertyValue3, entityPropertyEntityInstance3, entityPropertyEntity3) => new
                {

                    //first
                    entity = (entity.As<Entity>()),
                    entityInstance = entityInstance.As<EntityInstance>(),
                    entityPropertyEntityInstance = entityPropertyEntityInstance.As<EntityInstance>(),
                    dataPropertyPropertyValue = dataPropertyPropertyValue.As<PropertyValue>(),
                    property = property.As<Property>(),

                    entityPropertyEntity = entityPropertyEntity.As<Entity>(),

                    property2 = property2.As<Property>(),
                    dataPropertyPropertyValue2 = dataPropertyPropertyValue2.As<PropertyValue>(),
                    entityPropertyEntityInstance2 = entityPropertyEntityInstance2.As<EntityInstance>(),

                    entityPropertyEntity2 = entityPropertyEntity2.As<Entity>(),

                    property3 = property3.As<Property>(),
                    dataPropertyPropertyValue3 = dataPropertyPropertyValue3.As<PropertyValue>(),
                    entityPropertyEntityInstance3 = entityPropertyEntityInstance3.As<EntityInstance>(),

                    entityPropertyEntity3 = entityPropertyEntity3.As<Entity>(),
                });



            var results = query.Results
                .GroupBy(x =>
                    new
                    {
                        entityInstanceGuid = x.entityInstance.guid,
                        entityName = x.entity.name,
                        entityGuid = x.entity.guid,
                    }
                )
                .Select(y => new
                    //asset
                    EntityInstanceVm
                {
                    guid = y.Key.entityInstanceGuid,
                    entity = new PartialEntityVm { name = y.Key.entityName, guid = y.Key.entityGuid },
                    dataProperties = y.Where(ww => ww.property.dataType != DataTypeEnum.EntityInstance)
                    .GroupBy(az => new
                    {
                        propertyGuid = az.property.guid,
                        propertyName = az.property.name,
                    })
                    .Select(bz => new DataPropertyInstanceVm
                    {
                        guid = bz.Key.propertyGuid,
                        name = bz.Key.propertyName,
                        value = bz.First().dataPropertyPropertyValue == null ? null : bz.First().dataPropertyPropertyValue.value
                    }),
                    entityProperties = y.Where(www => www.property.dataType == DataTypeEnum.EntityInstance)
                    .GroupBy(z =>
                        new
                        {
                            propertyGuid = z.property.guid,
                            propertyName = z.property.name,
                            entityPropertyEntityName = z.entityPropertyEntity.name,
                            entityPropertyEntityGuid = z.entityPropertyEntity.guid,
                        }
                    )
                    .Select(entityInstanceProperties =>
                        new EntityPropertyInstanceVm
                        {
                            guid = entityInstanceProperties.Key.propertyGuid,
                            name = entityInstanceProperties.Key.propertyName,
                            //asset type
                            entity = new PartialEntityVm { guid = entityInstanceProperties.Key.entityPropertyEntityGuid, name = entityInstanceProperties.Key.entityPropertyEntityName },
                            entityInstanceGuid = entityInstanceProperties.First().entityPropertyEntityInstance == null ? null : entityInstanceProperties.First().entityPropertyEntityInstance.guid,
                            entityInstance = entityInstanceProperties.First().entityPropertyEntityInstance == null ? null : new EntityInstanceVm
                            {
                                guid = entityInstanceProperties.First().entityPropertyEntityInstance == null ? null : entityInstanceProperties.First().entityPropertyEntityInstance.guid,
                                entity = new PartialEntityVm { guid = entityInstanceProperties.Key.entityPropertyEntityGuid, name = entityInstanceProperties.Key.entityPropertyEntityName },
                                dataProperties = entityInstanceProperties.Where(ww => ww.property2 != null && ww.property2.dataType != DataTypeEnum.EntityInstance)
                                .GroupBy(az => new
                                {
                                    propertyGuid = az.property2.guid,
                                    propertyName = az.property2.name,
                                })
                                .Select(oz => new DataPropertyInstanceVm
                                {
                                    guid = oz.Key.propertyGuid,
                                    name = oz.Key.propertyName,
                                    value = oz.First().dataPropertyPropertyValue2 == null ? null : oz.First().dataPropertyPropertyValue2.value
                                }),
                                entityProperties = entityInstanceProperties.Where(ww => ww.property2 != null && ww.property2.dataType == DataTypeEnum.EntityInstance)
                                .GroupBy(pz => new
                                {
                                    propertyGuid = pz.property2.guid,
                                    propertyName = pz.property2.name,
                                    entityPropertyEntityName = pz.entityPropertyEntity2.name,
                                    entityPropertyEntityGuid = pz.entityPropertyEntity2.guid,
                                })
                                .Select(entityInstanceProperties2 => new EntityPropertyInstanceVm
                                {
                                    guid = entityInstanceProperties2.Key.propertyGuid,
                                    name = entityInstanceProperties2.Key.propertyName,
                                    entity = new PartialEntityVm { guid = entityInstanceProperties2.Key.entityPropertyEntityGuid, name = entityInstanceProperties2.Key.entityPropertyEntityName },
                                    entityInstanceGuid = entityInstanceProperties2.First().entityPropertyEntityInstance2 == null ? null : entityInstanceProperties2.First().entityPropertyEntityInstance2.guid,
                                    entityInstance = entityInstanceProperties2.First().entityPropertyEntityInstance == null ? null : new EntityInstanceVm
                                    {
                                        guid = entityInstanceProperties2.First().entityPropertyEntityInstance == null ? null : entityInstanceProperties2.First().entityPropertyEntityInstance.guid,
                                        entity = new PartialEntityVm { guid = entityInstanceProperties2.Key.entityPropertyEntityGuid, name = entityInstanceProperties2.Key.entityPropertyEntityName },
                                        dataProperties = entityInstanceProperties2.Where(ww => ww.property3 != null && ww.property3.dataType != DataTypeEnum.EntityInstance)
                                        .GroupBy(az => new
                                        {
                                            propertyGuid = az.property3.guid,
                                            propertyName = az.property3.name,
                                        })
                                        .Select(oz => new DataPropertyInstanceVm
                                        {
                                            guid = oz.Key.propertyGuid,
                                            name = oz.Key.propertyName,
                                            value = oz.First().dataPropertyPropertyValue3 == null ? null : oz.First().dataPropertyPropertyValue3.value
                                        }),
                                        entityProperties = entityInstanceProperties2.Where(ww => ww.property3 != null && ww.property3.dataType == DataTypeEnum.EntityInstance)
                                        .GroupBy(pz => new
                                        {
                                            propertyGuid = pz.property3.guid,
                                            propertyName = pz.property3.name,
                                            entityPropertyEntityName = pz.entityPropertyEntity3.name,
                                            entityPropertyEntityGuid = pz.entityPropertyEntity3.guid,
                                        })
                                        .Select(pp => new EntityPropertyInstanceVm
                                        {
                                            guid = pp.Key.propertyGuid,
                                            name = pp.Key.propertyName,
                                            entity = new PartialEntityVm { guid = pp.Key.entityPropertyEntityGuid, name = pp.Key.entityPropertyEntityName },
                                            entityInstanceGuid = pp.First().entityPropertyEntityInstance3 == null ? null : pp.First().entityPropertyEntityInstance3.guid,
                                        }),

                                    }
                                }),

                            }
                        }
                    )

                }).ToList();

            var all = results.SelectMany(m => m.entityProperties, (parent, child) => child.entityInstance)
                .Union(results.Select(p => new EntityInstanceVm
                {
                    guid = p.guid,
                    entity = p.entity,
                    entityProperties = p.entityProperties,
                    dataProperties = p.dataProperties

                }))
                .Where(g => g != null)
                .GroupBy(by => by.guid)
                .Select(group => group.First())
                .Union(
                    results.SelectMany(m => m.entityProperties, (parent, child) => child.entityInstance)
                    .Where(g => g != null)
                    .SelectMany(m => m.entityProperties, (parent, child) => child.entityInstance)
                    .GroupBy(by => by.guid)
                    .Select(group => group.First())
                )
                ;

            return all;
        }
        public IEnumerable<dynamic> GetByFilter([FromUri] EntityDetailsScreenFilter filter)
        {



            var screenEntity = new Entity { guid = filter.entity };
            var screenInstance = new Screen { guid = filter.screen };
            var application = new Application() { guid = ConfigurationManager.AppSettings["application_guid"] };

            var match = string.Format("{0}, {1}",
                  string.Format("{0}", screenEntity.MatchNode("entity")),
                  string.Format("{0}-[hasScreen:HAS_SCREEN]->{1}-[:HAS_TEMPLATE]->(template:Template)-[hasWidget:HAS_WIDGET*]->(widget:Widget)",
                  application.MatchNode(),
                  screenInstance.MatchNode("screen")));

            var optionalMatch = "(widget)-[:DISPLAYS_VALUE_FOR]->(property:Property)";
            var optionalMatch1 = "(widget)<-[:HAS_WIDGET]-(parentWidget:Widget)";
            var optionalMatch4 = "(widget)-[:HAS_ACTION]->(action:WidgetActionCommand)-[:RELATED_ACTION_SCREEN]->(relatedScreen:Screen)";

            var matchEntityProperties = "(property)<-[:HAS_PROPERTY]-(entity)";
            var matchSupportingEntityProperties = "(entity)<-[:FOR_ENTITY]-(property)<-[:HAS_PROPERTY]-(supportingEntity:Entity)";
            var matchEntityPropertiesAudits = "(widget)-[:FOR_THIS_HEADER_PROPERTY]->(headEntityProperty:Property)<-[:HAS_PROPERTY]-(entity)";
            var matchDataPropertiesOfEntityProperties = 
                "(headEntityProperty)-[:FOR_ENTITY]->                                                                                                  (entityPropertyEntity:Entity)-[:HAS_PROPERTY]->(property)<-[:DISPLAYS_VALUE_FOR]-(widget)-[:FOR_THIS_HEADER_PROPERTY]->(headEntityProperty)<-[:HAS_PROPERTY]-(entity)";
            var matchDataPropertiesOfEntityPropertiesOfTheEntitiesWhichAreEntityProperties = 
                "(headEntityProperty)-[:FOR_ENTITY]->(headEntityPropertyEntity:Entity)-[:HAS_PROPERTY]->(subEntityProperty:Property)-[:FOR_ENTITY]->(subEntityPropertyEntity:Entity)-[:HAS_PROPERTY]->(property)<-[:DISPLAYS_VALUE_FOR]-(widget)-[:FOR_THIS_HEADER_PROPERTY]->(headEntityProperty)<-[:HAS_PROPERTY]-(entity)";


            var query = StagedDbContext.Instance.GraphClient.Cypher
                .Match(match)
                .OptionalMatch(optionalMatch)
                .OptionalMatch(optionalMatch1)
                .OptionalMatch(optionalMatch4)
                .OptionalMatch(matchEntityProperties)
                .OptionalMatch(matchSupportingEntityProperties)
                .OptionalMatch(matchEntityPropertiesAudits)
                .OptionalMatch(matchDataPropertiesOfEntityProperties)
                .OptionalMatch(matchDataPropertiesOfEntityPropertiesOfTheEntitiesWhichAreEntityProperties)
                .Return((screen, entity, template, container, hasScreen, property, headEntityProperty, widget, parentWidget, entityPropertyEntity, subEntityProperty, headEntityPropertyEntity, supportingEntity, action, relatedScreen) => new
                {
                    screen = (screen.As<Screen>()),
                    entity = (entity.As<Entity>()),
                    supportingEntity = (supportingEntity.As<Entity>()),
                    template = (template.As<Template>()),

                    hasScreen = (hasScreen.As<HasScreen>()),

                    widget = (widget.As<Widget>()),
                    parentWidget = (parentWidget.As<Widget>()),
                    property = (property.As<Property>()),
                    headEntityProperty = (headEntityProperty.As<Property>()),
                    subEntityProperty = (subEntityProperty.As<Property>()),
                    entityPropertyEntity = entityPropertyEntity.As<Entity>(),
                    headEntityPropertyEntity = headEntityPropertyEntity.As<Entity>(),
                    action = action.As<WidgetActionCommand>(),
                    relatedScreen = (relatedScreen.As<Screen>()),
                });


            var returned = query.Results.GroupBy(x =>
                new
                {
                    screenGuid = x.screen.guid,
                    screenName = x.screen.name,
                    screenType = x.hasScreen.screenType,
                    templateGuid = x.template.guid,
                    templateName = x.template.name,
                    templateLocation = x.template.location,
                }
                )
                .Select(e =>
                new ScreenVm
                {
                    guid = e.Key.screenGuid,
                    name = e.Key.screenName,
                    screenType = e.Key.screenType,
                    template = new EntityDetailsTemplateInstanceVm
                    {
                        name = e.Key.templateName,
                        location = e.Key.templateLocation,
                        guid = e.Key.templateGuid,
                        widgets = e.GroupBy(gw => new
                        {
        
                            widgetGuid = gw.widget.guid,
                            widgetContainer = gw.widget.container,
                            widgetSchema = gw.widget.widgetSchema,
                            parentWidget = gw.parentWidget,
                            relatedScreen = gw.relatedScreen,
                            action = gw.action,
                            property = gw.property,
                            headEntityProperty = gw.headEntityProperty,
                            subEntityProperty = gw.subEntityProperty,
                            entity = gw.entity,
                            supportingEntity = gw.supportingEntity,
                            entityPropertyEntity = gw.entityPropertyEntity,
                            headEntityPropertyEntity = gw.headEntityPropertyEntity,        
                        })
                        .Select(w => new WidgetVm
                        {
                            guid = w.Key.widgetGuid,
                            container = w.Key.widgetContainer,
                            widgetSchema = w.Key.widgetSchema,
                            parentWidgetGuid = w.Key.parentWidget == null ? null : w.Key.parentWidget.guid,
                            action = w.Key.action == null ? null : new WidgetActionCommandVm
                            {
                                guid = w.Key.action.guid,
                                type = w.Key.action.type,
                                relatedScreen = w.Key.relatedScreen == null ? null : new RelatedScreenVm { guid = w.Key.relatedScreen.guid, name = w.Key.relatedScreen.name }
                            },
                            data = w.Key.property == null ? null : new WidgetDataChainCommandVm
                            {
                                type = "entity",
                                guid = w.Key.supportingEntity == null ? w.Key.entity.guid : w.Key.supportingEntity.guid,
                                next = w.Key.entityPropertyEntity == null && w.Key.headEntityPropertyEntity == null ? new WidgetDataChainCommandVm
                                {
                                    type = w.Key.property.dataType == DataTypeEnum.EntityInstance ? "entityProperty" : "dataProperty",
                                    guid = w.Key.property.guid
                                }
                                : w.Key.entityPropertyEntity != null && w.Key.headEntityPropertyEntity == null ? new WidgetDataChainCommandVm
                                {
                                    type = "entityProperty",
                                    guid = w.Key.headEntityProperty.guid,
                                    next = new WidgetDataChainCommandVm
                                    {
                                        type = "dataProperty",
                                        guid = w.Key.property.guid
                                    }
                                }
                                :
                                new WidgetDataChainCommandVm
                                {
                                    type = "entityProperty",
                                    guid = w.Key.headEntityProperty.guid,
                                    next = w.Key.subEntityProperty == null ? new WidgetDataChainCommandVm
                                    {
                                        type = "dataProperty",
                                        guid = w.Key.property.guid
                                    }
                                    : new WidgetDataChainCommandVm
                                    {
                                        type = "entityProperty",
                                        guid = w.Key.subEntityProperty.guid,
                                        next = new WidgetDataChainCommandVm
                                        {
                                            type = "dataProperty",
                                            guid = w.Key.property.guid
                                        }
                                        
                                    }
                                }
                            }
                        }).ToList()
  
                    }

                }

            ).ToList();

            //Aggregate container widgets 
            returned.ForEach(container => container.template.widgets = BuildWidgetTree(container.template.widgets));

            return returned;


        }