/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.arrebol.taxiservicios.beans.admin.taxi;

import com.arrebol.taxiservicios.beans.TaxiGenericBean;
import com.arrebol.taxiservicios.controller.admin.ReleaseResourceController;
import com.arrebol.taxiservicios.controller.admin.TaxiController;
import com.arrebol.taxiservicios.controller.util.DateWrapper;
import com.arrebol.taxiservicios.model.admin.Contract;
import com.arrebol.taxiservicios.model.admin.ContractHasService;
import com.arrebol.taxiservicios.model.admin.ReleaseResource;
import com.arrebol.taxiservicios.model.admin.Service;
import com.arrebol.taxiservicios.model.admin.Taxi;
import com.arrebol.taxiservicios.model.catalog.Color;
import com.arrebol.taxiservicios.model.catalog.Vehicle;
import com.arrebol.taxiservicios.model.core.Person;
import com.arrebol.taxiservicios.model.core.User;
import com.arrebol.taxiservicios.model.enums.BasicType;
import com.arrebol.taxiservicios.model.enums.GenericEnumType;
import com.arrebol.taxiservicios.model.enums.PlatformType;
import com.arrebol.taxiservicios.wrapper.ContractTaxiTreeNodeWrapper;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.DualListModel;
import org.primefaces.model.TreeNode;

/**
 *
 * @author oscarvargas
 */
@Named("taxiEditBean")
@ViewScoped
public class TaxiEditBean extends TaxiGenericBean implements Serializable {

    public void updateWeekWork() {
        logger.info("updateWeekWork");
        try {
            if (isMonday() || isTuesday() || isWednesday() || isThursday() || isFriday() || isSaturday() || isSunday()) {
                PlatformType platformType = null;

                for (PlatformType pf : PlatformType.values()) {
                    if (getPlatform().equals(pf.toString())) {
                        platformType = pf;
                        break;
                    }
                }

                if (getController().updateWeekWorkTaxiById(getTaxi().getId(), getLoggedUser().getId(), platformType,
                        isMonday(), isTuesday(), isWednesday(), isThursday(), isFriday(), isSaturday(), isSunday())) {
                    showMessage(FacesMessage.SEVERITY_INFO,
                            getBundlePropertyFile().getString("taxi.add.title"),
                            getBundlePropertyFile().getString("taxi.add.week.work.success.desc"));
                } else {
                    logger.error("updateWeekWork: error week work.");
                    showMessage(FacesMessage.SEVERITY_ERROR,
                            getBundlePropertyFile().getString("taxi.add.title"),
                            getBundlePropertyFile().getString("taxi.add.exception.desc"));
                }
            } else {
                logger.error("updateWeekWork: select at lease one day of te week.");
                showMessage(FacesMessage.SEVERITY_ERROR,
                        getBundlePropertyFile().getString("taxi.add.title"),
                        getBundlePropertyFile().getString("taxi.add.week.work.exception.desc"));
            }
        } catch (Exception e) {
            logger.error("updateWeekWork: " + e);
            showMessage(FacesMessage.SEVERITY_FATAL,
                    getBundlePropertyFile().getString("taxi.add.title"),
                    getBundlePropertyFile().getString("taxi.add.exception.desc"));
        }
    }

    /**
     * Delete all services that a contract has and the contract.
     *
     * @param contractId Contract Identification number.
     */
    public void deleteContract(String contractId) {
        logger.info("deleteContract");
        try {
            if (getController().deleteContractAndContractDetailsById(new Contract(contractId))) {
                initContractDetails();
                showMessage(FacesMessage.SEVERITY_INFO,
                        getBundlePropertyFile().getString("taxi.edit.title"),
                        getBundlePropertyFile().getString("taxi.delete.contract.success.desc"));

            } else {
                logger.error("Taxi " + getTaxi() + " was not updated");
                showMessage(FacesMessage.SEVERITY_ERROR,
                        getBundlePropertyFile().getString("taxi.edit.title"),
                        getBundlePropertyFile().getString("tax.delete.contract.fail.desc"));
            }
        } catch (Exception e) {
            logger.error("editTaxi: " + e);
            showMessage(FacesMessage.SEVERITY_FATAL,
                    getBundlePropertyFile().getString("taxi.edit.title"),
                    getBundlePropertyFile().getString("taxi.delete.contract.exception.desc"));
        }
    }

