OrgUnitTraversal.java

package com.tradecloud.domain.model.organisationalunit;

import com.tradecloud.authentication.MultiTenantUtil;
import com.tradecloud.common.base.HibernateUtils;
import com.tradecloud.domain.agent.OrganisationalUnitAgent;
import com.tradecloud.domain.party.Employee;
import com.tradecloud.domain.party.ServiceProvider;
import com.tradecloud.domain.supplier.AbstractSupplier;
import com.tradecloud.domain.supplier.OrganisationalUnitSupplier;

import java.util.*;

/**
 * @author jon
 */
public class OrgUnitTraversal {

    public static List<OrganisationalUnitAgent> getAllAgentsFromTree(OrganisationalUnit orgUnit, boolean includeCurrentOrgUnit) {
        Set<OrganisationalUnitAgent> agents = new TreeSet<OrganisationalUnitAgent>();

        if (includeCurrentOrgUnit) {
            // add my own
            if (orgUnit.isAllowsAgents()) {
                addAllAgents(agents, orgUnit.getAgents(), true);
            }
        }

        // add parent (recursively)
        getAllParentAgents(orgUnit, agents);

        // add all children recursively
        getAllChildAgents(orgUnit, agents);

        return new ArrayList<OrganisationalUnitAgent>(agents);
    }

    /**
     * This method will return all the agents linked to the incoming organisational unit and its children.
     *
     * @param orgUnit
     * @param includeCurrentOrgUnit
     * @return
     */
    public static List<OrganisationalUnitAgent> getAllAgentsFromTreeOwnAndDown(OrganisationalUnit orgUnit, boolean includeCurrentOrgUnit) {
        Set<OrganisationalUnitAgent> agents = new TreeSet<>();

        if (includeCurrentOrgUnit) {
            // add my own
            if (orgUnit.isAllowsAgents()) {
                addAllAgents(agents, orgUnit.getAgents(), true);
            }


        }
        // add all children recursively
        getAllChildAgents(orgUnit, agents);

        return new ArrayList<>(agents);
    }

    /**
     * This method will return all the agents linked to the incoming organisational unit, its children and one level up from incoming org.
     *
     * @param orgUnit
     * @param includeCurrentOrgUnit
     * @return
     */
    public static List<OrganisationalUnitAgent> getAllAgentsFromTreeOwnDownAndOneLevelUp(OrganisationalUnit orgUnit, boolean includeCurrentOrgUnit) {
        Set<OrganisationalUnitAgent> agents = new TreeSet<>();

        if (includeCurrentOrgUnit) {
            // add my own
            if (orgUnit.isAllowsAgents()) {
                addAllAgents(agents, orgUnit.getAgents(), true);
            }
        }
        // add all children recursively
        getAllChildAgents(orgUnit, agents);

        if (orgUnit.getParent() != null) {
            agents.addAll(orgUnit.getParent().getAgents());
        }
        return new ArrayList<>(agents);
    }

    private static void addAllAgents(Set<OrganisationalUnitAgent> addToo, Set<OrganisationalUnitAgent> addFrom, boolean activeAgentsOnly) {
        if (activeAgentsOnly) {
            for (OrganisationalUnitAgent agent : addFrom) {
                if (agent.getActive()) {
                    addToo.add(HibernateUtils.initializeAndUnproxy(agent));
                }
            }
        } else {
            addToo.addAll(HibernateUtils.initializeAndUnproxy(addFrom));
        }
    }

    /**
     * Recursively adds agents but only in a straight line up.
     *
     * @param orgUnit
     * @param agents
     */
    public static void getAllParentAgents(OrganisationalUnit orgUnit, Set<OrganisationalUnitAgent> agents) {
        if (orgUnit.getParent() != null) {
            if (orgUnit.getParent().isAllowsAgents()) {
                addAllAgents(agents, orgUnit.getParent().getAgents(), true);
            }
            getAllParentAgents(orgUnit.getParent(), agents);
        }
    }

