package org.netmelody.cieye.core.observation;

import java.text.SimpleDateFormat;
import java.util.Map;
import java.util.Map.Entry;

import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;

import static com.google.common.base.Functions.compose;

public final class CodeBook {

    private final String username;
    private final String password;
    private final SimpleDateFormat dateFormat;
    private final ImmutableMap<Class<?>, JsonDeserializer<?>> deserialisers;
    private final Function<String, String> munger;

    public CodeBook() {
        this(new SimpleDateFormat());
    }

    public CodeBook(SimpleDateFormat dateFormat) {
        this("", "", dateFormat, Functions.<String>identity(), ImmutableMap.<Class<?>, JsonDeserializer<?>>of());
    }

    private CodeBook(String username, String password, SimpleDateFormat dateFormat, Function<String, String> munger, ImmutableMap<Class<?>, JsonDeserializer<?>> deserialisers) {
        this.username = username;
        this.password = password;
        this.dateFormat = dateFormat;
        this.deserialisers = deserialisers;
        this.munger = munger;
    }

    public CodeBook withCredentials(String name, String pass) {
        return new CodeBook(name, pass, this.dateFormat, this.munger, this.deserialisers);
    }

    public CodeBook withRawContentMunger(Function<String, String> munger) {
        return new CodeBook(this.username, this.password, this.dateFormat, compose(munger, this.munger), this.deserialisers);
    }

    public <T> CodeBook withJsonDeserializerFor(Class<T> type, JsonDeserializer<T> deserialiser) {
        return new CodeBook(this.username, this.password, this.dateFormat, this.munger, extend(this.deserialisers, type, deserialiser));
    }

    public String username() {
        return username;
    }

    public String password() {
        return password;
    }

    public SimpleDateFormat dateFormat() {
        return dateFormat;
    }

    public Function<String, String> contentMunger() {
        return munger;
    }

    public Map<Class<?>, JsonDeserializer<?>> deserialisers() {
        return this.deserialisers;
    }

    private static <X, Y> ImmutableMap<X, Y> extend(Map<X, Y> map, X key, Y value) {
        return ImmutableMap.<X, Y>builder().putAll(map).put(key, value).build();
    }

    public Gson decoder() {
        final GsonBuilder builder = new GsonBuilder().setDateFormat(dateFormat().toPattern());
        
        for (Entry<Class<?>, JsonDeserializer<?>> entry : deserialisers().entrySet()) {
            builder.registerTypeAdapter(entry.getKey(), entry.getValue());
        }
        return builder.create();
    }
}
@@ -2056,255 +2056,72 @@
 lic 
-SimpleDateFormat dateFormat() %7B%0A        return dateFormat;%0A    %7D%0A%0A    public Function%3CString, String%3E contentMunger() %7B%0A        return munger;%0A    %7D%0A%0A    public Map%3CClass%3C?%3E, JsonDeserializer%3C?%3E%3E deserialisers() %7B%0A        return this.deserialisers
+Function%3CString, String%3E contentMunger() %7B%0A        return munger
 ;%0A  
@@ -2404,18 +2404,16 @@
 teFormat
-()
 .toPatte
@@ -2486,16 +2486,21 @@
 entry : 
+this.
 deserial
@@ -2504,18 +2504,16 @@
 ialisers
-()
 .entrySe

remove unused methods