package com.fp.frontend.controller.pcustomer;

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

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

import com.fp.common.helper.Constant;
import com.fp.dto.AbstractDataTransport;
import com.fp.dto.Request;
import com.fp.dto.Response;
import com.fp.dto.query.DtoQuery;
import com.fp.dto.query.Filter;
import com.fp.dto.query.SubQuery;
import com.fp.dto.save.DtoSave;
import com.fp.frontend.controller.AbstractController;
import com.fp.frontend.controller.pgeneral.gene.CantonController;
import com.fp.frontend.controller.pgeneral.gene.CatalogDetailController;
import com.fp.frontend.controller.pgeneral.gene.CityController;
import com.fp.frontend.controller.pgeneral.gene.CountryController;
import com.fp.frontend.controller.pgeneral.gene.ParroquiaController;
import com.fp.frontend.controller.pgeneral.gene.ProvinceController;
import com.fp.frontend.helper.MessageHelper;
import com.fp.persistence.pcustomer.company.TcustCompany;
import com.fp.persistence.pcustomer.gene.TcustPersonAddress;
import com.fp.persistence.pcustomer.gene.TcustPersonAddressKey;
import com.fp.persistence.pgeneral.gene.TgeneCanton;
import com.fp.persistence.pgeneral.gene.TgeneCatalogDetail;
import com.fp.persistence.pgeneral.gene.TgeneCity;
import com.fp.persistence.pgeneral.gene.TgeneCountry;
import com.fp.persistence.pgeneral.gene.TgeneParroquia;
import com.fp.persistence.pgeneral.gene.TgeneProvince;

/**
 * Clase controladora del bean TcustPersonAddress.
 *
 * @author WPA.
 * @version 2.1
 */
@ManagedBean
@ViewScoped
public class PersonAddressController extends AbstractController<TcustPersonAddress> {

    private static final long serialVersionUID = 1L;

    public PersonAddressController() throws Exception {
        super(TcustPersonAddress.class);
    }

    /**
     * Atributo para la lista de objetos TgeneCatalogDetail
     */
    private List<TgeneCatalogDetail> laddresstype;

    /**
     * Atributo para la lista de objetos TgeneCatalogDetail
     */
    private List<TgeneCountry> lcountries;

    /**
     * Atributo para la lista de objetos TgeneProvince
     */
    private List<TgeneProvince> lprovinces;

    /**
     * Atributo para la lista de objetos TgeneProvince
     */
    private List<TgeneCanton> lcantones;

    /**
     * Atributo para la lista de objetos TgeneProvince
     */
    private List<TgeneParroquia> lparroquias;

    /**
     * Atributo para la lista de objetos TgeneProvince
     */
    private List<TgeneCity> lcities;

    /**
     * Atributo para el control de checkBox de principal
     */
    private boolean principal;

    /**
     * Atributo para el c&oacute;digo de persona
     */
    private Integer personcode;

    private boolean typeaddress;

    @PostConstruct
    private void postconstruct() {
        this.init();
        // Inicializa autoconsulta
        super.startQuery();
        laddresstype = CatalogDetailController.find("ADDRESSTYPE");
        lcountries = CountryController.find();
    }

    /**
     * Incializa el controlador, cuando se esta utilizando una pagina que utliza
     * el controlador.
     */
    private void init() {
        try {
            recperpage = 10; // Cambiar al # reg a mirar.
            lrecord = new ArrayList<>();
            record = new TcustPersonAddress();
            record.setPk(new TcustPersonAddressKey());
            beanalias = "TCUSTPERSONADDRESS";
        } catch (Exception e) {
            MessageHelper.setMessageError(e);
        }
    }

    /**
     * Agrega un par&acute;metro para la conulta
     *
     * @param personcode C&oacute;digo de persona
     */
    public void addPersoncodeFilter(String personcode) {
        this.personcode = new Integer(personcode);
        super.addFilter("pk.personcode", personcode);
    }