    /**
     * Recursively adds agents for all children.
     *
     * @param orgUnit
     * @param agents
     */
    public static void getAllChildAgents(OrganisationalUnit orgUnit, Set<OrganisationalUnitAgent> agents) {
        // Now call the same for my children
        for (OrganisationalUnit childOrgUnit : orgUnit.getChildren()) {
            if (childOrgUnit.isAllowsAgents()) {
                addAllAgents(agents, childOrgUnit.getAgents(), true);
            }
            getAllChildAgents(childOrgUnit, agents);
        }
    }

    /**
     * Method to get all suppliers.
     *
     * Rules for it documented here:
     * https://connect.devstream.net/display/Dev/Link
     * +suppliers+to+organisational+units
     *
     * @param orgUnit
     * @param activeSuppliersOnly
     * @param includeCurrentOrgUnit
     * @return
     */
    public static List<OrganisationalUnitSupplier> getAllSuppliersFromTree(OrganisationalUnit orgUnit, boolean activeSuppliersOnly,
                                                                           boolean includeCurrentOrgUnit) {
        return getAllSuppliersFromTree(orgUnit, activeSuppliersOnly, includeCurrentOrgUnit, false);
    }

    public static List<OrganisationalUnitSupplier> getAllSuppliersFromTree(OrganisationalUnit orgUnit, boolean activeSuppliersOnly,
                                                                           boolean includeCurrentOrgUnit, boolean includeTemplate) {
        Set<OrganisationalUnitSupplier> suppliers = new TreeSet<OrganisationalUnitSupplier>();

        if (includeCurrentOrgUnit) {
            if (orgUnit.isAllowsSuppliers()) {
                addAllSuppliers(suppliers, orgUnit.getSuppliers(), activeSuppliersOnly, includeTemplate);
            }
        }

        // add parent (recursively)
        getAllParentSuppliers(orgUnit, activeSuppliersOnly, suppliers, includeTemplate);

        // add all children recursively
        getAllChildSuppliers(orgUnit, activeSuppliersOnly, suppliers, includeTemplate);

        return new ArrayList<OrganisationalUnitSupplier>(suppliers);
    }

    /**
     * Method to get all suppliers for incoming organisational unit and its children.
     *
     * @param orgUnit
     * @param activeSuppliersOnly
     * @param includeCurrentOrgUnit
     * @return
     */
    public static List<OrganisationalUnitSupplier> getAllSuppliersFromTreeOwnAndDown(OrganisationalUnit orgUnit, boolean activeSuppliersOnly,
                                                                                     boolean includeCurrentOrgUnit) {
        Set<OrganisationalUnitSupplier> suppliers = new TreeSet<OrganisationalUnitSupplier>();
        if (orgUnit != null) {
            if (includeCurrentOrgUnit) {
                if (orgUnit.isAllowsSuppliers()) {
                    addAllSuppliers(suppliers, orgUnit.getSuppliers(), activeSuppliersOnly);
                }
            }
            // add all children recursively
            getAllChildSuppliers(orgUnit, activeSuppliersOnly, suppliers);
        }

        return new ArrayList<>(suppliers);
    }

    /**
     * Method to get all suppliers for incoming organisational unit and its children.
     *
     * @param orgUnit
     * @param activeSuppliersOnly
     * @param includeCurrentOrgUnit
     * @return
     */
    public static List<OrganisationalUnitSupplier> getAllSuppliersFromTreeOwnOneUpAndDown(OrganisationalUnit orgUnit, boolean activeSuppliersOnly,
                                                                                          boolean includeCurrentOrgUnit) {
        Set<OrganisationalUnitSupplier> suppliers = new TreeSet<OrganisationalUnitSupplier>();
        if (orgUnit != null) {
            if (includeCurrentOrgUnit) {
                if (orgUnit.isAllowsSuppliers()) {
                    addAllSuppliers(suppliers, orgUnit.getSuppliers(), activeSuppliersOnly);
                }
            }
            // add all children recursively
            getAllChildSuppliers(orgUnit, activeSuppliersOnly, suppliers);
            if (orgUnit.getParent() != null) {
                if (orgUnit.getParent().isAllowsSuppliers()) {
                    addAllSuppliers(suppliers, orgUnit.getParent().getSuppliers(), activeSuppliersOnly);
                }
            }
        }

        return new ArrayList<>(suppliers);
    }

