def drawTBH(self):

        totalTBHSet = set(
            self.multiOrgParser.getFilteredPeople(
                PeopleFilter().addIsTBHFilter()))
        tbhLocations = set([aTBH.getLocation()
                            for aTBH in totalTBHSet]) or [""]
        tbhProducts = list(set([aTBH.getProduct()
                                for aTBH in totalTBHSet])) or [""]
        tbhProducts.sort(cmp=self._sortByProduct)
        tbhFunctions = list(set([aTBH.getFunction() for aTBH in totalTBHSet]))
        tbhFunctions.sort(cmp=self._sortByFunc)

        for aLocation in tbhLocations:
            title = "Hiring"

            # Location might not be set.
            if aLocation:
                title = "{} - {}".format(title, aLocation)

            chartDrawer = DrawChartSlideTBH(self.presentation, title,
                                            self.slideLayout)

            for aFunction in tbhFunctions:
                productTBHList = self.multiOrgParser.getFilteredPeople(
                    PeopleFilter().addIsTBHFilter().addFunctionFilter(
                        aFunction).addLocationFilter(aLocation))
                productTBHList = sorted(productTBHList, self._sortByFunc,
                                        lambda tbh: tbh.getProduct())
                self.buildGroup(aFunction, productTBHList, chartDrawer)

            chartDrawer.drawSlide()
    def drawProductManger(self):
        productManagers = self.multiOrgParser.getFilteredPeople(
            PeopleFilter().addIsProductManagerFilter())
        if not len(productManagers):
            return
        chartDrawer = DrawChartSlidePM(self.presentation, "Product Management",
                                       self.slideLayout)

        productBuckets = list(
            set([aPerson.getFeatureTeam() for aPerson in productManagers]))

        for aBucket in productBuckets:
            peopleList = [
                aPerson for aPerson in productManagers
                if aPerson.getFeatureTeam() == aBucket
            ]
            # peopleList = sorted(peopleList, key=lambda x: x.getProduct(), cmp=self._sortByProduct)
            peopleList.sort()

            # Set default name for PM who don't have 'feature team' set
            # If default name isn't set, these people are accidentally filtered out in the
            # buildGroup function
            if not aBucket:
                aBucket = orgchart_parser.NOT_SET
            self.buildGroup(aBucket, peopleList, chartDrawer)

        # peopleProducts = list(set([aPerson.getProduct() for aPerson in productManagers]))
        # for aProduct in peopleProducts:
        #     self.buildGroup(aProduct, [aPerson for aPerson in productManagers if aPerson.getProduct() == aProduct], chartDrawer)
        chartDrawer.drawSlide()
    def _getDirects(self, aManager, location=None):
        """

        :type aManager: str
        :return:
        """
        peopleFilter = PeopleFilter()
        directReports = []
        peopleFilter.addManagerFilter(aManager)
        peopleFilter.addIsTBHFilter(False)
        if location:
            peopleFilter.addLocationFilter(location)
        directReports.extend(
            self.multiOrgParser.getFilteredPeople(peopleFilter))

        return directReports
    def drawCrossFunc(self):
        crossFuncPeople = self.multiOrgParser.getCrossFuncPeople()

        if not len(crossFuncPeople):
            return

        chartDrawer = DrawChartSlide(self.presentation, "Cross Functional",
                                     self.slideLayout)

        functions = list(
            set([aPerson.getFunction() for aPerson in crossFuncPeople]))
        functions.sort(cmp=self._sortByFunc)

        for aFunction in functions:
            peopleFilter = PeopleFilter()
            peopleFilter.addFunctionFilter(aFunction)
            peopleFilter.addIsCrossFuncFilter()
            peopleFilter.addIsExpatFilter(False)
            peopleFilter.addIsInternFilter(False)

            funcPeople = self.multiOrgParser.getFilteredPeople(peopleFilter)
            self.buildGroup(aFunction, funcPeople, chartDrawer)
        chartDrawer.drawSlide()
    def drawCrossFunc(self):
        crossFuncPeople = self.multiOrgParser.getCrossFuncPeople()

        if not len(crossFuncPeople):
            return

        chartDrawer = DrawChartSlide(self.presentation, "Cross Functional", self.slideLayout)

        functions = list(set([aPerson.getFunction() for aPerson in crossFuncPeople]))
        functions.sort(cmp=self._sortByFunc)

        for aFunction in functions:
            peopleFilter = PeopleFilter()
            peopleFilter.addFunctionFilter(aFunction)
            peopleFilter.addIsCrossFuncFilter()
            peopleFilter.addIsExpatFilter(False)
            peopleFilter.addIsInternFilter(False)

            funcPeople = self.multiOrgParser.getFilteredPeople(peopleFilter)
            self.buildGroup(aFunction, funcPeople, chartDrawer)
        chartDrawer.drawSlide()
    def drawAllProducts(self, drawFeatureTeams, drawLocations,
                        drawExpatsInTeam):
        #Get all the products except the ones where a PM is the only member
        people = self.multiOrgParser.getFilteredPeople(
            PeopleFilter().addIsProductManagerFilter(False))

        productList = list(set([aPerson.getProduct() for aPerson in people]))

        for aCrossFuncTeam in self.multiOrgParser.getCrossFuncTeams():
            for aProductName in productList[:]:
                if aProductName.lower() == aCrossFuncTeam.lower():
                    productList.remove(aProductName)
            productList.sort(cmp=self._sortByProduct)

        for aProductName in productList:
            self.drawProduct(aProductName, drawFeatureTeams, drawLocations,
                             drawExpatsInTeam)
    def _getDirects(self, aManager, location=None):
        """

        :type aManager: str
        :return:
        """
        peopleFilter = PeopleFilter()
        directReports = []
        peopleFilter.addManagerFilter(aManager)
        peopleFilter.addIsTBHFilter(False)
        if location:
            peopleFilter.addLocationFilter(location)
        directReports.extend(self.multiOrgParser.getFilteredPeople(peopleFilter))

        return directReports
    def drawAdmin(self):

        # Populate the manager list with managers who are entered in the spreadsheet so it's easier to match them
        # to the appropriate floor and identify them as 1 person even if they are entered in different ways in the
        # Manager column (Ben/Benjamin)
        managerSet = set(
            self.multiOrgParser.getFilteredPeople(
                PeopleFilter().addIsManagerFilter()))

        # Get all the entries in the manager column but remove entries that start with "_" as they are excluded intentionally
        allManagers = set([
            SkeletonPerson(aManagerName)
            for aManagerName in self.multiOrgParser.getManagerSet()
            if (not aManagerName.startswith("_")) and "TBD" not in aManagerName
        ])

        print "Info: Managers not entered as rows: {}".format(
            managerSet.difference(allManagers))

        # Prefer Person type over SkeletonPerson type as it is more full featured - floors work better
        mergedManagerList = managerSet.union(allManagers)
        #pprint.pprint("Managers: {}".format(mergedManagerList))

        managerEmployeeDict = {}
        for aManager in mergedManagerList:
            managerEmployeeDict[aManager] = self._getDirects(aManager)

        # A manager can have reports on more than one floor
        managersByFloor = {}
        for aManager in mergedManagerList:
            floors = aManager.getFloors()
            for floor in floors:
                if not floor in managersByFloor:
                    managersByFloor[floor] = set()
                managersByFloor[floor].add(aManager)

        # Location: There can be people across locations reporting to the same manager:
        # Example: People report to Arno in Santa Clara and in Milan.
        # There will be a single slide for each unique location. Only direct reports in the specified location will be
        # drawn
        for aLocation in self.multiOrgParser.getLocationSet():
            locationName = aLocation or self.multiOrgParser.getOrgName()

            # Floor: The floor (or other grouping) that separates manager.
            # Example: There are a lot of managers in Waltham so we break them up across floors
            # NOTE: All of the direct reports in the location will be drawn
            # Example: If Dave is on floor1 and floor2 in Waltham, then the same direct reports will be drawn both times

            sortedFloors = list(managersByFloor.keys())
            sortedFloors.sort(cmp=self._sortByFloor)

            maxManagersPerSlide = 7
            managersOnSlide = 0
            partNum = 2
            slideNameAddendum = "pt {}".format(partNum)

            for aFloor in sortedFloors:
                managerList = managersByFloor[aFloor]
                chartDrawer = DrawChartSlideAdmin(
                    self.presentation,
                    "{} Admin {}".format(locationName,
                                         aFloor), self.slideLayout)
                managerList = list(managerList)
                managerList.sort()
                for aManager in managerList:
                    directReports = []

                    for aPerson in managerEmployeeDict[aManager][:]:
                        if aPerson.getLocation() == aLocation:
                            directReports.append(aPerson)
                            #print "TODO: Removing - {}".format(aPerson)
                            managerEmployeeDict[aManager].remove(aPerson)
                            #print "TODO : Removed"

                    #directReports.extend([aPerson for aPerson in managerEmployeeDict[aManager] if aPerson.getLocation() == aLocation])

                    # directReports.extend(self._getDirects(aManager, aLocation))
                    if not directReports:
                        continue
                    self.buildGroup(aManager.getPreferredName(), directReports,
                                    chartDrawer)
                    managersOnSlide += 1

                    # Split the slide into multiple parts if it's getting too crowded
                    if managersOnSlide >= maxManagersPerSlide:
                        managersOnSlide = 0
                        chartDrawer.drawSlide()
                        chartDrawer = DrawChartSlideAdmin(
                            self.presentation,
                            "{} Admin {}{}".format(locationName, aFloor,
                                                   slideNameAddendum),
                            self.slideLayout)
                        partNum += 1
                        slideNameAddendum = "pt {}".format(partNum)

                # Keep track of whether this floor has any people so that we avoid spamming "WARNING" messages because
                # a slide is being drawn that's empty
                if managersOnSlide > 0:
                    chartDrawer.drawSlide()
                managersOnSlide = 0

            emptyManagerPeopleFilter = (PeopleFilter().addManagerEmptyFilter(
            ).addIsTBHFilter(False).addLocationFilter(locationName))

            peopleMissingManager = (self.multiOrgParser.getFilteredPeople(
                emptyManagerPeopleFilter))

            if peopleMissingManager:
                #Draw people who are missing a manager on their own slide
                chartDrawer = DrawChartSlideAdmin(
                    self.presentation,
                    "{} Missing Admin Manager".format(locationName),
                    self.slideLayout)

                self.buildGroup("Chuck Norris", peopleMissingManager,
                                chartDrawer)
                chartDrawer.drawSlide()
    def drawProduct(self,
                    productName,
                    drawFeatureTeams=False,
                    drawLocations=False,
                    drawExpatsInTeam=True):
        """

        :type productName: str
        """
        if not productName:
            if not self.draftMode:
                return

        featureTeamList = [""]
        if drawFeatureTeams:
            featureTeamList = list(
                self.multiOrgParser.getFeatureTeamSet(productName))

        functionList = list(self.multiOrgParser.getFunctionSet(productName))
        functionList.sort(cmp=self._sortByFunc)

        teamModelText = None

        locations = [""]

        # If draw locations has been set (could still be an empty list) then break the chart up by locations.
        # if locations is set and isn't an empty list, only show the locations specified.
        if drawLocations is not None:
            locations = self.multiOrgParser.getLocationSet(productName)
            for drawLocation in drawLocations:
                if drawLocation not in locations:
                    raise ValueError(
                        "{} is not found in available locations: {}".format(
                            drawLocations, locations))

        for aLocation in drawLocations or locations:
            locationName = aLocation.strip() or self.multiOrgParser.getOrgName(
            )

            for aFeatureTeam in featureTeamList:
                if not productName:
                    slideTitle = orgchart_parser.NOT_SET
                elif drawFeatureTeams:
                    teamName = "- {} ".format(aFeatureTeam)
                    if not aFeatureTeam:
                        if len(featureTeamList) > 1:
                            teamName = "- Cross "
                        else:
                            teamName = ""
                    slideTitle = "{} {}Feature Team".format(
                        productName, teamName)
                else:
                    slideTitle = "{}".format(productName)
                    modelDict = self.multiOrgParser.getTeamModel()
                    if productName in modelDict:
                        teamModelText = modelDict[productName]

                chartDrawer = DrawChartSlide(self.presentation, slideTitle,
                                             self.slideLayout, teamModelText)
                if len(locations) > 1 and aLocation:
                    chartDrawer.setLocation(locationName)

                for aFunction in functionList:
                    if aFunction.lower(
                    ) in self.multiOrgParser.getCrossFunctions():
                        continue

                    peopleFilter = PeopleFilter()
                    peopleFilter.addProductFilter(productName)
                    peopleFilter.addFunctionFilter(aFunction)
                    if drawLocations is not None:
                        peopleFilter.addLocationFilter(aLocation)

                    if drawFeatureTeams:
                        peopleFilter.addFeatureTeamFilter(aFeatureTeam)
                    else:
                        if not drawExpatsInTeam:
                            peopleFilter.addIsExpatFilter(False)
                        peopleFilter.addIsInternFilter(False)
                        # peopleFilter.addIsProductManagerFilter(False)

                    functionPeople = self.multiOrgParser.getFilteredPeople(
                        peopleFilter)
                    self.buildGroup(aFunction, functionPeople, chartDrawer)

                chartDrawer.drawSlide()
 def drawIntern(self):
     interns = self.multiOrgParser.getFilteredPeople(
         PeopleFilter().addIsInternFilter())
     self._drawMiscGroups("Intern", interns)
 def drawExpat(self):
     expats = self.multiOrgParser.getFilteredPeople(
         PeopleFilter().addIsExpatFilter())
     #.addIsProductManagerFilter(False))
     self._drawMiscGroups("ExPat", expats)
    def drawProduct(self, productName, drawFeatureTeams=False, drawLocations=False, drawExpatsInTeam=True):
        """

        :type productName: str
        """
        if not productName:
            if not self.draftMode:
                return

        featureTeamList = [""]
        if drawFeatureTeams:
            featureTeamList = list(self.multiOrgParser.getFeatureTeamSet(productName))

        functionList = list(self.multiOrgParser.getFunctionSet(productName))
        functionList.sort(cmp=self._sortByFunc)

        teamModelText = None

        locations = [""]

        # If draw locations has been set (could still be an empty list) then break the chart up by locations.
        # if locations is set and isn't an empty list, only show the locations specified.
        if drawLocations is not None:
            locations = self.multiOrgParser.getLocationSet(productName)
            for drawLocation in drawLocations:
                if drawLocation not in locations:
                    raise ValueError("{} is not found in available locations: {}".format(drawLocations, locations))


        for aLocation in drawLocations or locations:
            locationName = aLocation.strip() or self.multiOrgParser.getOrgName()

            for aFeatureTeam in featureTeamList:
                if not productName:
                    slideTitle = orgchart_parser.NOT_SET
                elif drawFeatureTeams:
                    teamName = "- {} ".format(aFeatureTeam)
                    if not aFeatureTeam:
                        if len(featureTeamList) > 1:
                            teamName = "- Cross "
                        else:
                            teamName = ""
                    slideTitle = "{} {}Feature Team".format(productName, teamName)
                else:
                    slideTitle = "{}".format(productName)
                    modelDict = self.multiOrgParser.getTeamModel()
                    if productName in modelDict:
                        teamModelText = modelDict[productName]

                chartDrawer = DrawChartSlide(self.presentation, slideTitle, self.slideLayout, teamModelText)
                if len(locations) > 1 and aLocation:
                   chartDrawer.setLocation(locationName)

                for aFunction in functionList:
                    if aFunction.lower() in self.multiOrgParser.getCrossFunctions():
                        continue

                    peopleFilter = PeopleFilter()
                    peopleFilter.addProductFilter(productName)
                    peopleFilter.addFunctionFilter(aFunction)
                    if drawLocations is not None:
                        peopleFilter.addLocationFilter(aLocation)

                    if drawFeatureTeams:
                        peopleFilter.addFeatureTeamFilter(aFeatureTeam)
                    else:
                        if not drawExpatsInTeam:
                            peopleFilter.addIsExpatFilter(False)
                        peopleFilter.addIsInternFilter(False)
                        # peopleFilter.addIsProductManagerFilter(False)

                    functionPeople = self.multiOrgParser.getFilteredPeople(peopleFilter)
                    self.buildGroup(aFunction, functionPeople, chartDrawer)

                chartDrawer.drawSlide()