package com.fp.dto;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.fp.common.helper.BeanManager;
import com.fp.dto.fin.FinancialRequest;
import com.fp.dto.hb.HibernateBean;
import com.fp.dto.query.DtoQuery;
import com.fp.dto.save.DtoSave;
import com.fp.dto.save.SaveBean;

/**
 * Requet general utilizado en el procesamiento de transacciones, ejemplo consultas, mantenimiento, reportes financiero.
 * 
 * @author Jorge Vaca .
 * @version 2.1
 */
public class Request extends AbstractData {

    private static final long serialVersionUID = 1L;

    /** Objeto que almacena la respuesta de una consulta. */
    private Response response;

    /** Codigo de usuario que ejecuta una transaccion. */
    protected String user;

    /** Idioma preferido del usuario. */
    /** Codigo interno de usuario que ejecuta una transaccion. */
    protected Integer internalUserCode;

    /**
     * language
     */
    protected String language;

    /** Perfil del Usuario. */
    protected String profile;

    /** Codigo del modulo al que pertenece la transaccion. */
    protected String transactionModule;

    /** Codigo de transaccion a ejecutar. */
    protected Integer transactionCode;

    /** Version de la transaccion a ejecutar. */
    protected Integer transactionVersion;

    /** Codigo de terminal asociado al ip de la maquina desde la cual se ejecuta una transaccion. */
    protected String terminalCode;
    
    /** Nombre de la transaccion*/
    protected String tname;
    
    /** Identificador de la transaccion. */
    protected String journalId;

    /** Codigo de canal desde el cual se ejecuta una transaccion. */
    protected String channelCode;

    /** Codigo de compania. */
    protected Integer company;

    /** Codigo de sucursal origen de la transaccion. */
    protected Integer branchCode;

    /** Codigo de oficina origen de la transaccion. */
    protected Integer officeCode;
    
    /** Codigo de area origen de la transaccion. */
    protected Integer areaCode;

    /** Codigo de usuario que ejecuta una transaccion. */
    protected String authorizedUser;

    /** Numero de cuenta a enviar al log de transacion. */
    protected String logaccount;

    /** Numero de solicitud a enviar al log de transacion. */
    protected String logsolicitude;

    /** Codigo de persona a enviar al log de transacion. */
    protected Integer logperson;
    
    /** Centro de control donde pertenece la persona para enviar al log de transacion. */
    protected String centrocontrol;
    
    /** Unidad de control donde pertenece la persona para enviar al log de transacion. */
    protected String unidad;
    
    /**
     * Subject a presentar en la agenda del usuario.
     */
    protected String subject;

    /** Codigo del modulo original al que pertenece la transaccion. */
    private String originalTransactionModule;

    /** Codigo de transaccion original a ejecutar. */
    private Integer originalTransactionCode;

    /** Version de la transaccion original a ejecutar. */
    private Integer originalTransactionVersion;

    /** Secuencia interna de la transaccion por numero de mensaje. */
    private Integer jounalSequence;

    /** Indica que la transaccion que se esta ejecutando es el linea. */
    private boolean onLine = true;

    /** Navegador utilizado **/
    private String browser;

    /** Sitema operativo utilizado **/
    private String operativesystem;

    /** Cabecera de la transaccion que se esta ejecutando. */
    public Map<String, HibernateBean> mbeans = new HashMap<String, HibernateBean>();

    /**
     * Entrega el valor de subject
     * 
     * @return Valor de subject
     */
    public String getSubject() {
        return this.subject;
    }

    /**
     * Fija un nuevo valor en subject
     * 
     * @param subject nuevo valor para subject
     */
    public void setSubject(String subject) {
        this.subject = subject;
    }

    /**
     * Metodo que copia los valoes del requestq que llega como parametro.
     * 
     * @param pRequest Datos del request a copiar.
     * @throws Exception
     */
    public void copy(Request pRequest) throws Exception {
        this.copyFields(Request.class.getDeclaredFields(), pRequest);
    }

    /**
     * Metodo que copia los valoes del requestq que llega como parametro.
     * 
     * @param pRequest Datos del request a copiar.
     * @throws Exception
     */
    public void copy(GeneralRequest pGeneralRequest) throws Exception {
        this.copyFields(Request.class.getDeclaredFields(), pGeneralRequest);
        // copia los datos del request del que estan el map al request general utilizado en el financiero.
        Set<String> s = super.keySet();
        for (String key : s) {
            pGeneralRequest.put(key, super.get(key));
        }
    }