    public void editTaxi() {
        logger.info("editTaxi");
        try {
            Person oldDriver = null;
            Taxi tmp = getController().getDriverByTaxiId(getTaxi().getId());

            if (null != tmp && null != tmp.getDriver()) {
                oldDriver = tmp.getDriver();
            }
            
            if(gps)
            {
                getTaxi().setGps(BasicType.ENEBLED);
            }
            else
            {
                getTaxi().setGps(BasicType.DISABLED);
            }
            
            if(apc)
            {
                getTaxi().setApc(BasicType.ENEBLED);
            }
            else
            {
                getTaxi().setApc(BasicType.DISABLED);
            }

            boolean success = getController().updateTaxiById(
                    getTaxi(), getVehicleId(), getDriverId(), getCustomerId(), getColorId());

            if (success) {
                releaseResource(oldDriver);
                showMessage(FacesMessage.SEVERITY_INFO,
                        getBundlePropertyFile().getString("taxi.edit.title"),
                        getBundlePropertyFile().getString("taxi.edit.success.desc"));
            } else {
                logger.error("Taxi " + getTaxi() + " was not updated");
                showMessage(FacesMessage.SEVERITY_ERROR,
                        getBundlePropertyFile().getString("taxi.edit.title"),
                        getBundlePropertyFile().getString("tax.edit.fail.desc"));
            }
        } catch (Exception e) {
            logger.error("editTaxi: " + e);
            showMessage(FacesMessage.SEVERITY_FATAL,
                    getBundlePropertyFile().getString("taxi.edit.title"),
                    getBundlePropertyFile().getString("taxi.edit.exception.desc"));
        }
    }

    /**
     * Create a contract with all selected services for the current taxi.
     */
    public void saveContract() {
        logger.info("saveContract");
        try {
            List<Service> target = new ArrayList<>();
            float price = 0f;

            for (Service service : getServices().getTarget()) {
                if (!service.isDisable()) {
                    target.add(service);
                    price = price + service.getCharge();
                }
            }

            if (!target.isEmpty()) {
                Calendar calendar = Calendar.getInstance();

                calendar.setTime(getStartDate());
                calendar.add(Calendar.YEAR, 1);

                setContract(new Contract());

                getContract().setId(UUID.randomUUID().toString());
                getContract().setStartDate(getStartDate());
                getContract().setEndDate(calendar.getTime());
                getContract().setPrice(price);
                getContract().setActive(true);
                getContract().setTaxi(new Taxi(getTaxi().getId()));
                getContract().setCreatedOn(new Date());
                getContract().setName(getTaxi().getEconomicNumber()
                        + " - "
                        + (numberContract++));
                getContract().setCreatedBy(
                        new User(
                                getLoggedUser().getId(), getLoggedUser().getUserName()
                        )
                );

                boolean success = getController().saveContract(getContract(), target);

                if (success) {
                    getServices().getTarget().forEach((Service srv) -> {
                        srv.setDisable(true);
                    });
                    fillTreeTable(target);
                    showMessage(FacesMessage.SEVERITY_INFO,
                            getBundlePropertyFile().getString("taxi.contract.add.title"),
                            getBundlePropertyFile().getString("taxi.contract.add.success.desc"));
                } else {
                    logger.error("Contract was not saved " + contract);
                    showMessage(FacesMessage.SEVERITY_ERROR,
                            getBundlePropertyFile().getString("taxi.contract.add.title"),
                            getBundlePropertyFile().getString("taxi.contract.add.fail.desc"));
                }
            } else {
                showMessage(FacesMessage.SEVERITY_ERROR,
                        getBundlePropertyFile().getString("taxi.contract.add.title"),
                        getBundlePropertyFile().getString("empty.contract"));
            }
        } catch (Exception e) {
            logger.error("saveContract: " + e);
            showMessage(FacesMessage.SEVERITY_FATAL,
                    getBundlePropertyFile().getString("taxi.contract.add.title"),
                    getBundlePropertyFile().getString("taxi.contract.add.exception.desc"));
        }
    }