    /**
     * M&eacute;todo para armar la consulta
     *
     * @return dto Objeto DtoQuery
     * @throws Exception
     */
    public DtoQuery getDtoQuery() throws Exception {
        super.addFilterDateto();
        DtoQuery dto = super.getDtoQuery(true);
        dto.setOrderby("t.pk.addressnumber"); // En en string van todos los campos de
        // orden ("t.pk,  t.nombre, t.cpais").
        // subqueries
        SubQuery subquery = new SubQuery("TgeneCatalogDetail", "description", "addresstype",
                "i.pk.catalogcode = t.addresstypecatalogcode and i.pk.catalog = t.addresstypecatalog");
        dto.addSubQuery(subquery);

        SubQuery subqueryProvincia = new SubQuery("TgeneProvince", "description", "provincia",
                "i.pk.provincecode = t.provincecode and i.pk.countrycode = t.countrycode");
        dto.addSubQuery(subqueryProvincia);

        SubQuery subqueryCanton = new SubQuery("TgeneCanton", "description", "canton",
                "i.pk.provincecode = t.provincecode and i.pk.countrycode = t.countrycode  and i.pk.cantoncode=t.cantoncode");
        dto.addSubQuery(subqueryCanton);

        SubQuery subqueryCiudad = new SubQuery("TgeneCity", "description", "ciudad",
                "i.pk.provincecode = t.provincecode and i.pk.countrycode = t.countrycode  and i.pk.cantoncode=t.cantoncode and i.pk.citycode=t.citycode");
        dto.addSubQuery(subqueryCiudad);

        SubQuery subqueryParroquia = new SubQuery("TgeneParroquia", "description", "parroquia",
                "i.pk.provincecode = t.provincecode and i.pk.countrycode = t.countrycode  and i.pk.cantoncode=t.cantoncode and i.pk.parroquiacode=t.parroquiacode");
        dto.addSubQuery(subqueryParroquia);

        return dto;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void querydatabase() {
        try {
            DtoQuery dto = super.getDtoQuery(true);
            super.addFilterDateto();

            //Cargando el tipo de direccion
            SubQuery subQueryTipoDireccion = new SubQuery("TgeneCatalogDetail", "description",
                    "addresstype", "i.pk.catalog=t.addresstypecatalog and i.pk.catalogcode=t.addresstypecatalogcode");
            dto.addSubQuery(subQueryTipoDireccion);

            SubQuery subqueryProvincia = new SubQuery("TgeneProvince", "description", "provincia",
                    "i.pk.provincecode = t.provincecode and i.pk.countrycode = t.countrycode");
            dto.addSubQuery(subqueryProvincia);

            SubQuery subqueryCanton = new SubQuery("TgeneCanton", "description", "canton",
                    "i.pk.provincecode = t.provincecode and i.pk.countrycode = t.countrycode  and i.pk.cantoncode=t.cantoncode");
            dto.addSubQuery(subqueryCanton);

            SubQuery subqueryCiudad = new SubQuery("TgeneCity", "description", "ciudad",
                    "i.pk.provincecode = t.provincecode and i.pk.countrycode = t.countrycode  and i.pk.cantoncode=t.cantoncode and i.pk.citycode=t.citycode");
            dto.addSubQuery(subqueryCiudad);

            SubQuery subqueryParroquia = new SubQuery("TgeneParroquia", "description", "parroquia",
                    "i.pk.provincecode = t.provincecode and i.pk.countrycode = t.countrycode  and i.pk.cantoncode=t.cantoncode and i.pk.parroquiacode=t.parroquiacode");
            dto.addSubQuery(subqueryParroquia);

            HashMap<String, DtoQuery> mtables = new HashMap<String, DtoQuery>();
            mtables.put(beanalias, dto); // permite adicionar mas de una tabla.

            Request request = this.callerhelper.getRequest();
            request.setQueryTables(mtables);

            Response resp = this.callerhelper.executeQuery(request);

            if (resp.getResponseCode().compareTo(Response.RESPONSE_OK) != 0) {
                lrecord = new ArrayList<TcustPersonAddress>();
                MessageHelper.setMessageError(resp);
            } else {
                lrecord = (List<TcustPersonAddress>) resp.get(beanalias);
                if (lrecord != null && !lrecord.isEmpty()) {
                    record = lrecord.get(0);
                }
                super.postQuery(lrecord);
            }
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
        }
    }

    @SuppressWarnings("unchecked")
    protected void querydatabaseAll() {
        try {
            DtoQuery dto = super.getDtoQuery(true);
            HashMap<String, DtoQuery> mtables = new HashMap<String, DtoQuery>();
            mtables.put(beanalias, dto); // permite adicionar mas de una tabla.

            Request request = callerhelper.getRequest();
            request.setQueryTables(mtables);

            Response resp = callerhelper.executeQuery(request);

            if (resp.getResponseCode().compareTo(Response.RESPONSE_OK) != 0) {
                lrecord = new ArrayList<TcustPersonAddress>();
                MessageHelper.setMessageError(resp);
            } else {
                lrecord = (List<TcustPersonAddress>) resp.get(beanalias);
                super.postQuery(lrecord);
            }

        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
        }
    }

    /**
     * Controla la respuesta de la consulta
     *
     * @param resp Objeto Response
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public void manageResponseAddress(Response resp) throws Exception {
        if (resp.getResponseCode().compareTo(Response.RESPONSE_OK) != 0) {
            lrecord = new ArrayList<>();
            MessageHelper.setMessageError(resp);
        } else {
            lrecord = (List<TcustPersonAddress>) resp.get(beanalias);
            super.postQuery((List<AbstractDataTransport>) resp.get(beanalias));
        }
    }

    @Override
    public void save() {
        try {
            Request request = callerhelper.getRequest();
            DtoSave dtosave = super.getDtoSave();
            if (!dtosave.pendingProcess()) {
                return;
            }
            HashMap<String, DtoSave> msave = new HashMap<String, DtoSave>();
            msave.put(beanalias, dtosave); // adicionar metadata de
            // mantenimiento para cada
            // tabla.

            request.setSaveTables(msave);
            Response resp = callerhelper.executeSave(request);
            if (resp.getResponseCode().compareTo(Response.RESPONSE_OK) == 0) {
                this.postCommit(resp);
                MessageHelper.setMessageInfo(resp);
            } else {
                MessageHelper.setMessageError(resp);
            }

        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
        }
    }

    public TcustPersonAddress findPersonaPorDireccionTipoCatalogo(String codigopersona, String direcciontipoCatalogo) {
        try {
            PersonAddressController cc = new PersonAddressController();
            cc.init();
            cc.recperpage = 300;
            cc.addFilter("pk.personcode", codigopersona);
            cc.addFilter("addresstypecatalog", direcciontipoCatalogo);
            cc.addFilterDateto();
            cc.querydatabaseAll();
            if ((cc.lrecord != null) && !cc.lrecord.isEmpty()) {
                record = cc.lrecord.get(0);
                lprovinces = ProvinceController.findPorCodigo(record.getCountrycode(), record.getProvincecode());
                lcantones = CantonController.findPorCodigo(record.getCountrycode(), record.getProvincecode(), record.getCantoncode());
                lcities = CityController.findPorCodigo(record.getCountrycode(), record.getProvincecode(), record.getCantoncode(), record.getCitycode());
                lparroquias = ParroquiaController.find(record.getCountrycode(), record.getProvincecode(), record.getCantoncode());
                return record;
            }
            return null;
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
            return null;
        }
    }

    public TcustPersonAddress findByPersonCode(String codigopersona, String codigoCorreo) {
        try {
            PersonAddressController cc = new PersonAddressController();
            cc.init();
            cc.recperpage = 300;
            cc.addFilter("pk.personcode", codigopersona);
            cc.addFilter("addresstypecatalog", codigoCorreo);
            cc.addFilterDateto();
            cc.querydatabaseAll();
            if ((cc.lrecord != null) && !cc.lrecord.isEmpty()) {
                record = cc.lrecord.get(0);
                lprovinces = ProvinceController.findPorCodigo(record.getCountrycode(), record.getProvincecode());
                lcantones = CantonController.findPorCodigo(record.getCountrycode(), record.getProvincecode(), record.getCantoncode());
                lcities = CityController.findPorCodigo(record.getCountrycode(), record.getProvincecode(), record.getCantoncode(), record.getCitycode());
                lparroquias = ParroquiaController.find(record.getCountrycode(), record.getProvincecode(), record.getCantoncode());
                return record;
            }
            return null;
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
            return null;
        }
    }
    
    public static List<TcustPersonAddress> findByPersonCodeList(String codigopersona, String codigoCorreo) {
        try {
            PersonAddressController cc = new PersonAddressController();
            cc.init();
            cc.recperpage = 300;
            cc.addFilter("pk.personcode", codigopersona);
            cc.addFilter("addresstypecatalog", codigoCorreo);
            cc.addFilterDateto();
            cc.querydatabaseAll();
            if ((cc.lrecord != null) && !cc.lrecord.isEmpty()) {
                return cc.lrecord;
            }
            return null;
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
            return null;
        }
    }

    /**
     * Obtiene todas las direcciones de una persona
     *
     * @param codigopersona
     * @return
     */
    public static List<TcustPersonAddress> findAllByPersonCode(String codigopersona) {
        try {
            PersonAddressController cc = new PersonAddressController();
            cc.init();
            cc.recperpage = 300;
            cc.addFilter("pk.personcode", codigopersona);
            cc.addFilter("pk.dateto", "2999-12-31");
            cc.querydatabase();
            if ((cc.lrecord != null) && !cc.lrecord.isEmpty()) {
                return cc.lrecord;
            }
            return null;
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
            return null;
        }
    }

    /**
     * Metodo que retorna la direccion que sea diferente a la del mail
     *
     * @param codigopersona
     * @param direcciontipoCatalogo
     * @return
     */
    public static TcustPersonAddress findDifAMail(String codigopersona, String direcciontipoCatalogo) {
        try {
            PersonAddressController cc = new PersonAddressController();
            cc.init();
            cc.recperpage = 300;
            cc.addFilter("pk.personcode", codigopersona);
            cc.addFilter("addresstypecatalog", "!=" + direcciontipoCatalogo);
            cc.querydatabaseAll();
            if ((cc.lrecord != null) && !cc.lrecord.isEmpty()) {
                return cc.lrecord.get(0);
            }
            return null;
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
            return null;
        }
    }

    /**
     * Retorna la direcci&oacute;n marcada como principal
     *
     * @param codigoPersona
     * @return
     */
    public TcustPersonAddress findPrincipal(String codigoPersona) {
        try {
            PersonAddressController cc = new PersonAddressController();
            cc.init();
            cc.recperpage = 300;
            cc.addFilter("pk.personcode", codigoPersona);
            cc.addFilter("principal", Constant.STR_Y);
            cc.addFilterDateto();
            cc.querydatabase();
            if ((cc.lrecord != null) && !cc.lrecord.isEmpty()) {
                return cc.lrecord.get(0);
            }
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
        }
        return null;
    }

    /**
     * Retorna la direcci&oacute;n marcada como principal
     *
     * @param codigoPersona
     * @return
     */
    public static TcustPersonAddress find(String codigoPersona) {
        try {
            PersonAddressController cc = new PersonAddressController();
            cc.init();
            cc.recperpage = 300;
            cc.addFilter("pk.personcode", codigoPersona);
            cc.addFilter("principal", Constant.STR_Y);
            cc.addFilterDateto();
            cc.querydatabase();
            if ((cc.lrecord != null) && !cc.lrecord.isEmpty()) {
                return cc.lrecord.get(0);
            }
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
        }
        return null;
    }

    @Override
    public void postCommit(Response response) throws Exception {
        super.postCommitGeneric(response, beanalias);
    }

    /**
     * M&eacute;todo para el evento change del combo pa&iacute;ses
     */
    public void executeCountry() {
        if ((record.getCountrycode() != null) && (record.getCountrycode().compareTo("") != 0)) {
            lprovinces = ProvinceController.find(record.getCountrycode());
            lcantones = new ArrayList<>();
            lparroquias = new ArrayList<>();
            lcities = new ArrayList<>();
        }
    }

    /**
     * M&eacute;todo para el evento change del combo provincias
     */
    public void executeProvince() {
        if ((record.getCountrycode() != null) && (record.getCountrycode().compareTo("") != 0)) {
            lcantones = CantonController.find(record.getCountrycode(), record.getProvincecode());
            lparroquias = new ArrayList<>();
            lcities = new ArrayList<>();
        }
    }

    /**
     * M&eacute;todo para el evento change del combo cantones
     */
    public void executeCanton() {
        if ((record.getCountrycode() != null) && (record.getCountrycode().compareTo("") != 0)) {
            lparroquias = ParroquiaController.find(record.getCountrycode(), record.getProvincecode(), record.getCantoncode());
            lcities = CityController.find(record.getCountrycode(), record.getProvincecode(), record.getCantoncode());
        }
    }

    /**
     * M&eacute;todo para cargar datos en el editar
     */
    public void loadEdit() {
        this.onChangeType();
        principal = ((record.getPrincipal() != null) && record.getPrincipal().equals("Y") ? true : false);
        lprovinces = ProvinceController.find(record.getCountrycode());
        lcantones = CantonController.find(record.getCountrycode(), record.getProvincecode());
        lparroquias = ParroquiaController.find(record.getCountrycode(), record.getProvincecode(), record.getCantoncode());
        lcities = CityController.find(record.getCountrycode(), record.getProvincecode(), record.getCantoncode());
    }

    /**
     * M&eacute;todo para manejar el evento change en el CheckBox
     */
    public void onChangePrincipal() {
        if (principal) {
            record.setPrincipal("Y");
        } else {
            record.setPrincipal("N");
        }
    }

    @Override
    public void update() {
        try {

//            record.getPk().setPersoncode(((personcode == null) || personcode.equals(0)) ? null : personcode);
            /*
            if ((personcode == null) || (personcode == 0)) {
                record.getPk().setAddressnumber(this.getMaxNumber());
            }
            if(record.isnew){
            	record.getPk().setAddressnumber(this.getMaxNumber());
            }
             */
            record.setAddresstypecatalogcode("ADDRESSTYPE");
            for (TgeneCatalogDetail detail : laddresstype) {
                if (detail.getPk().getCatalog().equals(record.getAddresstypecatalog())) {
                    record.modifiedData.put("addresstype", detail.getDescription());
                }
            }
            super.update();
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
        }
    }

    /**
     * M&eacute;todo que obtiene el max de direcciones
     *
     * @return max N&uacute;mero max
     */
    private Integer getMaxNumber() {
        Integer max = 0;
        if (lrecord.size() > 0) {
            for (TcustPersonAddress address : lrecord) {
                if (max.compareTo(address.getPk().getAddressnumber()) < 0) {
                    max = address.getPk().getAddressnumber();
                }
            }
        }
        return max + 1;
    }

    /**
     * M&eacute;todo para manejar el evento change en el combo tipod e
     * direcci&oacute;n
     */
    public void onChangeType() {
        if (record.getAddresstypecatalog().compareTo("3") == 0) {
            typeaddress = true;
        } else {
            typeaddress = false;
        }
    }

    /**
     * Entrega una lista de objetos TgeneCatalogDetail tipo de direcciones
     *
     * @return laddresstype Lista de objetos TgeneCatalogDetail tipo de
     * direcciones
     */
    public List<TgeneCatalogDetail> getLaddresstype() {
        return laddresstype;
    }

    /**
     * Fija una lista de objetos TgeneCatalogDetail tipo de direcciones
     *
     * @param laddresstype Lista de objetos TgeneCatalogDetail tipo de
     * direcciones
     */
    public void setLaddresstype(List<TgeneCatalogDetail> laddresstype) {
        this.laddresstype = laddresstype;
    }

    /**
     * Entrega una lista de objetos TgeneCountry pa&iacute;ses
     *
     * @return lcountries Lista de objetos TgeneCountry
     */
    public List<TgeneCountry> getLcountries() {
        return lcountries;
    }

    /**
     * Fija una lista de objetos TgeneCountry pa&iacute;ses
     *
     * @param lcountries Lista de objetos TgeneCountry
     */
    public void setLcountries(List<TgeneCountry> lcountries) {
        this.lcountries = lcountries;
    }

    /**
     * Entrega una lista de objetos TgeneProvince provincias
     *
     * @return lprovinces Lista de objetos TgeneProvince
     */
    public List<TgeneProvince> getLprovinces() {
        return lprovinces;
    }

    /**
     * Fija una lista de objetos TgeneProvince provincias
     *
     * @param lprovinces Lista de objetos TgeneProvince
     */
    public void setLprovinces(List<TgeneProvince> lprovinces) {
        this.lprovinces = lprovinces;
    }

    /**
     * Entrega una lista de objetos TgeneCanton cantones
     *
     * @return lcantones Lista de objetos TgeneCanton
     */
    public List<TgeneCanton> getLcantones() {
        return lcantones;
    }

    /**
     * Fija una lista de objetos TgeneCanton cantones
     *
     * @param lcantones Lista de objetos TgeneCanton
     */
    public void setLcantones(List<TgeneCanton> lcantones) {
        this.lcantones = lcantones;
    }

    /**
     * Entrega una lista de objetos TgeneParroquia parroquias
     *
     * @return lparroquias Lista de objetos TgeneParroquia
     */
    public List<TgeneParroquia> getLparroquias() {
        return lparroquias;
    }

    /**
     * Fija una lista de objetos TgeneParroquia parroquias
     *
     * @param lparroquias Lista de objetos TgeneParroquia
     */
    public void setLparroquias(List<TgeneParroquia> lparroquias) {
        this.lparroquias = lparroquias;
    }

    /**
     * Entrega una lista de objetos TgeneCity ciudades
     *
     * @return lcities Lista de objetos TgeneCity
     */
    public List<TgeneCity> getLcities() {
        return lcities;
    }

    /**
     * Fija una lista de objetos TgeneCity ciudades
     *
     * @param lcities Lista de objetos TgeneCity
     */
    public void setLcities(List<TgeneCity> lcities) {
        this.lcities = lcities;
    }

    /**
     * Entrega Verdadero o Falso
     *
     * @return principal V/F
     */
    public boolean isPrincipal() {
        return principal;
    }

    /**
     * Fija Verdadero o Falso
     *
     * @param principal V/F
     */
    public void setPrincipal(boolean principal) {
        this.principal = principal;
    }

    /**
     * Entrega el c&oacute;digo de persona
     *
     * @return personcode C&oacute;digo de persona
     */
    public Integer getPersoncode() {
        return personcode;
    }

    /**
     * Fija el c&oacute;digo de persona
     *
     * @param personcode C&oacute;digo de persona
     */
    public void setPersoncode(Integer personcode) {
        this.personcode = personcode;
    }

    /**
     * Entrega Verdadero o Falso
     *
     * @return typeaddress V/F
     */
    public boolean isTypeaddress() {
        return typeaddress;
    }

    /**
     * Fija Verdadero o Falso
     *
     * @param typeaddress V/F
     */
    public void setTypeaddress(boolean typeaddress) {
        this.typeaddress = typeaddress;
    }

}
