package com.fp.dto.save;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.fp.dto.Request;
import com.fp.dto.fin.FinancialRequest;

/**
 * Clase que contiene beans de insert o update de datos en la base.
 * 
 * @author Jorge Vaca
 * @version 2.1
 */
public class SaveRequest extends Request {

    private static final long serialVersionUID = 1L;

    /**
     * indica si la consulta se origina en una pagina jsf.
     */
    private boolean jsf = false;

    /** Lista de nombres de beans a almacenar en la base de datos. */
    private final List<String> lOrderPersistentBeans = new ArrayList<String>();

    /*
     * (non-Javadoc)
     * 
     * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
     */
    @Override
    public Object put(String key, Object value) {
        if (key.compareTo("beans") == 0) {
            return value;
        }
        return super.put(key, value);
    }

    /**
     * Adiciona un objeto SaveBean persistente al request.
     * 
     * @param key Alias del objeto, es el mismo que el namebean del objeto SaveBean.
     * @param pObject Objeto a adicionar al SaveRequest.
     * @param pPosition Posicion del objeto para grabar en la base de datos.
     * @return Object
     */
    @SuppressWarnings("unchecked")
    public Object putSaveBean(String key, Object pObject, Integer pPosition) throws Exception {
        SaveBean saveBean = null;
        if (pObject instanceof SaveBean) {
            saveBean = (SaveBean) pObject;
        } else {
            saveBean = new SaveBean(key);
            if (pObject instanceof List) {
                saveBean.setModifiedRecords((List) pObject);
            } else {
                saveBean.setModifiedObject(pObject);
            }
            saveBean.setPosition(pPosition);
        }
        if (key.compareTo("beans") == 0) {
            return pObject;
        }
        if (pPosition == null) {
            this.addObjecttoList(key);
        } else {
            int index = --pPosition;
            if ((lOrderPersistentBeans.size() == 0) || (index > lOrderPersistentBeans.size())) {
                this.addObjecttoList(key);
            } else {
                this.addObjecttoList(key, index);
            }
        }
        return super.put(key, saveBean);
    }

    /**
     * Adiciona un key de un objeto a la lista de beans persistentes, si existe en la lista elimina el registro y lo
     * adiciona.
     * 
     * @param key Key a almacenar en la lista.
     * @throws Exception
     */
    private void addObjecttoList(String key) throws Exception {
        if (lOrderPersistentBeans.contains(key)) {
            lOrderPersistentBeans.remove(key);
        }
        lOrderPersistentBeans.add(key);
    }

    /**
     * Adiciona un key de un objeto a la lista de beans persistentes, si existe en la lista elimina el registro y lo
     * adiciona.
     * 
     * @param key Key a almacenar en la lista.
     * @param index Indice con el que se almacena el key en la lista.
     * @throws Exception
     */
    private void addObjecttoList(String key, Integer index) throws Exception {
        if (lOrderPersistentBeans.contains(key)) {
            lOrderPersistentBeans.remove(key);
        }
        lOrderPersistentBeans.add(index, key);
    }

    /**
     * Adiciona un objeto SaveBean persistente al request.
     * 
     * @param key Alias del objeto, es el mismo que el namebean del objeto SaveBean.
     * @param pObject Objeto a adicionar al SaveRequest.
     * @return Object
     */
    @SuppressWarnings("unchecked")
    public Object putSaveBean(String key, Object pObject) throws Exception {
        SaveBean saveBean = null;
        if (pObject instanceof SaveBean) {
            saveBean = (SaveBean) pObject;
            if (saveBean.getPosition() != null) {
                return this.putSaveBean(key, pObject, saveBean.getPosition());
            }
        } else {
            saveBean = new SaveBean(key);
            if (pObject instanceof List) {
                saveBean.setModifiedRecords((List) pObject);
            } else {
                saveBean.setModifiedObject(pObject);
            }
        }
        /** ==================== ACA AGREGE KEY VALUE COMPARACION NULL*/
        if ( key !=null && key.compareTo("beans") == 0 ) {
            return pObject;
        }
        this.addObjecttoList(key);
        return super.put(key, saveBean);
    }

