/// <exclude />
        public static DataTypeDescriptor Build(Type type)
        {
            Verify.ArgumentNotNull(type, "type");
            Verify.ArgumentCondition(typeof(IData).IsAssignableFrom(type), "type", "{0} does not implement {1}".FormatWith(type.FullName, typeof(IData).FullName));

            Guid dataTypeId = DynamicTypeReflectionFacade.GetImmutableTypeId(type);

            bool isCodeGenerated = type.GetCustomInterfaceAttributes<CodeGeneratedAttribute>().Any();

            var typeDescriptor = new DataTypeDescriptor(dataTypeId, type.Namespace, type.Name, TypeManager.SerializeType(type), isCodeGenerated)
            {
                Title = DynamicTypeReflectionFacade.GetTitle(type),
                LabelFieldName = DynamicTypeReflectionFacade.GetLabelPropertyName(type),
                InternalUrlPrefix = DynamicTypeReflectionFacade.GetInternalUrlPrefix(type),
                DataAssociations = DynamicTypeReflectionFacade.GetDataTypeAssociationDescriptors(type)
            };
            
            List<Type> superInterfaces = type.GetInterfacesRecursively(t => typeof(IData).IsAssignableFrom(t) && t != typeof(IData));
            typeDescriptor.SetSuperInterfaces(superInterfaces);
            
            Type buildNewHandlerType = DynamicTypeReflectionFacade.GetBuildNewHandlerType(type);
            if (buildNewHandlerType != null) typeDescriptor.BuildNewHandlerTypeName = TypeManager.SerializeType(buildNewHandlerType);


            foreach (PropertyInfo propertyInfo in type.GetProperties())
            {
                DataFieldDescriptor fieldDescriptor = BuildFieldDescriptor(propertyInfo, false);

                typeDescriptor.Fields.Add(fieldDescriptor);
            }

            foreach (Type superInterfaceType in superInterfaces)
            {
                foreach (PropertyInfo propertyInfo in superInterfaceType.GetProperties())
                {
                    if (propertyInfo.Name == nameof(IPageData.PageId) && propertyInfo.DeclaringType == typeof(IPageData))
                    {
                        continue;
                    }

                    DataFieldDescriptor fieldDescriptor = BuildFieldDescriptor(propertyInfo, true);

                    typeDescriptor.Fields.Add(fieldDescriptor);
                }
            }

            ValidateAndAddKeyProperties(typeDescriptor.KeyPropertyNames, typeDescriptor.VersionKeyPropertyNames, type);

            string[] storeSortOrder = DynamicTypeReflectionFacade.GetSortOrder(type);
            if (storeSortOrder != null)
            {
                foreach (string name in storeSortOrder)
                {
                    typeDescriptor.StoreSortOrderFieldNames.Add(name);
                }
            }

            CheckSortOrder(typeDescriptor);

            foreach (var dataScopeIdentifier in DynamicTypeReflectionFacade.GetDataScopes(type))
            {
                if (!typeDescriptor.DataScopes.Contains(dataScopeIdentifier))
                {
                    typeDescriptor.DataScopes.Add(dataScopeIdentifier);
                }
            }

            foreach (string keyPropertyName in type.GetKeyPropertyNames())
            {
                if (typeDescriptor.Fields[keyPropertyName] == null)
                {
                    throw new InvalidOperationException(
                        $"The type '{type}' has a non existing key property specified by the attribute '{typeof (KeyPropertyNameAttribute)}'");
                }
            }

            var indexes = new List<DataTypeIndex>();
            foreach (var indexAttribute in type.GetCustomAttributesRecursively<IndexAttribute>())
            {
                foreach (var field in indexAttribute.Fields)
                {
                    if (typeDescriptor.Fields[field.Item1] == null)
                    {
                        throw new InvalidOperationException($"Index field '{field.Item1}' is not defined");
                    }
                }

                indexes.Add(new DataTypeIndex(indexAttribute.Fields) { Clustered = indexAttribute.Clustered });
            }

            indexes.Sort((a,b) => string.Compare(a.ToString(), b.ToString(), StringComparison.Ordinal));

            typeDescriptor.Indexes = indexes;

            return typeDescriptor;
        }
        /// <exclude />
        public static DataTypeDescriptor Build(Type type)
        {
            Verify.ArgumentNotNull(type, "type");
            Verify.ArgumentCondition(typeof(IData).IsAssignableFrom(type), "type", "{0} does not implement {1}".FormatWith(type.FullName, typeof(IData).FullName));

            Guid dataTypeId = DynamicTypeReflectionFacade.GetImmutableTypeId(type);

            bool isCodeGenerated = type.GetCustomInterfaceAttributes <CodeGeneratedAttribute>().Any();

            var typeDescriptor = new DataTypeDescriptor(dataTypeId, type.Namespace, type.Name, TypeManager.SerializeType(type), isCodeGenerated)
            {
                Title             = DynamicTypeReflectionFacade.GetTitle(type),
                LabelFieldName    = DynamicTypeReflectionFacade.GetLabelPropertyName(type),
                InternalUrlPrefix = DynamicTypeReflectionFacade.GetInternalUrlPrefix(type),
                DataAssociations  = DynamicTypeReflectionFacade.GetDataTypeAssociationDescriptors(type)
            };

            List <Type> superInterfaces = type.GetInterfacesRecursively(t => typeof(IData).IsAssignableFrom(t) && t != typeof(IData));

            typeDescriptor.SetSuperInterfaces(superInterfaces);

            Type buildNewHandlerType = DynamicTypeReflectionFacade.GetBuildNewHandlerType(type);

            if (buildNewHandlerType != null)
            {
                typeDescriptor.BuildNewHandlerTypeName = TypeManager.SerializeType(buildNewHandlerType);
            }


            foreach (PropertyInfo propertyInfo in type.GetProperties())
            {
                DataFieldDescriptor fieldDescriptor = BuildFieldDescriptor(propertyInfo, false);

                typeDescriptor.Fields.Add(fieldDescriptor);
            }

            foreach (Type superInterfaceType in superInterfaces)
            {
                foreach (PropertyInfo propertyInfo in superInterfaceType.GetProperties())
                {
                    if (propertyInfo.Name == "PageId" && propertyInfo.DeclaringType == typeof(IPageData))
                    {
                        continue;
                    }

                    DataFieldDescriptor fieldDescriptor = BuildFieldDescriptor(propertyInfo, true);

                    typeDescriptor.Fields.Add(fieldDescriptor);
                }
            }

            ValidateAndAddKeyProperties(typeDescriptor.KeyPropertyNames, type, superInterfaces);

            string[] storeSortOrder = DynamicTypeReflectionFacade.GetSortOrder(type);
            if (storeSortOrder != null)
            {
                foreach (string name in storeSortOrder)
                {
                    typeDescriptor.StoreSortOrderFieldNames.Add(name);
                }
            }

            CheckSortOrder(typeDescriptor);

            foreach (DataScopeIdentifier dataScopeIdentifier in DynamicTypeReflectionFacade.GetDataScopes(type))
            {
                if (!typeDescriptor.DataScopes.Contains(dataScopeIdentifier))
                {
                    typeDescriptor.DataScopes.Add(dataScopeIdentifier);
                }
            }

            foreach (string keyPropertyName in type.GetKeyPropertyNames())
            {
                if (typeDescriptor.Fields[keyPropertyName] == null)
                {
                    throw new InvalidOperationException(string.Format("The type '{0}' has a non existing key property specified by the attribute '{1}'", type, typeof(KeyPropertyNameAttribute)));
                }
            }

            var indexes = new List <DataTypeIndex>();

            foreach (var indexAttribute in type.GetCustomAttributesRecursively <IndexAttribute>())
            {
                foreach (var field in indexAttribute.Fields)
                {
                    if (typeDescriptor.Fields[field.Item1] == null)
                    {
                        throw new InvalidOperationException(string.Format("Index field '{0}' is not defined", field.Item1));
                    }
                }

                indexes.Add(new DataTypeIndex(indexAttribute.Fields)
                {
                    Clustered = indexAttribute.Clustered
                });
            }

            indexes.Sort((a, b) => string.Compare(a.ToString(), b.ToString(), StringComparison.Ordinal));

            typeDescriptor.Indexes = indexes;

            return(typeDescriptor);
        }