private void HandleSimpleTypes(JsonProperty property, ContractPropertyInfo propertyInfo)
        {
            var typeInfo = property.PropertyType.GetTypeInfo();

            propertyInfo.IsSimpleType = true;

            // it's a case of: nullable / enum type property
            if (typeInfo.GenericTypeArguments != null && typeInfo.GenericTypeArguments.Length > 0)
            {
                var propertyGenericArg = property.PropertyType.GenericTypeArguments.First();
                var underlyingType     = Nullable.GetUnderlyingType(propertyGenericArg);
                propertyGenericArg = underlyingType ?? propertyGenericArg;

                propertyInfo.FullName         = propertyGenericArg.FullName;
                propertyInfo.AssemblyFullName = propertyGenericArg.GetTypeInfo().Assembly.FullName;

                if (propertyGenericArg.GetTypeInfo().IsEnum)
                {
                    propertyInfo.IsEnum   = true;
                    propertyInfo.TypeName = propertyGenericArg.Name;
                }
                else
                {
                    if (propertyGenericArg == typeof(DateTimeOffset))
                    {
                        propertyInfo.TypeName = TypeCode.DateTime.ToString();
                    }
                    else
                    {
                        // TODO: Find better solution for this
                        propertyInfo.TypeName = typeof(Type)
                                                .GetRuntimeMethod("GetTypeCode", new[] { typeof(Type) })
                                                .Invoke(null, new object[] { propertyGenericArg })
                                                .ToString();
                    }
                }
            }
            else
            {
                if (property.PropertyType == typeof(DateTimeOffset))
                {
                    propertyInfo.TypeName = TypeCode.DateTime.ToString();
                }
                else
                {
                    propertyInfo.TypeName = typeof(Type)
                                            .GetRuntimeMethod("GetTypeCode", new[] { typeof(Type) })
                                            .Invoke(null, new object[] { property.PropertyType })
                                            .ToString();
                }

                propertyInfo.FullName         = property.PropertyType.FullName;
                propertyInfo.AssemblyFullName = typeInfo.Assembly.FullName;
            }
        }
        private FieldBase CreateDateTypeField(ContractPropertyInfo property)
        {
            var dateAttribute =
                property.PictureparkAttributes.OfType <PictureparkDateTypeAttribute>().FirstOrDefault();
            var format = dateAttribute?.Format;

            return(dateAttribute == null || dateAttribute.ContainsTimePortion
                ? (FieldBase) new FieldDateTime {
                Index = true, Format = format
            }
                : new FieldDate {
                Index = true, Format = format
            });
        }
        private FieldOverwriteBase GetFieldOverwrite(ContractPropertyInfo property)
        {
            var tagboxAttribute = property.PictureparkAttributes
                                  .OfType <PictureparkTagboxAttribute>()
                                  .SingleOrDefault();

            var listItemCreateTemplateAttribute = property.PictureparkAttributes
                                                  .OfType <PictureparkListItemCreateTemplateAttribute>()
                                                  .SingleOrDefault();

            if (property.IsArray)
            {
                if (property.IsReference)
                {
                    return(new FieldOverwriteMultiTagbox
                    {
                        Id = property.Name,
                        Filter = tagboxAttribute?.Filter,
                        Required = property.PictureparkAttributes.OfType <PictureparkRequiredAttribute>().Any(),
                        ListItemCreateTemplate = listItemCreateTemplateAttribute?.ListItemCreateTemplate,
                        OverwriteListItemCreateTemplate = !string.IsNullOrEmpty(listItemCreateTemplateAttribute?.ListItemCreateTemplate)
                    });
                }
                else
                {
                    throw new InvalidOperationException("Only Tagbox properties can be overriden.");
                }
            }
            else
            {
                if (property.IsReference)
                {
                    return(new FieldOverwriteSingleTagbox
                    {
                        Id = property.Name,
                        Filter = tagboxAttribute?.Filter,
                        Required = property.PictureparkAttributes.OfType <PictureparkRequiredAttribute>().Any(),
                        ListItemCreateTemplate = listItemCreateTemplateAttribute?.ListItemCreateTemplate,
                        OverwriteListItemCreateTemplate = !string.IsNullOrEmpty(listItemCreateTemplateAttribute?.ListItemCreateTemplate)
                    });
                }
                else
                {
                    throw new InvalidOperationException("Only Tagbox properties can be overriden.");
                }
            }
        }
        private FieldBase GetField(ContractPropertyInfo property)
        {
            FieldBase field = null;

            if (property.IsDictionary)
            {
                if (property.TypeName == "TranslatedStringDictionary")
                {
                    field = new FieldTranslatedString
                    {
                        Required     = false,
                        Fixed        = false,
                        Index        = true,
                        SimpleSearch = true,
                        MultiLine    = false,
                        Boost        = 1,
                        Analyzers    = new List <AnalyzerBase>
                        {
                            new LanguageAnalyzer
                            {
                                SimpleSearch = true
                            }
                        }
                    };
                }
                else if (property.IsArray)
                {
                    field = new FieldDictionaryArray();
                }
                else
                {
                    field = new FieldDictionary();
                }
            }
            else if (property.IsEnum)
            {
                Type enumType = Type.GetType($"{property.FullName}, {property.AssemblyFullName}");

                // TODO: Handle enums
            }
            else if (property.IsSimpleType)
            {
                if (!Enum.TryParse(property.TypeName, out TypeCode typeCode))
                {
                    throw new Exception($"Parsing to TypeCode enumarated object failed for string value: {property.TypeName}.");
                }

                if (property.IsArray)
                {
                    switch (typeCode)
                    {
                    case TypeCode.String:
                        field = new FieldStringArray
                        {
                            Index = true
                        };
                        break;

                    case TypeCode.DateTime:
                        field = new FieldDateTimeArray
                        {
                            Index = true
                        };
                        break;

                    case TypeCode.Int16:
                    case TypeCode.Int32:
                    case TypeCode.Int64:
                        field = new FieldLongArray
                        {
                            Index = true
                        };
                        break;

                    default:
                        throw new Exception($"TypeCode {typeCode} is not supported.");
                    }
                }
                else
                {
                    var stringInfos = property.PictureparkAttributes.OfType <PictureparkStringAttribute>().SingleOrDefault();

                    switch (typeCode)
                    {
                    case TypeCode.String:
                        field = new FieldString
                        {
                            Index        = true,
                            SimpleSearch = true,
                            Boost        = 1,
                            Analyzers    = new List <AnalyzerBase>
                            {
                                new SimpleAnalyzer
                                {
                                    SimpleSearch = true
                                }
                            },
                            MultiLine = stringInfos?.MultiLine ?? false
                        };
                        break;

                    case TypeCode.DateTime:
                        field = new FieldDateTime
                        {
                            Index = true
                        };
                        break;

                    case TypeCode.Boolean:
                        field = new FieldBoolean
                        {
                            Index = true
                        };
                        break;

                    case TypeCode.Int16:
                    case TypeCode.Int32:
                    case TypeCode.Int64:
                        field = new FieldLong
                        {
                            Index = true
                        };
                        break;

                    case TypeCode.Decimal:
                    case TypeCode.Double:
                    case TypeCode.Single:
                        field = new FieldDecimal
                        {
                            Index = true
                        };
                        break;

                    default:
                        throw new Exception($"TypeCode {typeCode} is not supported.");
                    }
                }
            }
            else
            {
                var schemaIndexingAttribute         = property.PictureparkAttributes.OfType <PictureparkSchemaIndexingAttribute>().SingleOrDefault();
                var listItemCreateTemplateAttribute = property.PictureparkAttributes.OfType <PictureparkListItemCreateTemplateAttribute>().SingleOrDefault();
                var maximumRecursionAttribute       = property.PictureparkAttributes.OfType <PictureparkMaximumRecursionAttribute>().SingleOrDefault();
                var tagboxAttributes          = property.PictureparkAttributes.OfType <PictureparkTagboxAttribute>().SingleOrDefault();
                var contentRelationAttributes = property.PictureparkAttributes.OfType <PictureparkContentRelationAttribute>().ToList();

                var relationTypes = new List <RelationType>();
                if (contentRelationAttributes.Any())
                {
                    relationTypes = contentRelationAttributes.Select(i => new RelationType
                    {
                        Id            = i.Name,
                        Filter        = i.Filter,
                        TargetDocType = i.TargetDocType,
                        Names         = new TranslatedStringDictionary {
                            { "x-default", i.Name }
                        }
                    }).ToList();
                }

                if (property.IsArray)
                {
                    if (contentRelationAttributes.Any())
                    {
                        field = new FieldMultiRelation
                        {
                            Index              = true,
                            RelationTypes      = relationTypes,
                            SchemaId           = property.TypeName,
                            SchemaIndexingInfo = schemaIndexingAttribute?.SchemaIndexingInfo
                        };
                    }
                    else if (property.IsReference)
                    {
                        field = new FieldMultiTagbox
                        {
                            Index                  = true,
                            SimpleSearch           = true,
                            SchemaId               = property.TypeName,
                            Filter                 = tagboxAttributes?.Filter,
                            SchemaIndexingInfo     = schemaIndexingAttribute?.SchemaIndexingInfo,
                            ListItemCreateTemplate = listItemCreateTemplateAttribute?.ListItemCreateTemplate
                        };
                    }
                    else
                    {
                        field = new FieldMultiFieldset
                        {
                            Index              = true,
                            SimpleSearch       = true,
                            SchemaId           = property.TypeName,
                            SchemaIndexingInfo = schemaIndexingAttribute?.SchemaIndexingInfo
                        };
                    }
                }
                else
                {
                    if (contentRelationAttributes.Any())
                    {
                        field = new FieldSingleRelation
                        {
                            Index              = true,
                            SimpleSearch       = true,
                            RelationTypes      = relationTypes,
                            SchemaId           = property.TypeName,
                            SchemaIndexingInfo = schemaIndexingAttribute?.SchemaIndexingInfo
                        };
                    }
                    else if (property.TypeName == "GeoPoint")
                    {
                        field = new FieldGeoPoint
                        {
                            Index = true
                        };
                    }
                    else if (property.IsReference)
                    {
                        field = new FieldSingleTagbox
                        {
                            Index                  = true,
                            SimpleSearch           = true,
                            SchemaId               = property.TypeName,
                            Filter                 = tagboxAttributes?.Filter,
                            SchemaIndexingInfo     = schemaIndexingAttribute?.SchemaIndexingInfo,
                            ListItemCreateTemplate = listItemCreateTemplateAttribute?.ListItemCreateTemplate
                        };
                    }
                    else
                    {
                        field = new FieldSingleFieldset
                        {
                            Index              = true,
                            SimpleSearch       = true,
                            SchemaId           = property.TypeName,
                            SchemaIndexingInfo = schemaIndexingAttribute?.SchemaIndexingInfo
                        };
                    }
                }
            }

            if (field == null)
            {
                throw new Exception($"Could not find type for {property.Name}");
            }

            foreach (var attribute in property.PictureparkAttributes)
            {
                if (attribute is PictureparkSearchAttribute searchAttribute)
                {
                    field.Index        = searchAttribute.Index;
                    field.SimpleSearch = searchAttribute.SimpleSearch;

                    if (field.GetType().GetRuntimeProperty("Boost") != null)
                    {
                        field.GetType().GetRuntimeProperty("Boost").SetValue(field, searchAttribute.Boost);
                    }
                }

                if (attribute is PictureparkRequiredAttribute)
                {
                    field.Required = true;
                }

                if (attribute is PictureparkMaximumLengthAttribute maxLengthAttribute)
                {
                    field.GetType().GetRuntimeProperty("MaximumLength").SetValue(field, maxLengthAttribute.Length);
                }

                if (attribute is PictureparkPatternAttribute patternAttribute)
                {
                    field.GetType().GetRuntimeProperty("Pattern").SetValue(field, patternAttribute.Pattern);
                }

                if (attribute is PictureparkNameTranslationAttribute nameTranslationAttribute)
                {
                    if (field.Names == null)
                    {
                        field.Names = new TranslatedStringDictionary();
                    }

                    field.Names[nameTranslationAttribute.LanguageAbbreviation] = nameTranslationAttribute.Translation;
                }
            }

            var fieldName = property.Name;

            field.Id = fieldName.ToLowerCamelCase();

            if (field.Names == null)
            {
                field.Names = new TranslatedStringDictionary
                {
                    ["x-default"] = fieldName
                };
            }

            var fieldAnalyzers = property.PictureparkAttributes
                                 .OfType <PictureparkAnalyzerAttribute>()
                                 .Select(a => a.CreateAnalyzer())
                                 .ToList();

            if (fieldAnalyzers.Any())
            {
                field.GetType().GetRuntimeProperty("Analyzers").SetValue(field, fieldAnalyzers);
            }

            return(field);
        }
        private List <ContractPropertyInfo> GetProperties(Type type)
        {
            var contactPropertiesInfo = new List <ContractPropertyInfo>();

            var objectContract = _contractResolver.ResolveContract(type) as JsonObjectContract;

            if (objectContract != null)
            {
                foreach (var property in objectContract.Properties.Where(p => p.DeclaringType == type))
                {
                    var typeInfo = property.PropertyType.GetTypeInfo();
                    var name     = property.PropertyName;

                    // Check if name is overridden by JsonProperty attribute
                    var attributes   = property.AttributeProvider.GetAttributes(false);
                    var jsonProperty = attributes.OfType <JsonPropertyAttribute>().FirstOrDefault();
                    if (jsonProperty != null)
                    {
                        name = jsonProperty.PropertyName;
                    }

                    // Skip ignored properties
                    if (_ignoredProperties.Contains(name))
                    {
                        continue;
                    }

                    var propertyInfo = new ContractPropertyInfo()
                    {
                        Name          = name,
                        IsOverwritten = type.GetTypeInfo().BaseType?.GetRuntimeProperty(property.UnderlyingName) != null
                    };

                    if (IsSimpleType(property.PropertyType))
                    {
                        HandleSimpleTypes(property, propertyInfo);
                    }
                    else
                    {
                        // either list or dictionary
                        if (typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(typeInfo))
                        {
                            if (typeInfo.ImplementedInterfaces.Contains(typeof(IDictionary)) ||
                                (typeInfo.GenericTypeArguments.Any() && typeInfo.GenericTypeArguments.First().GetTypeInfo().ImplementedInterfaces.Contains(typeof(IDictionary))))
                            {
                                propertyInfo.IsArray      = typeInfo.ImplementedInterfaces.Contains(typeof(IList));
                                propertyInfo.IsDictionary = true;
                                propertyInfo.TypeName     = property.PropertyType.Name;
                            }
                            else
                            {
                                var propertyGenericArg = typeInfo.GenericTypeArguments.First();

                                if (IsSimpleType(propertyGenericArg))
                                {
                                    HandleSimpleTypes(property, propertyInfo);
                                }
                                else
                                {
                                    propertyInfo.IsCustomType     = true;
                                    propertyInfo.TypeName         = propertyGenericArg.Name;
                                    propertyInfo.FullName         = propertyGenericArg.FullName;
                                    propertyInfo.AssemblyFullName = propertyGenericArg.GetTypeInfo().Assembly.FullName;

                                    // Check for prevention of an infinite loop
                                    if (propertyGenericArg.FullName != type.FullName)
                                    {
                                        propertyInfo.TypeProperties.AddRange(
                                            GetProperties(propertyGenericArg));
                                    }
                                }

                                propertyInfo.IsArray = true;

                                if (attributes.OfType <PictureparkReferenceAttribute>().Any() ||
                                    property.PropertyType.GenericTypeArguments.FirstOrDefault().GetTypeInfo().GetCustomAttribute <PictureparkReferenceAttribute>() != null)
                                {
                                    propertyInfo.IsReference = true;
                                }
                            }
                        }
                        else
                        {
                            propertyInfo.IsCustomType     = true;
                            propertyInfo.TypeName         = property.PropertyType.Name;
                            propertyInfo.FullName         = property.PropertyType.FullName;
                            propertyInfo.AssemblyFullName = typeInfo.Assembly.FullName;

                            if (typeInfo.GetCustomAttribute <PictureparkReferenceAttribute>() != null)
                            {
                                propertyInfo.IsReference = true;
                            }

                            // Check for prevention of an infinite loop
                            if (property.PropertyType.FullName != type.FullName)
                            {
                                propertyInfo.TypeProperties.AddRange(
                                    GetProperties(property.PropertyType));
                            }
                        }
                    }

                    var searchAttributes = property.AttributeProvider
                                           .GetAttributes(true)
                                           .Where(i => i.GetType().GetTypeInfo().ImplementedInterfaces.Any(j => j == typeof(IPictureparkAttribute)))
                                           .Select(i => i as IPictureparkAttribute)
                                           .ToList();

                    propertyInfo.PictureparkAttributes = searchAttributes;

                    contactPropertiesInfo.Add(propertyInfo);
                }
            }

            return(contactPropertiesInfo);
        }
        private IReadOnlyList <ContractTypeInfo> GetProperties(Type type)
        {
            var result = new List <ContractTypeInfo>();

            var typesToReflect = new VisitedTypesStack();

            typesToReflect.Push(type);

            while (typesToReflect.HasMore())
            {
                var typeToReflect = typesToReflect.Pop();

                foreach (var knownType in typeToReflect.GetKnownTypes())
                {
                    typesToReflect.Push(knownType);
                }

                var objectContract = _contractResolver.ResolveContract(typeToReflect) as JsonObjectContract;
                if (objectContract == null)
                {
                    continue;
                }

                var contractTypeInfo = new ContractTypeInfo()
                {
                    Type = typeToReflect
                };

                var baseType       = typeToReflect.GetTypeInfo().BaseType;
                var parentSchemaId = string.Empty;

                if (baseType != null &&
                    baseType != typeof(object) &&
                    baseType != typeof(Relation) &&
                    baseType != typeof(ReferenceObject))
                {
                    typesToReflect.Push(baseType);
                    parentSchemaId = ResolveSchemaName(baseType);
                }

                contractTypeInfo.ParentTypeName = parentSchemaId;

                foreach (var property in objectContract.Properties.Where(p => p.DeclaringType == typeToReflect))
                {
                    var typeInfo = property.PropertyType.GetTypeInfo();
                    var name     = property.PropertyName;

                    // Check if name is overridden by JsonProperty attribute
                    var attributes   = property.AttributeProvider.GetAttributes(false);
                    var jsonProperty = attributes.OfType <JsonPropertyAttribute>().FirstOrDefault();
                    if (jsonProperty != null)
                    {
                        name = jsonProperty.PropertyName;
                    }

                    // Skip ignored properties
                    if (_ignoredProperties.Contains(name))
                    {
                        continue;
                    }

                    var propertyInfo = new ContractPropertyInfo()
                    {
                        Name          = name,
                        IsOverwritten = typeToReflect.GetTypeInfo().BaseType?.GetRuntimeProperty(property.UnderlyingName) != null
                    };

                    if (IsSimpleType(property.PropertyType))
                    {
                        HandleSimpleTypes(property, propertyInfo);
                    }
                    else
                    {
                        // either list or dictionary
                        if (typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(typeInfo))
                        {
                            if (typeInfo.ImplementedInterfaces.Contains(typeof(IDictionary)) ||
                                (typeInfo.GenericTypeArguments.Any() && typeInfo.GenericTypeArguments.First().GetTypeInfo().ImplementedInterfaces.Contains(typeof(IDictionary))))
                            {
                                propertyInfo.IsArray      = typeInfo.ImplementedInterfaces.Contains(typeof(IList));
                                propertyInfo.IsDictionary = true;
                                propertyInfo.TypeName     = property.PropertyType.Name;
                            }
                            else
                            {
                                var propertyGenericArg = typeInfo.GenericTypeArguments.First();

                                if (IsSimpleType(propertyGenericArg))
                                {
                                    HandleSimpleTypes(property, propertyInfo);
                                }
                                else
                                {
                                    propertyInfo.TypeName = propertyGenericArg.Name;
                                    typesToReflect.Push(propertyGenericArg);
                                }

                                propertyInfo.IsArray = true;

                                if (attributes.OfType <PictureparkReferenceAttribute>().Any() ||
                                    property.PropertyType.GenericTypeArguments.FirstOrDefault().GetTypeInfo().GetCustomAttribute <PictureparkReferenceAttribute>() != null)
                                {
                                    propertyInfo.IsReference = true;
                                }
                            }
                        }
                        else
                        {
                            propertyInfo.TypeName = property.PropertyType.Name;
                            if (typeInfo.GetCustomAttribute <PictureparkReferenceAttribute>() != null)
                            {
                                propertyInfo.IsReference = true;
                            }

                            typesToReflect.Push(property.PropertyType);
                        }
                    }

                    propertyInfo.PictureparkAttributes = property.AttributeProvider
                                                         .GetAttributes(true)
                                                         .Select(i => i as IPictureparkAttribute)
                                                         .Where(i => i != null)
                                                         .ToList();

                    contractTypeInfo.Properties.Add(propertyInfo);
                }

                result.Add(contractTypeInfo);
            }

            return(result);
        }
        private FieldBase GetField(ContractPropertyInfo property)
        {
            FieldBase field;

            if (property.IsDictionary)
            {
                if (property.TypeName == "TranslatedStringDictionary")
                {
                    field = new FieldTranslatedString
                    {
                        Required       = false,
                        Fixed          = false,
                        Index          = true,
                        SimpleSearch   = true,
                        MultiLine      = false,
                        Boost          = 1,
                        IndexAnalyzers = new List <AnalyzerBase>
                        {
                            new LanguageAnalyzer()
                        },
                        SimpleSearchAnalyzers = new List <AnalyzerBase>
                        {
                            new LanguageAnalyzer()
                        }
                    };
                }
                else if (property.IsArray)
                {
                    field = new FieldDictionaryArray();
                }
                else
                {
                    field = new FieldDictionary();
                }
            }
            else if (property.IsEnum)
            {
                throw new NotSupportedException("Enum types are not supported in Class to Schema conversion");
            }
            else if (property.IsSimpleType)
            {
                if (!Enum.TryParse(property.TypeName, out TypeCode typeCode))
                {
                    throw new Exception($"Parsing to TypeCode enumerated object failed for string value: {property.TypeName}.");
                }

                if (property.IsArray)
                {
                    switch (typeCode)
                    {
                    case TypeCode.String:
                        field = new FieldStringArray
                        {
                            Index = true
                        };
                        break;

                    case TypeCode.DateTime:
                        field = new FieldDateTimeArray
                        {
                            Index = true
                        };
                        break;

                    case TypeCode.Int16:
                    case TypeCode.Int32:
                    case TypeCode.Int64:
                        field = new FieldLongArray
                        {
                            Index = true
                        };
                        break;

                    default:
                        throw new Exception($"TypeCode {typeCode} is not supported.");
                    }
                }
                else
                {
                    var stringInfos = property.PictureparkAttributes.OfType <PictureparkStringAttribute>().SingleOrDefault();

                    switch (typeCode)
                    {
                    case TypeCode.String:
                        field = new FieldString
                        {
                            Index          = true,
                            SimpleSearch   = true,
                            Boost          = 1,
                            IndexAnalyzers = new List <AnalyzerBase>
                            {
                                new SimpleAnalyzer()
                            },
                            SimpleSearchAnalyzers = new List <AnalyzerBase>
                            {
                                new SimpleAnalyzer()
                            },
                            MultiLine = stringInfos?.MultiLine ?? false
                        };
                        break;

                    case TypeCode.DateTime:
                        field = CreateDateTypeField(property);

                        break;

                    case TypeCode.Boolean:
                        field = new FieldBoolean
                        {
                            Index = true
                        };
                        break;

                    case TypeCode.Int16:
                    case TypeCode.Int32:
                    case TypeCode.Int64:
                        field = new FieldLong
                        {
                            Index = true
                        };
                        break;

                    case TypeCode.Decimal:
                    case TypeCode.Double:
                    case TypeCode.Single:
                        field = new FieldDecimal
                        {
                            Index = true
                        };
                        break;

                    default:
                        throw new Exception($"TypeCode {typeCode} is not supported.");
                    }
                }
            }
            else
            {
                var schemaIndexingAttribute         = property.PictureparkAttributes.OfType <PictureparkSchemaIndexingAttribute>().SingleOrDefault();
                var listItemCreateTemplateAttribute = property.PictureparkAttributes.OfType <PictureparkListItemCreateTemplateAttribute>().SingleOrDefault();
                var tagboxAttributes          = property.PictureparkAttributes.OfType <PictureparkTagboxAttribute>().SingleOrDefault();
                var contentRelationAttributes = property.PictureparkAttributes.OfType <PictureparkContentRelationAttribute>().ToList();

                var relationTypes = new List <RelationType>();
                if (contentRelationAttributes.Any())
                {
                    relationTypes = contentRelationAttributes.Select(i => new RelationType
                    {
                        Id            = i.Name,
                        Filter        = i.Filter,
                        TargetDocType = i.TargetDocType,
                        Names         = new TranslatedStringDictionary {
                            { _defaultLanguage, i.Name }
                        }
                    }).ToList();
                }

                if (property.IsArray)
                {
                    if (contentRelationAttributes.Any())
                    {
                        field = new FieldMultiRelation
                        {
                            Index              = true,
                            RelationTypes      = relationTypes,
                            SchemaId           = property.TypeName,
                            SchemaIndexingInfo = schemaIndexingAttribute?.SchemaIndexingInfo
                        };
                    }
                    else if (property.IsReference)
                    {
                        field = new FieldMultiTagbox
                        {
                            Index                  = true,
                            SimpleSearch           = true,
                            SchemaId               = property.TypeName,
                            Filter                 = tagboxAttributes?.Filter,
                            SchemaIndexingInfo     = schemaIndexingAttribute?.SchemaIndexingInfo,
                            ListItemCreateTemplate = listItemCreateTemplateAttribute?.ListItemCreateTemplate
                        };
                    }
                    else
                    {
                        field = new FieldMultiFieldset
                        {
                            Index              = true,
                            SimpleSearch       = true,
                            SchemaId           = property.TypeName,
                            SchemaIndexingInfo = schemaIndexingAttribute?.SchemaIndexingInfo
                        };
                    }
                }
                else
                {
                    if (contentRelationAttributes.Any())
                    {
                        field = new FieldSingleRelation
                        {
                            Index              = true,
                            SimpleSearch       = true,
                            RelationTypes      = relationTypes,
                            SchemaId           = property.TypeName,
                            SchemaIndexingInfo = schemaIndexingAttribute?.SchemaIndexingInfo
                        };
                    }
                    else if (property.TypeName == "GeoPoint")
                    {
                        field = new FieldGeoPoint
                        {
                            Index = true
                        };
                    }
                    else if (property.IsReference)
                    {
                        field = new FieldSingleTagbox
                        {
                            Index                  = true,
                            SimpleSearch           = true,
                            SchemaId               = property.TypeName,
                            Filter                 = tagboxAttributes?.Filter,
                            SchemaIndexingInfo     = schemaIndexingAttribute?.SchemaIndexingInfo,
                            ListItemCreateTemplate = listItemCreateTemplateAttribute?.ListItemCreateTemplate
                        };
                    }
                    else
                    {
                        field = new FieldSingleFieldset
                        {
                            Index              = true,
                            SimpleSearch       = true,
                            SchemaId           = property.TypeName,
                            SchemaIndexingInfo = schemaIndexingAttribute?.SchemaIndexingInfo
                        };
                    }
                }
            }

            if (field == null)
            {
                throw new Exception($"Could not find type for {property.Name}");
            }

            foreach (var attribute in property.PictureparkAttributes)
            {
                if (attribute is PictureparkSearchAttribute searchAttribute)
                {
                    field.Index        = searchAttribute.Index;
                    field.SimpleSearch = searchAttribute.SimpleSearch;

                    if (field.GetType().GetRuntimeProperty("Boost") != null)
                    {
                        field.GetType().GetRuntimeProperty("Boost").SetValue(field, searchAttribute.Boost);
                    }
                }

                if (attribute is PictureparkRequiredAttribute)
                {
                    field.Required = true;
                }

                if (attribute is PictureparkMaximumLengthAttribute maxLengthAttribute)
                {
                    field.GetType().GetRuntimeProperty("MaximumLength").SetValue(field, maxLengthAttribute.Length);
                }

                if (attribute is PictureparkPatternAttribute patternAttribute)
                {
                    field.GetType().GetRuntimeProperty("Pattern").SetValue(field, patternAttribute.Pattern);
                }

                if (attribute is PictureparkNameTranslationAttribute nameTranslationAttribute)
                {
                    if (field.Names == null)
                    {
                        field.Names = new TranslatedStringDictionary();
                    }

                    var language = string.IsNullOrEmpty(nameTranslationAttribute.LanguageAbbreviation)
                        ? _defaultLanguage
                        : nameTranslationAttribute.LanguageAbbreviation;

                    field.Names[language] = nameTranslationAttribute.Translation;
                }

                if (attribute is PictureparkSortAttribute)
                {
                    if (field is FieldSingleRelation || field is FieldMultiRelation)
                    {
                        throw new InvalidOperationException($"Relation property {property.Name} must not be marked as sortable.");
                    }

                    if (field is FieldGeoPoint)
                    {
                        throw new InvalidOperationException($"GeoPoint property {property.Name} must not be marked as sortable.");
                    }

                    field.Sortable = true;
                }
            }

            var fieldName = property.Name;

            field.Id = fieldName.ToLowerCamelCase();

            if (field.Names == null)
            {
                field.Names = new TranslatedStringDictionary
                {
                    [_defaultLanguage] = fieldName
                };
            }

            if (property.PictureparkAttributes.OfType <PictureparkAnalyzerAttribute>().Any(a => !a.Index && !a.SimpleSearch))
            {
                throw new InvalidOperationException(
                          $"Property {property.Name} has invalid analyzer configuration: Specify one or both of {nameof(PictureparkAnalyzerAttribute.Index)}, {nameof(PictureparkAnalyzerAttribute.SimpleSearch)}.");
            }

            var fieldIndexAnalyzers = property.PictureparkAttributes
                                      .OfType <PictureparkAnalyzerAttribute>()
                                      .Where(a => a.Index)
                                      .Select(a => a.CreateAnalyzer())
                                      .ToList();

            if (fieldIndexAnalyzers.Any())
            {
                field.GetType().GetRuntimeProperty("IndexAnalyzers").SetValue(field, fieldIndexAnalyzers);
            }

            var fieldSimpleSearchAnalyzers = property.PictureparkAttributes
                                             .OfType <PictureparkAnalyzerAttribute>()
                                             .Where(a => a.SimpleSearch)
                                             .Select(a => a.CreateAnalyzer())
                                             .ToList();

            if (fieldSimpleSearchAnalyzers.Any())
            {
                field.GetType().GetRuntimeProperty("SimpleSearchAnalyzers").SetValue(field, fieldSimpleSearchAnalyzers);
            }

            return(field);
        }