    /**
     * Metodo que fina el valor en request actual los datos del request que llegan como parametro.
     * 
     * @param pFields Arreglo de campos que formn parte del request.
     * @param pRequest Datos del request original a copiar.
     * @throws Exception
     */
    private void copyFields(Field[] pFields, GeneralRequest pGeneralRequest) throws Exception {
        for (Field f : pFields) {
            try {
                Object value = f.get(this);
                BeanManager.setBeanAttributeValue(pGeneralRequest, f.getName(), value);
            } catch (Exception e) {
                continue;
            }
        }
    }

    /**
     * Metodo que fina el valor en request actual los datos del request que llegan como parametro.
     * 
     * @param pFields Arreglo de campos que formn parte del request.
     * @param pRequest Datos del request original a copiar.
     * @throws Exception
     */
    private void copyFields(Field[] pFields, Request pRequest) throws Exception {
        for (Field f : pFields) {
            try {
                f.set(pRequest, f.get(this));
            } catch (Exception e) {
                continue;
            }
        }
    }

    /**
     * Metodo que copia los valoes del requestq que llega como parametro.
     * 
     * @param pRequest Datos del request a copiar.
     * @throws Exception
     */
    public void copyMapValues(Request pRequest) throws Exception {
        Set<String> s = this.keySet();
        for (String key : s) {
            pRequest.put(key, this.get(key));
        }
    }

    /**
     * Metodo que copia los valoes del requestq que llega como parametro.
     * 
     * @param pRequest Datos del request a copiar.
     * @throws Exception
     */
    public void copyMapValuesWithOutSaveBean(Request pRequest) throws Exception {
        Set<String> s = this.keySet();
        for (String key : s) {
            if(this.get(key) == null || this.get(key) instanceof SaveBean){
                continue;
            }
            pRequest.put(key, this.get(key));
        }
    }

    /**
     * Metodo que completa datos del Request en un financial request.
     * 
     * @param pFinancialRequest Objeto a ser completado con los datos del Request.
     * @throws Exception
     */
    protected void completeFinancialRequest(FinancialRequest pFinancialRequest) throws Exception {
        this.copy(pFinancialRequest);
    }

    /**
     * Metodo que crea y entraga un FinancialRequest dado un SaveRequest.
     * 
     * @return FinancialRequest
     * @throws Exception
     */
    public FinancialRequest toFinancialRequest() throws Exception {
        FinancialRequest financialRequest = new FinancialRequest();
        this.copy(financialRequest);
        return financialRequest;
    }

    /**
     * Entrega el valor de: user
     * 
     * @return String
     */
    public String getUser() {
        return this.user;
    }

    /**
     * Fija el valor de: user
     * 
     * @param user
     */
    public void setUser(String user) {
        this.user = user;
    }

    /**
     * Entrega el valor de: internalUserCode
     * 
     * @return Integer
     */
    public Integer getInternalUserCode() {
        return this.internalUserCode;
    }

    /**
     * Fija el valor de internalUserCode
     * 
     * @param internalUserCode value to set
     */
    public void setInternalUserCode(Integer internalUserCode) {
        this.internalUserCode = internalUserCode;
    }

    /**
     * Entrega el valor de: language
     * 
     * @return String
     */
    public String getLanguage() {
        return this.language;
    }

    /**
     * Fija el valor de: language
     * 
     * @param language
     */
    public void setLanguage(String language) {
        this.language = language;
    }

    /**
     * Entrega el valor de: profile
     * 
     * @return String
     */
    public String getProfile() {
        return this.profile;
    }

    /**
     * Fija el valor de: profile
     * 
     * @param profile
     */
    public void setProfile(String profile) {
        this.profile = profile;
    }

    /**
     * Entrega el valor de: transactionModule
     * 
     * @return String
     */
    public String getTransactionModule() {
        return this.transactionModule;
    }

    /**
     * Fija el valor de: transactionModule
     * 
     * @param transactionModule
     */
    public void setTransactionModule(String transactionModule) {
        this.transactionModule = transactionModule;
    }

    /**
     * Entrega el valor de: transactionCode
     * 
     * @return Integer
     */
    public Integer getTransactionCode() {
        return this.transactionCode;
    }

