public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
        {
            try
            {
                if (source != null && !source.ToString().IsNullOrWhiteSpace() && source.ToString() != "{}")
                {
                    var value = JsonConvert.DeserializeObject <MortarValue>(source.ToString());

                    // We get the JSON converter to do some initial conversion, but
                    // created the IPublishedContent values requires some context
                    // so we have to do them in an additional loop here
                    foreach (var key in value.Keys)
                    {
                        var rowOptionsDocTypeAlias = MortarHelper.GetRowOptionsDocType(propertyType.DataTypeId, key);

                        foreach (var row in value[key])
                        {
                            if (!string.IsNullOrWhiteSpace(rowOptionsDocTypeAlias))
                            {
                                row.Options = ConvertDataToSource_DocType(propertyType, rowOptionsDocTypeAlias, row.RawOptions, preview);
                            }

                            foreach (var item in row.Items)
                            {
                                if (item != null && item.RawValue != null)
                                {
                                    switch (item.Type.ToLowerInvariant())
                                    {
                                    case "richtext":
                                        item.Value = ConvertDataToSource_Fake(propertyType, "MortarRichtext", Constants.PropertyEditors.TinyMCEAlias, "bodyText", item.RawValue, preview);
                                        break;

                                    case "embed":
                                        item.Value = ConvertDataToSource_Fake(propertyType, "MortarEmbed", Constants.PropertyEditors.TextboxMultipleAlias, "embedCode", item.RawValue, preview);
                                        break;

                                    case "link":
                                        item.Value = ConvertDataToSource_Link(propertyType, item.RawValue, preview);
                                        break;

                                    case "media":
                                        item.Value = ConvertDataToSource_Media(propertyType, item.RawValue, preview);
                                        break;

                                    case "doctype":
                                        Guid docTypeGuid;
                                        if (item.AdditionalInfo.ContainsKey("docType") &&
                                            item.AdditionalInfo["docType"] != null &&
                                            !item.AdditionalInfo["docType"].IsNullOrWhiteSpace())
                                        {
                                            // Lookup the doctype
                                            var docTypeAlias = item.AdditionalInfo["docType"];

                                            // We make an assumption that the docTypeAlias is a Guid and attempt to parse it,
                                            // failing that we assume that the docTypeAlias is the actual alias.
                                            if (Guid.TryParse(docTypeAlias, out docTypeGuid))
                                            {
                                                docTypeAlias = ApplicationContext.Current.Services.ContentTypeService.GetAliasByGuid(docTypeGuid);
                                            }

                                            item.Value = ConvertDataToSource_DocType(propertyType, docTypeAlias, item.RawValue, preview);
                                        }

                                        break;
                                    }
                                }
                            }
                        }
                    }

                    return(value);
                }
            }
            catch (Exception e)
            {
                LogHelper.Error <MortarValueConverter>("Error converting value", e);
            }

            return(null);
        }
        private void ResolvePropertyData(Item item, ContentProperty propertyData, Direction direction)
        {
            if (propertyData == null || propertyData.Value == null)
            {
                return;
            }

            // create a fake `PublishedPropertyType`
            var dataTypeId = ExecutionContext.DatabasePersistence.GetNodeId(propertyData.DataType, NodeObjectTypes.DataType);

            // deserialize the current Property's value into a 'MortarValue'
            var mortarValue = JsonConvert.DeserializeObject <MortarValue>(propertyData.Value.ToString());

            // get the `PropertyItemProvider` from the collection.
            var propertyItemProvider = ItemProviderCollection.Instance.GetProvider(ProviderIDCollection.propertyDataItemProviderGuid, this.ExecutionContext);

            if (mortarValue != null)
            {
                foreach (var mortarBlock in mortarValue)
                {
                    foreach (var mortarRow in mortarBlock.Value)
                    {
                        var rowOptionsDocTypeAlias = MortarHelper.GetRowOptionsDocType(dataTypeId, mortarBlock.Key);
                        if (!string.IsNullOrWhiteSpace(rowOptionsDocTypeAlias))
                        {
                            mortarRow.RawOptions = ResolveMultiplePropertyItemData(item, propertyItemProvider,
                                                                                   mortarRow.RawOptions, rowOptionsDocTypeAlias, direction);
                        }

                        foreach (var mortarItem in mortarRow.Items)
                        {
                            if (mortarItem == null)
                            {
                                CourierLogHelper.Warn <MortarDataResolver>("MortarItem appears to be null, (from '{0}' block)", () => mortarBlock.Key);
                                continue;
                            }

                            if (mortarItem.Type == null)
                            {
                                CourierLogHelper.Warn <MortarDataResolver>("MortarItem did not contain a value for Type, (from '{0}' block)", () => mortarBlock.Key);
                                continue;
                            }

                            switch (mortarItem.Type.ToUpperInvariant())
                            {
                            case "DOCTYPE":
                                // resolve the doctype alias/guid
                                string docTypeAlias = string.Empty;
                                if (mortarItem.AdditionalInfo.ContainsKey("docType"))
                                {
                                    docTypeAlias = mortarItem.AdditionalInfo["docType"];
                                    DocumentType docType;
                                    Guid         docTypeGuid;
                                    if (Guid.TryParse(docTypeAlias, out docTypeGuid))
                                    {
                                        docType = ExecutionContext.DatabasePersistence.RetrieveItem <DocumentType>(
                                            new ItemIdentifier(docTypeGuid.ToString(),
                                                               ProviderIDCollection.documentTypeItemProviderGuid));
                                        docTypeAlias = docType.Alias;
                                    }
                                    else
                                    {
                                        docType = ExecutionContext.DatabasePersistence.RetrieveItem <DocumentType>(
                                            new ItemIdentifier(docTypeAlias,
                                                               ProviderIDCollection.documentTypeItemProviderGuid));
                                        docTypeGuid = docType.UniqueId;
                                    }

                                    if (direction == Direction.Packaging)
                                    {
                                        mortarItem.AdditionalInfo["docType"] = docTypeAlias;

                                        // add dependency for the DocType
                                        var name       = string.Concat("Document type: ", docTypeAlias);
                                        var dependency = new Dependency(name, docTypeAlias, ProviderIDCollection.documentTypeItemProviderGuid);
                                        item.Dependencies.Add(dependency);
                                    }
                                    else if (direction == Direction.Extracting)
                                    {
                                        mortarItem.AdditionalInfo["docType"] = docTypeGuid.ToString();
                                    }
                                }

                                // resolve the value's properties
                                mortarItem.RawValue = ResolveMultiplePropertyItemData(item, propertyItemProvider, mortarItem.RawValue, docTypeAlias, direction);

                                break;

                            case "EMBED":
                                // we don't need Courier to process the embed code - it's pure HTML
                                break;

                            case "LINK":
                                mortarItem.RawValue = ConvertIdentifier(mortarItem.RawValue, item, direction, ProviderIDCollection.documentItemProviderGuid, "Document");
                                break;

                            case "MEDIA":
                                mortarItem.RawValue = ConvertIdentifier(mortarItem.RawValue, item, direction, ProviderIDCollection.mediaItemProviderGuid, "Media");
                                break;

                            case "RICHTEXT":
                                //From the 'MortarValueConverter' it appears that the DocumentTypeAlias, PropertyEditorAlias and PropertyTypeAlias are
                                //all constants, so we reuse them here.
                                mortarItem.RawValue = ResolvePropertyItemData(item, propertyItemProvider, mortarItem.RawValue,
                                                                              Constants.PropertyEditors.TinyMCEAlias, "bodyText", Guid.Empty, direction);
                                break;

                            default:
                                break;
                            }
                        }
                    }
                }

                propertyData.Value = JsonConvert.SerializeObject(mortarValue);
            }
        }
            public override object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue)
            {
                if (editorValue.Value == null || string.IsNullOrWhiteSpace(editorValue.Value.ToString()))
                {
                    return(null);
                }

                var value = JsonConvert.DeserializeObject <MortarValue>(editorValue.Value.ToString());

                if (value == null)
                {
                    return(null);
                }

                foreach (var key in value.Keys)
                {
                    var rowOptionsDocTypeAlias = MortarHelper.GetRowOptionsDocType(editorValue.PreValues, key);

                    foreach (var row in value[key])
                    {
                        row.RawOptions = !string.IsNullOrWhiteSpace(rowOptionsDocTypeAlias)
                                                        ? ConvertEditorToDb_DocType(rowOptionsDocTypeAlias, row.RawOptions)
                                                        : null;

                        foreach (var item in row.Items)
                        {
                            if (item != null && item.RawValue != null)
                            {
                                switch (item.Type.ToLowerInvariant())
                                {
                                case "richtext":
                                    item.RawValue = ConvertEditorToDb_Fake(Constants.PropertyEditors.TinyMCEAlias, item.RawValue);
                                    break;

                                case "embed":
                                    item.RawValue = ConvertEditorToDb_Fake(Constants.PropertyEditors.TextboxMultipleAlias, item.RawValue);
                                    break;

                                case "doctype":
                                    if (item.AdditionalInfo.ContainsKey("docType") &&
                                        item.AdditionalInfo["docType"] != null &&
                                        !item.AdditionalInfo["docType"].IsNullOrWhiteSpace())
                                    {
                                        // Lookup the doctype
                                        var docTypeAlias = item.AdditionalInfo["docType"];

                                        // We make an assumption that the docTypeAlias is a Guid and attempt to parse it,
                                        // failing that we assume that the docTypeAlias is the actual alias.
                                        Guid docTypeGuid;
                                        if (Guid.TryParse(docTypeAlias, out docTypeGuid))
                                        {
                                            docTypeAlias = ApplicationContext.Current.Services.ContentTypeService.GetAliasByGuid(docTypeGuid);

                                            // NOTE: [LK] As of v0.4.0 we want to persist the DocType's alias
                                            item.AdditionalInfo["docType"] = docTypeAlias;
                                        }

                                        // Serialize the dictionary back
                                        item.RawValue = ConvertEditorToDb_DocType(docTypeAlias, item.RawValue);
                                    }

                                    break;
                                }
                            }
                        }
                    }
                }

                return(JsonConvert.SerializeObject(value));
            }
            public override string ConvertDbToString(Property property, PropertyType propertyType, IDataTypeService dataTypeService)
            {
                if (property.Value == null || string.IsNullOrWhiteSpace(property.Value.ToString()))
                {
                    return(string.Empty);
                }

                var value = JsonConvert.DeserializeObject <MortarValue>(property.Value.ToString());

                if (value == null)
                {
                    return(string.Empty);
                }

                foreach (var key in value.Keys)
                {
                    var rowOptionsDocTypeAlias = MortarHelper.GetRowOptionsDocType(propertyType.DataTypeDefinitionId, key);

                    foreach (var row in value[key])
                    {
                        row.RawOptions = !string.IsNullOrWhiteSpace(rowOptionsDocTypeAlias)
                                                        ? ConvertDbToString_DocType(rowOptionsDocTypeAlias, row.RawOptions)
                                                        : null;

                        foreach (var item in row.Items)
                        {
                            if (item != null && item.RawValue != null)
                            {
                                switch (item.Type.ToLowerInvariant())
                                {
                                case "richtext":
                                    item.RawValue = ConvertDbToString_Fake(Constants.PropertyEditors.TinyMCEAlias, "bodyText", item.RawValue);
                                    break;

                                case "embed":
                                    item.RawValue = ConvertDbToString_Fake(Constants.PropertyEditors.TextboxMultipleAlias, "embedCode", item.RawValue);
                                    break;

                                case "doctype":

                                    if (item.AdditionalInfo.ContainsKey("docType") &&
                                        item.AdditionalInfo["docType"] != null &&
                                        !item.AdditionalInfo["docType"].IsNullOrWhiteSpace())
                                    {
                                        // Lookup the doctype
                                        var docTypeAlias = item.AdditionalInfo["docType"];

                                        // We make an assumption that the docTypeAlias is a Guid and attempt to parse it,
                                        // failing that we assume that the docTypeAlias is the actual alias.
                                        Guid docTypeGuid;
                                        if (Guid.TryParse(docTypeAlias, out docTypeGuid))
                                        {
                                            docTypeAlias = ApplicationContext.Current.Services.ContentTypeService.GetAliasByGuid(docTypeGuid);

                                            // NOTE: [LK] As of v0.4.0 we want to persist the DocType's alias
                                            item.AdditionalInfo["docType"] = docTypeAlias;
                                        }

                                        item.RawValue = ConvertDbToString_DocType(docTypeAlias, item.RawValue);
                                    }

                                    break;
                                }
                            }
                        }
                    }
                }

                // Update the value on the property
                property.Value = JsonConvert.SerializeObject(value);

                // Pass the call down
                return(base.ConvertDbToString(property, propertyType, dataTypeService));
            }
            public override object ConvertDbToEditor(Property property, PropertyType propertyType, IDataTypeService dataTypeService)
            {
                if (property.Value == null || string.IsNullOrWhiteSpace(property.Value.ToString()))
                {
                    return(string.Empty);
                }

                var value = JsonConvert.DeserializeObject <MortarValue>(property.Value.ToString());

                if (value == null)
                {
                    return(string.Empty);
                }

                foreach (var key in value.Keys)
                {
                    // Lookup the row option doc type here so we only do it once per cell
                    var rowOptionsDocTypeAlias = MortarHelper.GetRowOptionsDocType(propertyType.DataTypeDefinitionId, key);

                    foreach (var row in value[key])
                    {
                        row.RawOptions = !string.IsNullOrWhiteSpace(rowOptionsDocTypeAlias)
                                                        ? ConvertDbToEditor_DocType(rowOptionsDocTypeAlias, row.RawOptions)
                                                        : null;

                        foreach (var item in row.Items)
                        {
                            if (item != null && item.RawValue != null)
                            {
                                switch (item.Type.ToLowerInvariant())
                                {
                                case "richtext":
                                    item.RawValue = ConvertDbToEditor_Fake(Constants.PropertyEditors.TinyMCEAlias, "bodyText", item.RawValue);
                                    break;

                                case "embed":
                                    item.RawValue = ConvertDbToEditor_Fake(Constants.PropertyEditors.TextboxMultipleAlias, "embedCode", item.RawValue);
                                    break;

                                case "doctype":
                                    Guid docTypeGuid;
                                    if (item.AdditionalInfo.ContainsKey("docType") &&
                                        item.AdditionalInfo["docType"] != null &&
                                        !item.AdditionalInfo["docType"].IsNullOrWhiteSpace() &&
                                        Guid.TryParse(item.AdditionalInfo["docType"], out docTypeGuid))
                                    {
                                        // Lookup the doctype
                                        var docTypeAlias = ApplicationContext.Current.Services.ContentTypeService.GetAliasByGuid(docTypeGuid);
                                        item.RawValue = ConvertDbToEditor_DocType(docTypeAlias, item.RawValue);
                                    }

                                    break;
                                }
                            }
                        }
                    }
                }

                // We serialize back down as we want the editor to handle
                // the data as a generic object type, not our specific classes
                property.Value = JsonConvert.SerializeObject(value);

                return(base.ConvertDbToEditor(property, propertyType, dataTypeService));
            }