from pandac.PandaModules import *
from MarginCell import MarginCell
import random

class MarginManager(PandaNode):
    def __init__(self):
        PandaNode.__init__(self, 'margins')

        self.cells = set()
        self.visiblePopups = set()

    def addGridCell(self, x, y, a2d):
        # Yucky!
        nodePath = NodePath.anyPath(self)
        a2d.reparentTo(nodePath)
        cell = MarginCell(self)
        cell.reparentTo(a2d)
        cell.setScale(0.2)
        cell.setPos(x, 0, y + 0.025)
        cell.setAvailable(True)
        cell.setPythonTag('MarginCell', cell)

        self.cells.add(cell)
        self.reorganize()

        return cell

    def setCellAvailable(self, cell, available):
        cell = cell.getPythonTag('MarginCell')
        cell.setAvailable(available)
        self.reorganize()

    def addVisiblePopup(self, popup):
        self.visiblePopups.add(popup)
        self.reorganize()

    def removeVisiblePopup(self, popup):
        if popup not in self.visiblePopups: return
        self.visiblePopups.remove(popup)
        self.reorganize()

    def reorganize(self):
        # First, get all active cells:
        activeCells = [cell for cell in self.cells if cell.isAvailable()]

        # Next, get all visible popups, sorted by priority:
        popups = list(self.visiblePopups)
        popups.sort(key=lambda x: -x.getPriority())

        # We can only display so many popups, so truncate to the number of active
        # margin cells:
        popups = popups[:len(activeCells)]

        # Now, we need to build up a list of free cells:
        freeCells = []
        for cell in activeCells:
            if not cell.hasContent():
                freeCells.append(cell)
            elif cell.getContent() in popups:
                # It's already displaying something we want to show, so we can
                # safely ignore this cell/popup pair:
                popups.remove(cell.getContent())
            else:
                # It's not displaying something we want to see, evict the old
                # popup:
                cell.setContent(None)
                freeCells.append(cell)

        # At this point, there should be enough cells to show the popups:
        assert len(freeCells) >= len(popups)

        # Now we assign the popups:
        for popup in popups:
            if popup._lastCell in freeCells and popup._lastCell.isFree():
                # The last cell it had assigned is available, so let's assign it
                # again:
                popup._lastCell.setContent(popup)
                freeCells.remove(popup._lastCell)
            else:
                # We assign a cell at random.
                cell = random.choice(freeCells)
                cell.setContent(popup)
                freeCells.remove(cell)