    public void printContracts() {

    }

    /**
     * Fill the tree table with the new Contract and all its services.
     *
     * @param services Services that contract has.
     */
    private void fillTreeTable(List<Service> services) {

        TreeNode node = new DefaultTreeNode(
                new ContractTaxiTreeNodeWrapper(
                        getContract().getId(),
                        getContract().getName(),
                        getContract().getEndDate(),
                        getContract().getPrice(),
                        true
                ),
                getRoot()
        );

        services.forEach((Service service) -> {
            TreeNode tn = new DefaultTreeNode(
                    new ContractTaxiTreeNodeWrapper(
                            "",
                            service.getName(),
                            null,
                            service.getCharge(),
                            false
                    ),
                    node
            );
        });
    }

    @PostConstruct
    public void init() {
        logger.info("init update Taxi");
        try {
            loadBundlePropertyFile();

            setController(new TaxiController());
            setReleaseResourceController(new ReleaseResourceController());
            setTaxiId(externalContext().getRequestParameterMap().get("taxiForm:taxiDtTbl_selection"));
            setTaxi(getController().getTaxiDetailsByTaxiId(getTaxiId()));
            setVehicleId(getTaxi().getVehicle().getId());
            setColorId(getTaxi().getColor().getId());
            setDrivers(getController().findAllActiveAndBancaDriversWithoutTaxi(getLoggedUser().getLocation().getId()));
            
            if(getTaxi().getGps() == BasicType.ENEBLED)
            {
                gps = true;
            }
            else
            {
                gps = false;
            }
            
            if(getTaxi().getApc() == BasicType.ENEBLED)
            {
                apc = true;
            }
            else
            {
                apc = false;
            }

            if (null == getTaxi().getDriver()) {
                setDriverId(null);
            } else {
                setDriverId(getTaxi().getDriver().getId());
                getDrivers().add(getTaxi().getDriver());
            }

            setCustomerId(getTaxi().getCustomer().getId());

            initWeekWorkDeails();
            initContractDetails();

        } catch (Exception e) {
            logger.info("Error taxi update", e);
        }
    }

    private void initWeekWorkDeails() {
        logger.info("initWeekWorkDeails");
        try {
            setPlatform(getTaxi().getPlatform().toString());
            setMonday(BasicType.ENEBLED.equals(getTaxi().getMonday()));
            setTuesday(BasicType.ENEBLED.equals(getTaxi().getTuesday()));
            setWednesday(BasicType.ENEBLED.equals(getTaxi().getWednesday()));
            setThursday(BasicType.ENEBLED.equals(getTaxi().getThursday()));
            setFriday(BasicType.ENEBLED.equals(getTaxi().getFriday()));
            setSaturday(BasicType.ENEBLED.equals(getTaxi().getSaturday()));
            setSunday(BasicType.ENEBLED.equals(getTaxi().getSunday()));
        } catch (Exception e) {
            logger.error("initWeekWorkDeails", e);
        }
    }

