package com.capgemini.framework.common;

import lombok.extern.slf4j.Slf4j;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Map;
import java.util.TreeMap;

/**
 * JAVA bean attribute serializer.
 **/
@Slf4j
public final class BeanHelper {

    private static final String CLASS_ATT = "class";

    private BeanHelper() {
        // Makes this class static
    }

    /**
     * Map conversion for attributes of the current bean.
     *
     * @param aJavaBean Serialized JAVA bean
     * @return Map with key as property name and value as a String conversion of the attribute value.
     */
    public static Map<String, String> toStringMap(final Object aJavaBean) {
        Map<String, String> theStrMap = new TreeMap<>();
        try {
            fillStrMap(aJavaBean, theStrMap);
        } catch (IntrospectionException | IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
            log.error("Error occurred during instrospection, unable to analyse JAVA bean: " + aJavaBean.getClass().getName(), e);
        }
        return theStrMap;
    }

    /**
     * Sub-method of toStringMap() filling the map.
     *
     * @param aJavaBean Serialized JAVA bean
     * @param aStrMap   Map with key as property name and value as a String conversion of the attribute value.
     */
    private static void fillStrMap(final Object aJavaBean, final Map<String, String> aStrMap)
            throws IntrospectionException, IllegalAccessException, InvocationTargetException {

        BeanInfo beanInfo = Introspector.getBeanInfo(aJavaBean.getClass());
        for (PropertyDescriptor propertyDesc : beanInfo.getPropertyDescriptors()) {

            /* Get the next property name and ignore the common attribute called "class" */
            String propertyName = propertyDesc.getName();
            if (CLASS_ATT.equals(propertyName)) {
                continue;
            }

            /* Try to access to the property through its getter */
            Object theAttValue = propertyDesc.getReadMethod().invoke(aJavaBean);

            /* Convert attribute value to string */
            String theAttributeStrValue = StringHelper.EMPTY;
            if (theAttValue != null) {

                if (theAttValue instanceof Timestamp) {
                    theAttributeStrValue = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(theAttValue);
                } else {
                    theAttributeStrValue = theAttValue.toString();
                }
            }

            /* Store attribute in map */
            aStrMap.put(propertyName, theAttributeStrValue);
        }
    }
}