    /**
     * Fija el valor de: transactionCode
     * 
     * @param transactionCode
     */
    public void setTransactionCode(Integer transactionCode) {
        this.transactionCode = transactionCode;
    }

    /**
     * Entrega el valor de: transactionVersion
     * 
     * @return Integer
     */
    public Integer getTransactionVersion() {
        return this.transactionVersion;
    }

    /**
     * Fija el valor de: transactionVersion
     * 
     * @param transactionVersion
     */
    public void setTransactionVersion(Integer transactionVersion) {
        this.transactionVersion = transactionVersion;
    }

    /**
     * Entrega el valor de: terminalCode
     * 
     * @return String
     */
    public String getTerminalCode() {
        return this.terminalCode;
    }

    /**
     * Fija el valor de: terminalCode
     * 
     * @param terminalCode
     */
    public void setTerminalCode(String terminalCode) {
        this.terminalCode = terminalCode;
    }

    /**
     * Entrega el valor de: journalId
     * 
     * @return String
     */
    public String getJournalId() {
        return this.journalId;
    }

    /**
     * Fija el valor de: journalId
     * 
     * @param journalId
     */
    public void setJournalId(String journalId) {
        this.journalId = journalId;
    }

    /**
     * Entrega el valor de: channelCode
     * 
     * @return String
     */
    public String getChannelCode() {
        return this.channelCode;
    }

    /**
     * Fija el valor de: channelCode
     * 
     * @param channelCode
     */
    public void setChannelCode(String channelCode) {
        this.channelCode = channelCode;
    }

    /**
     * Entrega el valor de: company
     * 
     * @return Integer
     */
    public Integer getCompany() {
        return this.company;
    }

    /**
     * Fija el valor de company
     * 
     * @param company value to set
     */
    public void setCompany(Integer company) {
        this.company = company;
    }

    /**
     * Entrega el valor de: branchCode
     * 
     * @return Integer
     */
    public Integer getBranchCode() {
        return this.branchCode;
    }

    /**
     * Fija el valor de: branchCode
     * 
     * @param branchCode
     */
    public void setBranchCode(Integer branchCode) {
        this.branchCode = branchCode;
    }

    /**
     * Entrega el valor de: officeCode
     * 
     * @return Integer
     */
    public Integer getOfficeCode() {
        return this.officeCode;
    }

    /**
     * Fija el valor de: officeCode
     * 
     * @param officeCode
     */
    public void setOfficeCode(Integer officeCode) {
        this.officeCode = officeCode;
    }
    
    /**
     * Entrega el valor de: areaCode
     * 
     * @return Integer
     */
    public Integer getAreaCode() {
        return this.areaCode;
    }

    /**
     * Fija el valor de: areaCode
     * 
     * @param areaCode
     */
    public void setAreaCode(Integer areaCode) {
        this.areaCode = areaCode;
    }

    /**
     * Entrega el valor de: authorizedUser
     * 
     * @return String
     */
    public String getAuthorizedUser() {
        return this.authorizedUser;
    }

    /**
     * Fija el valor de: authorizedUser
     * 
     * @param authorizedUser
     */
    public void setAuthorizedUser(String authorizedUser) {
        this.authorizedUser = authorizedUser;
    }

    /**
     * Entrega el valor convertido a Bigdecimal de un objeto del map.
     * 
     * @param key Key de la entrada del map.
     * @return BigDecimal
     */
    public BigDecimal getBigDecimal(Object key) {
        if (this.get(key) instanceof Integer) {
            return new BigDecimal((Integer) this.get(key));
        }
        if (this.get(key) instanceof Long) {
            return new BigDecimal((Long) this.get(key));
        }
        if (this.get(key) == null) {
            return BigDecimal.ZERO;
        }
        return (BigDecimal) this.get(key);
    }

    /**
     * Entrega el valor convertido a Bigdecimal de un objeto del map.
     * 
     * @param key Key de la entrada del map.
     * @return BigDecimal
     */
    public Date getDate(Object key) throws ParseException {
        String value = this.getString(key);
        SimpleDateFormat formatt = new SimpleDateFormat("yyyy-MM-dd");
        return new Date(formatt.parse(value).getTime());
    }

    /**
     * Entrega el valor convertido a String de un objeto del map.
     * 
     * @param key Key de la entrada del map.
     * @return String
     */
    public String getString(Object key) {
        Object val = this.get(key);
        if (val == null) {
            throw new RuntimeException("NO SE PUDO DETERMINAR EL VALOR DE " + key);
        }
        return "" + val;
    }