    /**
     * Initializing Services and Contracts.
     */
    private void initContractDetails() {
        logger.info("initContractDetails");
        try {
            setTaxi(getController().getTaxiDetailsByTaxiId(getTaxiId()));
            setRoot(
                    new DefaultTreeNode(
                            new ContractTaxiTreeNodeWrapper(
                                    APP, getToday(), Float.NaN), null)
            );

            List<Service> servicesSource = getController().getAllServices(true);
            List<Service> servicesTarget = new ArrayList<>();
            Set<Service> uniqueService = new HashSet<>();

            if (!getTaxi().getContracts().isEmpty()) {
                numberContract = getTaxi().getContracts().size() + 1;
                List<ContractHasService> chses
                        = getController().getAllContractsForTaxi(
                                (Set<Contract>) getTaxi().getContracts()
                        );

                chses.forEach((ContractHasService obj) -> {
                    servicesSource.remove(obj.getService());
                    uniqueService.add(obj.getService());
                });

                ((Set<Service>) uniqueService).forEach((Service ser) -> {
                    Service s = new Service(ser.getId());

                    s.setCharge(ser.getCharge());
                    s.setName(ser.getName());
                    s.setDisable(true);

                    servicesTarget.add(s);
                });

                ((Set<Contract>) getTaxi().getContracts()).forEach((Contract con) -> {
                    setContract(con);
                    List<Service> tmpService = new ArrayList<>();

                    chses.forEach((ContractHasService obj) -> {
                        if (con.getId().equals(obj.getId().getContractId())) {
                            tmpService.add(obj.getService());
                        }
                    });

                    fillTreeTable(tmpService);
                });
            }

            setServices(new DualListModel<>(servicesSource, servicesTarget));
        } catch (Exception e) {
            logger.error(e);
        }
    }

    /**
     *
     * @param oldDriver
     */
    private void releaseResource(Person oldDriver) {
        try {
            Date date = DateWrapper.getTodayMXTime();

            ReleaseResource oldDriverRR = new ReleaseResource(UUID.randomUUID().toString(), oldDriver, date, GenericEnumType.ENABLED, getLoggedUser(), date);
            ReleaseResource taxiToRelease = new ReleaseResource(UUID.randomUUID().toString(), getTaxi(), date, GenericEnumType.ENABLED, getLoggedUser(), date);

            // ENABLED  = Poner en banca = Insert
            // DISABLED = Sacar de banca = Update
            /**
             * Si no tenia chofer previo y ahora si tiene chofer: TAXI =
             * DISABLED and CHOFER = DISABLED
             */
            if (null == oldDriver && (null != getDriverId() && !"".equals(getDriverId()))) {
                getReleaseResourceController().updateReleaseResourceDetails(null, getTaxi(), date, GenericEnumType.DISABLED, getLoggedUser(), date);
                getReleaseResourceController().updateReleaseResourceDetails(new Person(getDriverId()), null, date, GenericEnumType.DISABLED, getLoggedUser(), date);
            } /**
             * Tenia chofer viejo, pero ahora ya no va a tener chofer chofer
             * viejo = ENABLED, taxi = ENABLED
             */
            else if ((null == getDriverId() || "".equals(getDriverId())) && null != oldDriver) {
                getReleaseResourceController().saveReleaseResource(oldDriverRR);
                getReleaseResourceController().saveReleaseResource(taxiToRelease);
            } /**
             * Si choferes son diferentes chofer viejo = ENEABLED, chofer nuevo
             * = DISABLED
             */
            else if (null != oldDriver && (null != getDriverId() && !"".equals(getDriverId())) && !oldDriver.getId().equals(getDriverId())) {
                getReleaseResourceController().saveReleaseResource(oldDriverRR);
                getReleaseResourceController().updateReleaseResourceDetails(new Person(getDriverId()), null, date, GenericEnumType.DISABLED, getLoggedUser(), date);
            }
        } catch (Exception e) {
            logger.error("releaseResource", e);
        }
    }

    private static final long serialVersionUID = 4230039188401916706L;

    final Logger logger = LogManager.getLogger(TaxiEditBean.class
    );

    private TaxiController controller;

    private String taxiId;
    private Taxi taxi;
    private String vehicleId;
    private String driverId;
    private String customerId;
    private String colorId;
    private int numberContract = 1;
    private DualListModel<Service> services;
    private TreeNode root;
    private Contract contract;
    private Date startDate;
    private String platform;
    private List<String> platforms;
    private boolean monday;
    private boolean tuesday;
    private boolean wednesday;
    private boolean thursday;
    private boolean friday;
    private boolean saturday;
    private boolean sunday;
    private List<Person> drivers;
    private ReleaseResourceController releaseResourceController;
    private boolean gps;
    private boolean apc;