    /**
     * Method to get all suppliers for incoming organisational unit, its children and level up from org.
     *
     * @param orgUnit
     * @param activeSuppliersOnly
     * @param includeCurrentOrgUnit
     * @return
     */
    public static List<OrganisationalUnitSupplier> getAllSuppliersFromTreeOwnDownAndOneLevelUp(OrganisationalUnit orgUnit,
                                                                                               boolean activeSuppliersOnly,
                                                                                               boolean includeCurrentOrgUnit) {
        return getAllSuppliersFromTreeOwnDownAndOneLevelUp(orgUnit, activeSuppliersOnly, includeCurrentOrgUnit, false);
    }

    public static List<OrganisationalUnitSupplier> getAllSuppliersFromTreeOwnDownAndOneLevelUp(OrganisationalUnit orgUnit,
                                                                                               boolean activeSuppliersOnly,
                                                                                               boolean includeCurrentOrgUnit,
                                                                                               boolean includeTemplate) {
        Set<OrganisationalUnitSupplier> suppliers = new TreeSet<OrganisationalUnitSupplier>();
        if (orgUnit != null) {
            if (includeCurrentOrgUnit) {
                if (orgUnit.isAllowsSuppliers()) {
                    addAllSuppliers(suppliers, orgUnit.getSuppliers(), activeSuppliersOnly, includeTemplate);
                }
            }
            // add all children recursively
            getAllChildSuppliers(orgUnit, activeSuppliersOnly, suppliers, includeTemplate);
        }

        if (orgUnit.getParent() != null) {
            suppliers.addAll(orgUnit.getParent().getSuppliers());
        }

        return new ArrayList<>(suppliers);
    }

    private static void addAllSuppliers(Set<OrganisationalUnitSupplier> addToo, Set<OrganisationalUnitSupplier> addFrom,
                                        boolean activeSuppliersOnly) {
        addAllSuppliers(addToo, addFrom, activeSuppliersOnly, false);
    }

    private static void addAllSuppliers(Set<OrganisationalUnitSupplier> addToo, Set<OrganisationalUnitSupplier> addFrom,
                                        boolean activeSuppliersOnly, boolean includeTemplate) {
        if (activeSuppliersOnly) {
            for (OrganisationalUnitSupplier supplier : addFrom) {
                if (supplier.getSupplier().getActive() && supplier.getSupplier().isComplete()) {
                    if (includeTemplate) {
                        addToo.add(supplier);
                    } else {
                        if (!supplier.getSupplier().getType().equals(AbstractSupplier.Type.TEMPLATE)) {
                            addToo.add(supplier);
                        }
                    }
                }
            }
        } else {
            for (OrganisationalUnitSupplier supplier : addFrom) {
                if (includeTemplate) {
                    addToo.add(supplier);
                } else {
                    if (!supplier.getSupplier().getType().equals(AbstractSupplier.Type.TEMPLATE)) {
                        addToo.add(supplier);
                    }
                }
            }
        }
    }

    private static void addAllSuppliersForElc(Set<OrganisationalUnitSupplier> addToo, Set<OrganisationalUnitSupplier> addFrom,
                                              boolean activeSuppliersOnly) {
        if (activeSuppliersOnly) {
            for (OrganisationalUnitSupplier supplier : addFrom) {
                if (supplier.getSupplier().getActive()) {
                    addToo.add(supplier);
                }
            }
        } else {
            for (OrganisationalUnitSupplier supplier : addFrom) {
                addToo.add(supplier);
            }
        }
    }

    /**
     * Recursively adds suppliers but only in a straight line up.
     */
    public static void getAllParentSuppliers(OrganisationalUnit orgUnit, boolean activeSuppliersOnly, Set<OrganisationalUnitSupplier> suppliers) {
        getAllParentSuppliers(orgUnit, activeSuppliersOnly, suppliers, false);
    }