    /**
     * Entrega el valor convertido a String de un objeto del map.
     * 
     * @param key Key de la entrada del map.
     * @return String
     */
    public String findString(Object key) {
        Object val = this.find(key);
        if (val == null) {
            throw new RuntimeException("NO SE PUDO DETERMINAR EL VALOR DE " + key);
        }
        return "" + val;
    }

    /**
     * Entrega el valor de un objeto, busca en el request si no lo encuentra busca en el response.
     * 
     * @param key Key de la entrada del map.
     * @return String
     */
    public Object find(Object key) {
        Object val = this.get(key);
        if ((val == null) && (this.response != null)) {
            val = this.response.get(key);
        }
        return val;
    }

    /**
     * Entrega el valor convertido a long de un objeto del map.
     * 
     * @param key Key de la entrada del map.
     * @return Long
     */
    public Long getLong(Object key) {
        return Long.valueOf(this.getString(key));
    }

    /**
     * Entrega el valor convertido a integer de un objeto del map.
     * 
     * @param key Key de la entrada del map.
     * @return Integer
     */
    public Integer getInteger(Object key) {
        return Integer.valueOf(this.getString(key));
    }

    /**
     * Entrega el valor de: logaccount.
     * 
     * @return String
     */
    public String getLogaccount() {
        return this.logaccount;
    }

    /**
     * Fija el valor de: logaccount.
     * 
     * @param logaccount
     */
    public void setLogaccount(String logaccount) {
        this.logaccount = logaccount;
    }

    /**
     * Entrega el valor de: logsolicitude.
     * 
     * @return String
     */
    public String getLogsolicitude() {
        return this.logsolicitude;
    }

    /**
     * Fija el valor de: logsolicitude.
     * 
     * @param logsolicitude
     */
    public void setLogsolicitude(String logsolicitude) {
        this.logsolicitude = logsolicitude;
    }

    /**
     * Entrega el valor de: logpPerson.
     * 
     * @return Integer
     */
    public Integer getLogperson() {
        return this.logperson;
    }

    /**
     * Fija el valor de: logsolicitude.
     * 
     * @param logsolicitude
     */
    public void setLogperson(Integer logperson) {
        this.logperson = logperson;
    }
    
    /**
     * Entrega el valor de: centrocontrol.
     * 
     * @return String
     */
    public String getCentrocontrol() {
		return centrocontrol;
	}
    
    /**
     * Fija el valor de: centrocontrol.
     * 
     * @param centrocontrol
     */
	public void setCentrocontrol(String centrocontrol) {
		this.centrocontrol = centrocontrol;
	}
	
	/**
     * Entrega el valor de: unidad.
     * 
     * @return String
     */
	public String getUnidad() {
		return unidad;
	}
	
	/**
     * Fija el valor de: unidad.
     * 
     * @param unidad
     */
	public void setUnidad(String unidad) {
		this.unidad = unidad;
	}

    protected Map<String, Object> ruleParameters = new HashMap<String, Object>();

    /**
     * Entrega el valor de ruleParameters
     * 
     * @return Valor de ruleParameters
     */
    public Map<String, Object> getRuleParameters() {
        return this.ruleParameters;
    }

    /**
     * Entrega el valor de: originalTransactionModule
     * 
     * @return String
     */
    public String getOriginalTransactionModule() {
        return this.originalTransactionModule;
    }

    /**
     * Fija el valor de: originalTransactionModule
     * 
     * @param originalTransactionModule
     */
    public void setOriginalTransactionModule(String originalTransactionModule) {
        this.originalTransactionModule = originalTransactionModule;
    }

    /**
     * Entrega el valor de: originalTransactionCode
     * 
     * @return Integer
     */
    public Integer getOriginalTransactionCode() {
        return this.originalTransactionCode;
    }

    /**
     * Fija el valor de: originalTransactionCode
     * 
     * @param originalTransactionCode
     */
    public void setOriginalTransactionCode(Integer originalTransactionCode) {
        this.originalTransactionCode = originalTransactionCode;
    }

    /**
     * Entrega el valor de: originalTransactionVersion
     * 
     * @return Integer
     */
    public Integer getOriginalTransactionVersion() {
        return this.originalTransactionVersion;
    }