    public boolean isApc() {
        return apc;
    }

    public void setApc(boolean apc) {
        this.apc = apc;
    }

    public boolean isGps() {
        return gps;
    }

    public void setGps(boolean gps) {
        this.gps = gps;
    }

    public String getVehicleId() {
        return vehicleId;
    }

    public void setVehicleId(String vehicleId) {
        this.vehicleId = vehicleId;
    }

    public String getDriverId() {
        return driverId;
    }

    public void setDriverId(String driverId) {
        this.driverId = driverId;
    }

    public String getCustomerId() {
        return customerId;
    }

    public void setCustomerId(String customerId) {
        this.customerId = customerId;
    }

    public String getColorId() {
        return colorId;
    }

    public void setColorId(String colorId) {
        this.colorId = colorId;
    }

    public TaxiController getController() {
        return controller;
    }

    public void setController(TaxiController controller) {
        this.controller = controller;
    }

    public String getTaxiId() {
        return taxiId;
    }

    public void setTaxiId(String taxiId) {
        this.taxiId = taxiId;
    }

    public Taxi getTaxi() {
        return taxi;
    }

    public void setTaxi(Taxi taxi) {
        this.taxi = taxi;
    }

    public List<Vehicle> getVehicles() {
        return getController().fillVehicleComboBox();
    }

    public List<Person> getDrivers() {
        //return getController().fillDriversComboBox();
        return drivers;
    }

    public void setDrivers(List<Person> drivers) {
        this.drivers = drivers;
    }

    public List<Person> getCustomers() {
        return getController().fillCustomersComboBox();
    }

    public List<Color> getColors() {
        return getController().fillColorsComboBox();
    }

    public int getNumberContract() {
        return numberContract;
    }

    public void setNumberContract(int numberContract) {
        this.numberContract = numberContract;
    }

    public DualListModel<Service> getServices() {
        return services;
    }

    public void setServices(DualListModel<Service> services) {
        this.services = services;
    }

    public TreeNode getRoot() {
        return root;
    }

    public void setRoot(TreeNode root) {
        this.root = root;
    }

    public Contract getContract() {
        return contract;
    }

    public void setContract(Contract contract) {
        this.contract = contract;
    }

    public Date getStartDate() {
        return startDate;
    }

    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    public String getPlatform() {
        return platform;
    }

    public void setPlatform(String platform) {
        this.platform = platform;
    }

    public List<String> getPlatforms() {
        if (null == platforms) {
            platforms = new ArrayList<>();
            for (PlatformType day : PlatformType.values()) {
                platforms.add(day.toString());
            }
        }
        return platforms;
    }

    public void setPlatforms(List<String> platforms) {
        this.platforms = platforms;
    }

    public boolean isMonday() {
        return monday;
    }

    public void setMonday(boolean monday) {
        this.monday = monday;
    }

    public boolean isTuesday() {
        return tuesday;
    }

    public void setTuesday(boolean tuesday) {
        this.tuesday = tuesday;
    }

    public boolean isWednesday() {
        return wednesday;
    }

    public void setWednesday(boolean wednesday) {
        this.wednesday = wednesday;
    }

    public boolean isThursday() {
        return thursday;
    }

    public void setThursday(boolean thursday) {
        this.thursday = thursday;
    }

    public boolean isFriday() {
        return friday;
    }

    public void setFriday(boolean friday) {
        this.friday = friday;
    }

    public boolean isSaturday() {
        return saturday;
    }

    public void setSaturday(boolean saturday) {
        this.saturday = saturday;
    }

    public boolean isSunday() {
        return sunday;
    }

    public void setSunday(boolean sunday) {
        this.sunday = sunday;
    }

    public ReleaseResourceController getReleaseResourceController() {
        return releaseResourceController;
    }

    public void setReleaseResourceController(ReleaseResourceController releaseResourceController) {
        this.releaseResourceController = releaseResourceController;
    }

}
