/**
 * Copyright 2017 Jerónimo López Bezanilla
 *
 * 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.jfleet.common;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

import org.jfleet.EntityFieldType;
import org.jfleet.EntityFieldType.FieldTypeEnum;

public class BaseTypeSerializer {

    public interface Mapper extends Function<Object, String> {
    }

    private Map<FieldTypeEnum, Mapper> mappers = new HashMap<>();

    public BaseTypeSerializer() {
        add(FieldTypeEnum.BOOLEAN, FROM_BOOLEAN);
        add(FieldTypeEnum.BYTE, FROM_BYTE);
        add(FieldTypeEnum.CHAR, FROM_CHAR);
        add(FieldTypeEnum.DOUBLE, FROM_DOUBLE);
        add(FieldTypeEnum.FLOAT, FROM_FLOAT);
        add(FieldTypeEnum.INT, FROM_INT);
        add(FieldTypeEnum.LONG, FROM_LONG);
        add(FieldTypeEnum.SHORT, FROM_SHORT);
        add(FieldTypeEnum.BIGDECIMAL, FROM_BIGDECIMAL);
        add(FieldTypeEnum.BIGINTEGER, FROM_BIGINTEGER);
        add(FieldTypeEnum.STRING, FROM_STRING);
        add(FieldTypeEnum.TIMESTAMP, FROM_TIMESTAMP);
        add(FieldTypeEnum.DATE, FROM_DATE);
        add(FieldTypeEnum.TIME, FROM_TIME);
    }

    public void add(FieldTypeEnum type, Mapper mapper) {
        mappers.put(type, mapper);
    }

    public String toString(Object obj, EntityFieldType entityFieldType) {
        if (obj == null) {
            return null;
        }
        FieldTypeEnum fieldType = entityFieldType.getFieldType();
        Function<Object, String> function = mappers.get(fieldType);
        return function.apply(obj);
    }

    private static final Mapper FROM_BOOLEAN = (obj) -> ((Boolean) obj).booleanValue() ? "1" : "0";

    private static final Mapper FROM_BYTE = (obj) -> ((Byte) obj).toString();

    private static final Mapper FROM_CHAR = (obj) -> ((Character) obj).toString();

    private static final Mapper FROM_DOUBLE = (obj) -> ((Double) obj).toString();

    private static final Mapper FROM_FLOAT = (obj) -> ((Float) obj).toString();

    private static final Mapper FROM_INT = (obj) -> ((Integer) obj).toString();

    private static final Mapper FROM_LONG = (obj) -> ((Long) obj).toString();

    private static final Mapper FROM_SHORT = (obj) -> ((Short) obj).toString();

    private static final Mapper FROM_BIGDECIMAL = (obj) -> ((BigDecimal) obj).toString();

    private static final Mapper FROM_BIGINTEGER = (obj) -> ((BigInteger) obj).toString();

    private static final Mapper FROM_STRING = (obj) -> (String) obj;

    private static final Mapper FROM_TIMESTAMP = (obj) -> {
        if (obj instanceof java.util.Date) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return sdf.format((java.util.Date) obj);
        }
        return null;
    };

    private static final Mapper FROM_DATE = (obj) -> {
        if (obj instanceof java.util.Date) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            return sdf.format((java.util.Date) obj);
        }
        return null;
    };

    private static final Mapper FROM_TIME = (obj) -> {
        if (obj instanceof java.util.Date) {
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
            return sdf.format((java.util.Date) obj);
        }
        return null;
    };

}

@@ -723,16 +723,59 @@
 Format;%0A
+import java.time.format.DateTimeFormatter;%0A
 import j
@@ -1045,23 +1045,403 @@
  %7D%0A%0A    
-private
+/* As Type Serializer is used in a single stream, we don't need to take care of threadsafety of SimpleDateFormat*/%0A    private final SimpleDateFormat sdfDateTime = new SimpleDateFormat(%22yyyy-MM-dd HH:mm:ss%22);%0A    private final SimpleDateFormat sdfDate = new SimpleDateFormat(%22yyyy-MM-dd%22);%0A    private final SimpleDateFormat sdfTime = new SimpleDateFormat(%22HH:mm:ss%22);%0A%0A    private final
  Map%3CFie
@@ -2611,39 +2611,32 @@
  %7D%0A%0A    private 
-static 
 final Mapper FRO
@@ -2705,39 +2705,32 @@
 %22;%0A%0A    private 
-static 
 final Mapper FRO
@@ -2777,39 +2777,32 @@
 );%0A%0A    private 
-static 
 final Mapper FRO
@@ -2854,39 +2854,32 @@
 );%0A%0A    private 
-static 
 final Mapper FRO
@@ -2930,39 +2930,32 @@
 );%0A%0A    private 
-static 
 final Mapper FRO
@@ -3004,39 +3004,32 @@
 );%0A%0A    private 
-static 
 final Mapper FRO
@@ -3078,39 +3078,32 @@
 );%0A%0A    private 
-static 
 final Mapper FRO
@@ -3150,39 +3150,32 @@
 );%0A%0A    private 
-static 
 final Mapper FRO
@@ -3224,39 +3224,32 @@
 );%0A%0A    private 
-static 
 final Mapper FRO
@@ -3308,39 +3308,32 @@
 );%0A%0A    private 
-static 
 final Mapper FRO
@@ -3392,39 +3392,32 @@
 );%0A%0A    private 
-static 
 final Mapper FRO
@@ -3455,39 +3455,32 @@
 j;%0A%0A    private 
-static 
 final Mapper FRO
@@ -3565,88 +3565,8 @@
     
-SimpleDateFormat sdf = new SimpleDateFormat(%22yyyy-MM-dd HH:mm:ss%22);%0A            
 retu
@@ -3563,32 +3563,40 @@
       return sdf
+DateTime
 .format((java.ut
@@ -3653,39 +3653,32 @@
 %7D;%0A%0A    private 
-static 
 final Mapper FRO
@@ -3758,79 +3758,8 @@
     
-SimpleDateFormat sdf = new SimpleDateFormat(%22yyyy-MM-dd%22);%0A            
 retu
@@ -3756,32 +3756,36 @@
       return sdf
+Date
 .format((java.ut
@@ -3854,15 +3854,8 @@
 ate 
-static 
 fina
@@ -3947,77 +3947,8 @@
     
-SimpleDateFormat sdf = new SimpleDateFormat(%22HH:mm:ss%22);%0A            
 retu
@@ -3953,16 +3953,20 @@
 turn sdf
+Time
 .format(

Change static methods to instance method and use a single instance of DateFormat for all format, as execution is done in single thread, and class is instanced for each operation