    /**
     * Fija el valor de: originalTransactionVersion
     * 
     * @param originalTransactionVersion
     */
    public void setOriginalTransactionVersion(Integer originalTransactionVersion) {
        this.originalTransactionVersion = originalTransactionVersion;
    }

    /**
     * Entrega el valor de: jounalSequence
     * 
     * @return Integer
     */
    public Integer getJounalSequence() {
        return this.jounalSequence;
    }

    /**
     * Fija el valor de jounalSequence
     * 
     * @param jounalSequence value to set
     */
    public void setJounalSequence(Integer jounalSequence) {
        this.jounalSequence = jounalSequence;
    }

    /**
     * Entrega el valor de: onLine
     * 
     * @return boolean
     */
    public boolean isOnLine() {
        return this.onLine;
    }

    /**
     * Fija el valor de: onLine
     * 
     * @param onLine
     */
    public void setOnLine(boolean onLine) {
        this.onLine = onLine;
    }

    /**
     * Fija un nuevo valor en ruleParameters
     * 
     * @param pRuleParameters nuevo valor para ruleParameters
     */
    public void setRuleParameters(Map<String, Object> pRuleParameters) {
        this.ruleParameters = pRuleParameters;
    }

    public void addRuleParameter(String pName, Object pValue) {
        this.ruleParameters.put(pName, pValue);
    }

    public void cleanRuleParameters() {
        this.ruleParameters = new HashMap<String, Object>();
    }

    public void addRuleParameter(String pNameValue) {
        String[] val = pNameValue.split(",");
        this.ruleParameters.put(val[0], val[1]);
    }

    public String getRuleParameterString(String pKey) {
        return "" + this.ruleParameters.get(pKey);
    }

    public boolean getRuleParameterIsYes(String pKey) {
        return "Y".compareTo(this.getRuleParameterString(pKey)) == 0;
    }

    public BigDecimal getRuleParameterBigDecimal(String pKey) {
        return new BigDecimal(this.getRuleParameterString(pKey));
    }

    public Integer getRuleParameterInteger(String pKey) {
        return Integer.valueOf(this.getRuleParameterString(pKey));
    }

    /**
     * Entrega el valor de: QueryRequest.java
     * 
     * @return Response
     */
    public Response getResponse() {
        return this.response;
    }

    /**
     * Fija el valor de: response
     * 
     * @param response Valor a almacenar
     */
    public void setResponse(Response response) {
        this.response = response;
    }

    /**
     * Filja map con tablas a consultar.
     * 
     * @param mquerytables
     * @throws Exception
     */
    public void setQueryTables(HashMap<String, DtoQuery> mquerytables) throws Exception {
        this.put("MQUERY", mquerytables);
    }

    /**
     * Entrega un map con la metadata de tablas a consultar.
     * 
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public HashMap<String, DtoQuery> getQueryTables() throws Exception {
        return (HashMap<String, DtoQuery>) this.get("MQUERY");
    }

    /**
     * Filja map con tablas a dar mantenimiento.
     * 
     * @param msavetables
     * @throws Exception
     */
    public void setSaveTables(HashMap<String, DtoSave> msavetables) throws Exception {
        this.put("MSAVE", msavetables);
    }

    /**
     * Entrega un map con la metadata de tablas a dar mantenimiento.
     * 
     * @return HashMap<String, DtoSave>
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public HashMap<String, DtoSave> getSaveTables() throws Exception {
        return (HashMap<String, DtoSave>) this.get("MSAVE");
    }

    /**
     * Entrega la descripcion del navegador
     * 
     * @return browser
     */
    public String getBrowser() {
        return browser;
    }

    /**
     * Fija la descripcion del navegador
     * 
     * @param browser
     */
    public void setBrowser(String browser) {
        this.browser = browser;
    }

    /**
     * Entrega la descripcion del sistema operativo
     * 
     * @return operativesystem
     */
    public String getOperativesystem() {
        return operativesystem;
    }

    /**
     * Fija la descripcion del sistema operativo
     * 
     * @param operativesystem
     */
    public void setOperativesystem(String operativesystem) {
        this.operativesystem = operativesystem;
    }
    /**
     * Entrega el nombre de la transaccion
     * @return tname
     */
	public String getTname() {
		return tname;
	}
	/**
	 * Fija el nombre de la transaccion
	 * @param tname
	 */
	public void setTname(String tname) {
		this.tname = tname;
	}	
    
}
