package com.fp.dto;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.BeanMap;

import com.fp.common.helper.BeanManager;
import com.fp.dto.hb.HibernateId;

public class Response extends HashMap<String, Object> implements Serializable {

    /** Version de la clase. */
    private static final long serialVersionUID = 1L;

    /** Constante que define el codigo de respuesta ok. */
    public static final String RESPONSE_OK = "0";

    /** Codigo de respuesta. */
    private String responseCode;

    /** Mensaje de usuario asociado al codigo de respuesta. */
    private String responseUserMessage;

    /** Mensaje tecnico asociado al codigo de respuesta. */
    private String responseTechnicalMessage;

    /** Stack trace, del error ocasionada en al ejecucion de una operacion. */
    private String responseStack;

    /**
     * Variable para identificar si un mensaje es o no de aplicacion
     */
    private boolean isAplicationMessage;

    /**
     * Metodo que rerna si el mensaje es de la aplicacion
     * 
     * @return
     */
    public boolean isIsAplicationMessage() {
        return isAplicationMessage;
    }

    /**
     * Metodo que fija si el mensaje es de la aplicacion o no
     * 
     * @param isAplicationMessage
     */
    public void setIsAplicationMessage(boolean isAplicationMessage) {
        this.isAplicationMessage = isAplicationMessage;
        this.put("isAplicationMessage", isAplicationMessage);
    }

    /**
     * Entrega el valor de: responseTechnicalMessage
     * 
     * @return String
     */
    public String getResponseTechnicalMessage() {
        return responseTechnicalMessage;
    }

    /**
     * Fija el valor de: responseTechnicalMessage
     * 
     * @param responseTechnicalMessage
     */
    public void setResponseTechnicalMessage(String responseTechnicalMessage) {
        this.responseTechnicalMessage = responseTechnicalMessage;
        this.put("responseTechnicalMessage", responseTechnicalMessage);
    }

    /**
     * Entrega el valor de: responseStack
     * 
     * @return String
     */
    public String getResponseStack() {
        return responseStack;
    }

    /**
     * Fija el valor de: responseStack
     * 
     * @param responseStack
     */
    public void setResponseStack(String responseStack) {
        this.responseStack = responseStack;
        this.put("responseStack", responseStack);
    }

    /**
     * Entrega el valor de: responseCode
     * 
     * @return String
     */
    public String getResponseCode() {
        return responseCode;
    }

    /**
     * Entrega el valor de: responseUserMessage
     * 
     * @return String
     */
    public String getResponseUserMessage() {
        return responseUserMessage;
    }

    public Response(String responseCode, String responseUserMessage) {
        this.responseCode = responseCode;
        this.responseUserMessage = responseUserMessage;
        this.put("messageCode", responseCode);
        this.put("message", responseUserMessage);
        this.put("isAplicationMessage", true);
    }

    /**
     * Fija el valor de: responseCode
     * 
     * @param responseCode
     */
    public void setResponseCode(String responseCode) {
        this.responseCode = responseCode;
        this.put("messageCode", responseCode);
    }

    /**
     * Fija el valor de: responseUserMessage
     * 
     * @param responseUserMessage
     */
    public void setResponseUserMessage(String responseUserMessage) {
        this.responseUserMessage = responseUserMessage;
        this.put("message", responseUserMessage);
    }

    public void changeAbstractBeanToMap() throws Exception {
        Set<String> s = super.keySet();
        for (String key : s) {
            Object obj;
            obj = super.get(key);

            if (obj instanceof AbstractDataTransport) {
                Map<String, Object> mresp = this.beanToMap((AbstractDataTransport) obj);
                super.put(key, mresp);
            }
            if (obj instanceof List) {
                this.changeBeanListToMap(key, obj);
                continue;
            }
        }
    }

    @SuppressWarnings("unchecked")
    private void changeBeanListToMap(String key, Object data) throws Exception {
        List<Object> ldata;
        try {
            ldata = (List<Object>) data;
        } catch (Exception e) {
            return;
        }
        List<Map<String, Object>> lresp = new ArrayList<Map<String, Object>>();
        for (Object obj : ldata) {
            if (obj instanceof AbstractDataTransport) {
                Map<String, Object> mresp = this.beanToMap((AbstractDataTransport) obj);
                lresp.add(mresp);
            }
        }
        if (!lresp.isEmpty()) {
            super.put(key, lresp);
        }

    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> beanToMap(AbstractDataTransport bean) throws Exception {
        Map<String, Object> mresp = new HashMap<String, Object>();
        Field[] fs = bean.getClass().getDeclaredFields();
        for (Field field : fs) {
            try {
                String name = field.getName();
                if (name.compareTo("serialVersionUID") == 0 || name.compareTo("__id") == 0) {
                    continue;
                }
                Object val = null;
                try {
                    val = BeanManager.getBeanAttributeValue(bean, name);
                } catch (Exception e1) {
                    continue;
                }
                if (val instanceof HibernateId) {
                    BeanMap bm = new BeanMap(val);
                    Set<java.util.Map.Entry<String, Object>> ent = bm.entrySet();
                    for (java.util.Map.Entry<String, Object> e : ent) {
                        String key = e.getKey();
                        if (key.compareTo("class") == 0 || key.compareTo("transportBeanClass") == 0 || key.compareTo("empty") == 0
                                || key.compareTo("modifiedData") == 0) {
                            continue;
                        }
                        mresp.put(name + "_" + key, e.getValue());
                    }
                    continue;
                }
                mresp.put(name, val);
            } catch (Exception e) {
                continue;
            }

        }
        // completa datos adicionales.
        Set<String> s = bean.modifiedData.keySet();
        for (String key : s) {
            mresp.put(key, bean.modifiedData.get(key));
        }
        return mresp;
    }
}
