private static IAppBuilder CacheScreens(this IAppBuilder app)
        {
            var application = new Application() {guid = ConfigurationManager.AppSettings["application_guid"]};
            var match = string.Format("{0}-[hasScreen:HAS_SCREEN]->(screen: Screen)-[:HAS_TEMPLATE]->(template:Template)-[:HAS_WIDGET*]->(widget:Widget)", application.MatchNode());
            var optionalmatch = "(property:Property)<-[:DISPLAYS_VALUE_FOR]-(widget)";
            var optionalmatch2 = "(widget)-[:FOR_THIS_HEADER_PROPERTY]->(headEntityProperty:Property)<-[:HAS_PROPERTY]-(entity: Entity)";
            var optionalmatch3 = "(headEntityProperty)-[:FOR_ENTITY]->                                                      (level2Entity:Entity)-[:HAS_PROPERTY]->(property)<-[:DISPLAYS_VALUE_FOR]-(widget)-[:FOR_THIS_HEADER_PROPERTY]->(headEntityProperty)<-[:HAS_PROPERTY]-(entity)";
            var optionalmatch4 = "(headEntityProperty)-[:FOR_ENTITY]->(level3Entity:Entity)-[:HAS_PROPERTY]->(:Property)-[:FOR_ENTITY]->(: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(optionalmatch2)
                .OptionalMatch(optionalmatch3)
                .OptionalMatch(optionalmatch4)

                .Return((screen, entity, template, hasScreen, widget, level2Entity, level3Entity) => new
                {
                    screen = (screen.As<Screen>()),
                    entity = (entity.As<Entity>()),

                    template = (template.As<Template>()),
                    hasScreen = (hasScreen.As<HasScreen>()),
                    widget = (widget.As<Widget>()),
                    level2Entity = (level2Entity.As<Entity>()),
                    level3Entity = (level3Entity.As<Entity>())

                });


            var returned = query.Results.GroupBy(x =>
                new
                {
                    screenGuid = x.screen.guid,
                    screenName = x.screen.name,
                    screenType = x.hasScreen.screenType,
                }
                )
                .Select(e =>
                new ScreenMeta
                {
                    guid = e.Key.screenGuid,
                    name = e.Key.screenName,
                    screenType = e.Key.screenType,
                    entityExpandLevel = e.Any(x => x.level3Entity != null) ? 3 : e.Any(x => x.level2Entity != null) ? 2 : 1
                }

            ).ToList();

           
            MetadataCache.Instance.Screens.AddRange(returned);
            return app;
        }
        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;


        }