    public static void getAllParentSuppliers(OrganisationalUnit orgUnit, boolean activeSuppliersOnly, Set<OrganisationalUnitSupplier> suppliers,
                                             boolean includeTemplate) {
        if (orgUnit.getParent() != null) {
            if (orgUnit.getParent().isAllowsSuppliers()) {
                addAllSuppliers(suppliers, orgUnit.getParent().getSuppliers(), activeSuppliersOnly, includeTemplate);
            }
            getAllParentSuppliers(orgUnit.getParent(), activeSuppliersOnly, suppliers, includeTemplate);
        }
    }

    public static void getAllParentSuppliersForElc(OrganisationalUnit orgUnit, boolean activeSuppliersOnly,
                                                   Set<OrganisationalUnitSupplier> suppliers) {
        if (orgUnit.getParent() != null) {
            if (orgUnit.getParent().isAllowsSuppliers()) {
                addAllSuppliersForElc(suppliers, orgUnit.getParent().getSuppliers(), activeSuppliersOnly);
            }
            getAllParentSuppliersForElc(orgUnit.getParent(), activeSuppliersOnly, suppliers);
        }
    }

    /**
     * Recursively adds suppliers for all children.
     *
     * @param suppliers
     */
    private static void getAllChildSuppliers(OrganisationalUnit orgUnit, boolean activeSuppliersOnly, Set<OrganisationalUnitSupplier> suppliers) {
        getAllChildSuppliers(orgUnit, activeSuppliersOnly, suppliers, false);
    }

    private static void getAllChildSuppliers(OrganisationalUnit orgUnit, boolean activeSuppliersOnly, Set<OrganisationalUnitSupplier> suppliers,
                                             boolean includeTemplate) {
        // Now call the same for my children
        for (OrganisationalUnit child : orgUnit.getChildren()) {
            if (child.isAllowsSuppliers()) {
                addAllSuppliers(suppliers, child.getSuppliers(), activeSuppliersOnly, includeTemplate);
            }
            getAllChildSuppliers(child, activeSuppliersOnly, suppliers, includeTemplate);
        }
    }

    public static List<ServiceProvider> getAllServiceProvidersFromTree(OrganisationalUnit orgUnit, boolean includeCurrent) {
        Set<ServiceProvider> serviceProviders = new TreeSet<ServiceProvider>();

        if (includeCurrent) {
            // add my own
            if (orgUnit.isAllowsServiceProviders()) {
                serviceProviders.addAll(orgUnit.getServiceProviders());
            }
        }

        // add parent (recursively)
        getAllParentServiceProviders(orgUnit, serviceProviders);

        // add all children recursively
        getAllChildServiceProviders(orgUnit, serviceProviders);
        if (!MultiTenantUtil.getActiveUser().isInternalAdmin())
            serviceProviders.removeIf(serviceProvider -> serviceProvider.isCostCompareOnly());
        return new ArrayList<ServiceProvider>(serviceProviders);
    }

    /**
     * Recursively adds serviceProviders but only in a straight line up.
     */
    private static void getAllParentServiceProviders(OrganisationalUnit orgUnit, Set<ServiceProvider> serviceProviders) {
        if (orgUnit.getParent() != null) {
            if (orgUnit.getParent().isAllowsServiceProviders()) {
                serviceProviders.addAll(orgUnit.getParent().getServiceProviders());
            }
            getAllParentServiceProviders(orgUnit.getParent(), serviceProviders);
        }
    }

    /**
     * Recursively adds serviceProviders for all children.
     */
    private static void getAllChildServiceProviders(OrganisationalUnit orgUnit, Set<ServiceProvider> serviceProviders) {
        // Now call the same for my children
        for (OrganisationalUnit child : orgUnit.getChildren()) {
            if (child.isAllowsServiceProviders()) {
                serviceProviders.addAll(child.getServiceProviders());
            }
            getAllChildServiceProviders(child, serviceProviders);
        }
    }

    public static OrganisationalUnit getFirstOrgInStructureWithServiceProviders(OrganisationalUnit organisationalUnit) {
        if (organisationalUnit.getServiceProviders().isEmpty() && organisationalUnit.getParent() != null) {
            return getFirstOrgInStructureWithServiceProviders(organisationalUnit.getParent());
        } else {
            return organisationalUnit;
        }
    }

