package com.atlassian.stash.internal.setting;

import com.atlassian.bitbucket.validation.FormValidationException;
import com.atlassian.bitbucket.setting.Settings;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Map;

import static com.google.common.base.Preconditions.checkNotNull;

@Component("settingsHelper")
public class JacksonSettingsHelper implements SettingsHelper {

    // This is thread-safe provided no setters are called on it
    private static final ObjectMapper MAPPER = new ObjectMapper();

    @Nonnull
    @Override
    public Settings deserialize(@Nonnull String data) {
        checkNotNull(data, "data");

        try {
            //noinspection unchecked
            return new MapSettingsBuilder()
                    .addAll(MAPPER.readValue(data, Map.class))
                    .build();
        } catch (IOException e) {
            // This should never happen as we use the same ObjectMapper to serialize settings for storage. Possible
            // causes include:
            //  * An encoding issue in the database
            //  * A bug in Jackson
            //  * A manual modification to the database
            throw new DeserializeSettingsException("The provided data could not be deserialized from JSON", e);
        }
    }

    @Nonnull
    @Override
    public String serialize(@Nonnull Settings settings) throws FormValidationException {
        checkNotNull(settings, "settings");

        try {
            return MAPPER.writeValueAsString(settings.asMap());
        } catch (IOException e) {
            // This should never happen, since generally Jackson can serialize almost anything to JSON. The most
            // likely culprit here is that the Settings object contains rich data, which is not expected. Only
            // basic types like Java primitives and Strings are supported
            throw new SerializeSettingsException("The provided Settings could not be serialized to JSON", e);
        }
    }
}
