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 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);
        }