    /**
     * Return employees for this org unit...but ONLY down the tree (not up as
     * well like for suppliers and service providers).
     *
     * @param orgUnit
     * @param includeCurrentOrgUnit
     * @return
     */
    public static List<Employee> getAllEmployeesDownTheTree(OrganisationalUnit orgUnit, boolean includeCurrentOrgUnit) {
        Set<Employee> employees = new TreeSet<>();

        if (includeCurrentOrgUnit && orgUnit != null) {
            // add my own
            for (Employee employee : orgUnit.getEmployees()) {
                if (employee.getActive()) {
                    employees.add(employee);
                }
            }
        }

        // add all children recursively
        getAllChildEmployees(orgUnit, employees);

        return new ArrayList<Employee>(employees);
    }

    /**
     * Recursively gets all Child employees of the Org Unit.
     */
    private static void getAllChildEmployees(OrganisationalUnit orgUnit, Set<Employee> employees) {
        // Now call the same for my children
        if (orgUnit != null) {
            for (OrganisationalUnit child : orgUnit.getChildren()) {
                for (Employee employee : child.getEmployees()) {
                    if (employee.getActive()) {
                        employees.add(employee);
                    }
                }
                getAllChildEmployees(child, employees);
            }
        }
    }

    /**
     * Add this org unit to the set of matching org units and also all it's
     * children (recursively).
     *
     * @param orgUnit
     * @param matching
     */
    public static void getAllOrgUnitsDown(OrganisationalUnit orgUnit, Set<OrganisationalUnit> matching) {
        // Add this if it's an active org unit
        if (orgUnit != null) {
            if (orgUnit.getActive() && !matching.equals(orgUnit)) {
                matching.add(orgUnit);
            }

            // Now add all children and their childrens childrens children
            // (infinity)
            for (OrganisationalUnit childOrgUnit : orgUnit.getChildren()) {
                getAllOrgUnitsDown(childOrgUnit, matching);
            }
        }
    }

    public static void getAllLegalEntityOrgUnitsDown(OrganisationalUnit orgUnit, Set<OrganisationalUnit> matching) {
        // Add this if it's an active org unit
        if (orgUnit != null) {
            if (orgUnit.getActive() && !matching.equals(orgUnit) && orgUnit.isLegalEntity()) {
                matching.add(orgUnit);
            }

            // Now add all children and their childrens childrens children
            // (infinity)
            for (OrganisationalUnit childOrgUnit : orgUnit.getChildren()) {
                getAllLegalEntityOrgUnitsDown(childOrgUnit, matching);
            }
        }
    }

    public static OrganisationalUnit getParentOnTier(OrganisationalUnit orgUnit, OrganisationalUnitTier unitTier) {
        if (orgUnit == null) {
            return null;
        }
        // Add this if it's an active org unit
        if (orgUnit != null && orgUnit.getActive() && orgUnit.getTier().equals(unitTier)) {
            return orgUnit;
        }
        return getParentOnTier(orgUnit.getParent(), unitTier);
    }

    public static void getAllParentOrgUnits(OrganisationalUnit childOrgUnit, Set<OrganisationalUnit> matching) {
        if (childOrgUnit != null) {
            matching.add(childOrgUnit);
        } else {
            return;
        }
        getAllParentOrgUnits(childOrgUnit.getParent(), matching);
    }

    public static void getAllOrgUnitsDownWithTier(OrganisationalUnit orgUnit, OrganisationalUnitTier unitTier,
                                                  HashSet<OrganisationalUnit> matching) {
        if (orgUnit.getActive() && orgUnit.getTier().equals(unitTier)) {
            matching.add(orgUnit);
        }
        for (OrganisationalUnit childOrgUnit : orgUnit.getChildren()) {
            if (!childOrgUnit.getParent().getTier().equals(unitTier)) {
                getAllOrgUnitsDown(childOrgUnit, matching);
            }
        }

    }

}