    /**
     * Entrega un objeto SaveBean dado el key.
     * 
     * @param pKey Key a buscar y entregarr el objeto.
     * @return SaveBean
     * @throws Exception
     */
    public SaveBean getSaveBeanOLD(Object pKey) throws Exception {
        return (SaveBean) super.get(pKey);
    }

    /**
     * Entrega un objeto SaveBean dado el key.
     * 
     * @param pKey Key a buscar y entregarr el objeto.
     * @return SaveBean
     * @throws Exception
     */
    public Object getSaveBeanModifiedObject(Object pKey) throws Exception {
        try {
            SaveBean sb = (SaveBean) super.get(pKey);
            if (sb != null) {
                return sb.getModifiedObject();
            }
        } catch (ClassCastException e) {
            return null;
        }
        return null;
    }

    /**
     * Entrega un SaveBean dato el key del objeto. Si no existe el objeto entrega null;
     * 
     * @param pKey Key del objeto a buscar.
     * @return SaveBean
     * @throws Exception
     */
    public SaveBean getSaveBean(Object pKey) throws Exception {
        try {
            return (SaveBean) super.get(pKey);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Entrega una Lista de registros modificados dado el key.
     * 
     * @param pKey Key a buscar y entregarr el objeto.
     * @return List<Object>
     * @throws Exception
     */
    public List<Object> getSaveBeanModifiedRecords(Object pKey) throws Exception {
        List<Object> lObjects = null;
        try {
            SaveBean sb = (SaveBean) super.get(pKey);
            if (sb == null) {
                return lObjects;
            } else {
                lObjects = sb.getModifiedRecords();
            }
            return lObjects;
        } catch (ClassCastException e) {
            return null;
        }

    }

    /**
     * Entrega una Lista de registros marcados para eliminar dado el key.
     * 
     * @param pKey Key a buscar y entregarr el objeto.
     * @return List<Object>
     * @throws Exception
     */
    public List<Object> getSaveBeanDeletedRecords(Object pKey) throws Exception {
        List<Object> lObjects = null;
        try {
            SaveBean sb = (SaveBean) super.get(pKey);
            if (sb == null) {
                return lObjects;
            } else {
                lObjects = sb.getDeletedRecords();
            }
            return lObjects;
        } catch (ClassCastException e) {
            return null;
        }
    }

    /**
     * Entrega el valor de: beans
     * 
     * @return Map<String,SaveBean>
     */
    public Map<String, SaveBean> getBeans() {
        Map<String, SaveBean> beans = new HashMap<String, SaveBean>();
        Set<String> keys = super.keySet();
        for (String key : keys) {
            Object obj = super.get(key);
            if (obj instanceof SaveBean) {
                beans.put(key, (SaveBean) obj);
            }
        }
        return beans;
    }

    /**
     * Metodo que entrega un objeto FinancialRequest, que contiene informacion necesaria para procesar una transaccion
     * financiera.
     * 
     * @return FinancialRequest Dto que permite ejecutar transacciones financieras.
     * @throws Exception
     */
    public FinancialRequest getFinancialRequest() throws Exception {
        FinancialRequest frequest = (FinancialRequest) this.getSaveBeanModifiedObject("FINANCIAL");
        if (frequest == null) {
            return frequest;
        }
        super.completeFinancialRequest(frequest);
        return frequest;
    }

    @Override
    public Set<java.util.Map.Entry<String, Object>> entrySet() {
        super.entrySet();
        super.remove("beans");
        return super.entrySetDefault();
    }

    /**
     * Entrega una lista con el nombre de los SaveBean a realizar sentencias DML en la base de datos.
     * 
     * @return List<String>
     * @throws Exception
     */
    public List<String> getLOrderPersistentBeans() throws Exception {
        return lOrderPersistentBeans;
    }

    /**
     * Entrega el valor de: jsf
     * 
     * @return boolean
     */
    public boolean isJsf() {
        return jsf;
    }

    /**
     * Fija el valor de: jsf
     * 
     * @param Valor a fijar en el atributo.
     */
    public void setJsf(boolean jsf) {
        this.jsf = jsf;
    }

}
