/*
 * Copyright 2014-2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.lastaflute.core.json;

import java.lang.reflect.ParameterizedType;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;

import org.dbflute.util.DfCollectionUtil;
import org.dbflute.util.DfReflectionUtil;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/**
 * @author jflute
 */
public class GsonJsonParser implements RealJsonParser, Java8TimeGson {

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    protected final Gson gson;

    // ===================================================================================
    //                                                                         Constructor
    //                                                                         ===========
    public GsonJsonParser(Consumer<GsonBuilder> settings) {
        final GsonBuilder builder = newGsonBuilder();
        acceptGsonSettings(settings, builder);
        setupGsonBuilder(builder);
        registerJava8TimeAdapter(builder);
        gson = builder.create();
    }

    protected GsonBuilder newGsonBuilder() {
        return new GsonBuilder();
    }

    protected void acceptGsonSettings(Consumer<GsonBuilder> settings, GsonBuilder builder) {
        settings.accept(builder);
    }

    protected void setupGsonBuilder(GsonBuilder builder) { // you can override
    }

    protected void registerJava8TimeAdapter(GsonBuilder builder) { // until supported by Gson
        builder.registerTypeAdapter(localDateType, newLocalDatelizer());
        builder.registerTypeAdapter(localDateTimeType, newLocalDateTimelizer());
        builder.registerTypeAdapter(localTimeType, newLocalTimelizer());
    }

    protected LocalDatelizer newLocalDatelizer() {
        return new LocalDatelizer();
    }

    protected LocalDateTimelizer newLocalDateTimelizer() {
        return new LocalDateTimelizer();
    }

    protected LocalTimelizer newLocalTimelizer() {
        return new LocalTimelizer();
    }

    // ===================================================================================
    //                                                                      JSON Interface
    //                                                                      ==============
    @SuppressWarnings("unchecked")
    @Override
    public <BEAN> BEAN fromJson(String json, Class<BEAN> beanType) { // are not null, already checked
        final BEAN bean = gson.fromJson(json, beanType); // if empty JSON, new-only instance
        return bean != null ? bean : (BEAN) DfReflectionUtil.newInstance(beanType);
    }

    @Override
    public <BEAN> List<BEAN> fromJsonList(String json, ParameterizedType elementType) { // are not null, already checked
        final List<BEAN> list = gson.fromJson(json, elementType); // if empty JSON, empty list
        return list != null ? Collections.unmodifiableList(list) : DfCollectionUtil.emptyList();
    }

    @Override
    public String toJson(Object bean) { // is not null, already checked
        return gson.toJson(bean);
    }
}

@@ -1736,37 +1736,29 @@
     
-acceptGsonSettings(settings, 
+setupDefaultSettings(
 buil
@@ -1776,27 +1776,28 @@
    setup
-GsonBuilder
+YourSettings
 (builder
@@ -1811,33 +1811,37 @@
     
-registerJava8TimeAdapter(
+acceptGsonSettings(settings, 
 buil
@@ -1995,105 +1995,131 @@
 oid 
-acceptGsonSettings(Consumer%3CGsonBuilder%3E settings, GsonBuilder builder) %7B%0A        settings.accept
+setupDefaultSettings(final GsonBuilder builder) %7B%0A        registerUtilDateFormat(builder);%0A        registerJava8TimeAdapter
 (bui
@@ -2155,24 +2155,30 @@
 oid 
-setupGsonBuilder
+registerUtilDateFormat
 (Gso
@@ -2200,27 +2200,90 @@
 r) %7B
- // you can overrid
+%0A        builder.setDateFormat(%22yyyy-MM-dd'T'HH:mm:ss%22); // same as local date-tim
 e%0A  
@@ -2607,32 +2607,253 @@
 izer());%0A    %7D%0A%0A
+    protected void setupYourSettings(GsonBuilder builder) %7B // you can override%0A    %7D%0A%0A    protected void acceptGsonSettings(Consumer%3CGsonBuilder%3E settings, GsonBuilder builder) %7B%0A        settings.accept(builder);%0A    %7D%0A%0A
     protected Lo

add registerUtilDateFormat()