from panda3d.core import *


class PopupHandle:
    def __init__(self, popup):
        self.m_popup = popup  # 12
        self.m_cell = -1  # 16
        self.m_wants_visible = False  # 20
        self.m_score = 0  # 24
        self.m_objcode = id(self)  # 28
        popup.setObjectCode(self.m_objcode)


class MarginCell:
    def __init__(self):
        self.m_mat = Mat4()  # 0
        self.m_cell_width = 0  # 64
        self.m_popup = None  # 68
        self.m_np = None  # 72
        self.m_visible = False  # 84
        self.m_objcode = 0  # 88
        self.m_time = 0  # 96


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

        # self.setCullCallback()
        self.cbNode = CallbackNode(self.getName() + '-cbNode')
        self.cbNode.setCullCallback(PythonCallbackObject(self.cullCallback))
        self.addChild(self.cbNode)

        self.m_cells = []
        self.m_popups = {}  # MarginPopup*: PopupHandle
        self.m_code_map = {}  # code: MarginPopup*
        self.m_num_available = 0

    def addGridCell(self, a2, a3, a4, a5, a6, a7):
        v7 = (a5 - a4) * 0.16666667
        v8 = (a7 - a6) * 0.16666667
        v15 = v7 * a2 + a4
        v9 = a3 * v8 + a6
        v10 = v9 + v8 - 0.01
        v11 = v9 + 0.01
        v12 = v15 + v7 - 0.01
        v13 = v15 + 0.01
        return self.addCell(v13, v12, v11, v10)

    def addCell(self, left, right, bottom, top):
        v5 = (top - bottom) * 0.5
        v19 = Vec3(v5, 0, 0)
        scale = Vec3(v5, v5, v5)
        shear = Vec3(0, 0, 0)
        trans = Vec3((left + right) * 0.5, 0, (bottom + top) * 0.5)

        v18 = len(self.m_cells)
        v9 = MarginCell()
        self.m_cells.append(v9)
        v9.m_available = True

        mat3 = Mat3()
        composeMatrix(mat3, scale, shear, Vec3(0, 0, 0), 0)
        v9.m_mat = Mat4(mat3, trans)

        v9.m_cell_width = (right - left) * 0.5 / v19[0]
        v9.m_np = None
        v9.m_popup = None
        v9.m_objcode = 0
        v9.m_time = 0.0

        self.m_num_available += 1
        return v18

    def setCellAvailable(self, a2, a3):
        v5 = self.m_cells[a2]
        if v5.m_available:
            self.m_num_available -= 1

        v5.m_available = a3
        if v5.m_available:
            self.m_num_available += 1

        if v5.m_np:
            self.hide(a2)
            v5.m_popup = None
            v5.m_objcode = 0

    def getCellAvailable(self, a2):
        return self.m_cells[a2].m_available

    def cullCallback(self, *args):
        self.update()

    def managePopup(self, a2):
        a2.setManaged(True)
        self.m_popups[a2] = PopupHandle(a2)
        self.m_code_map[a2.getObjectCode()] = a2

    def unmanagePopup(self, a2):
        v9 = self.m_popups.get(a2)
        if v9:
            if v9.m_cell >= 0:
                self.hide(v9.m_cell)
                v9.m_cell = -1

            a2.setManaged(False)
            del self.m_popups[a2]
            del self.m_code_map[v9.m_objcode]

    def hide(self, a2):
        cell = self.m_cells[a2]
        cell.m_np.removeNode()
        cell.m_time = globalClock.getFrameTime()
        if cell.m_popup:
            cell.m_popup.setVisible(False)

    def show(self, popup, cell_index):
        v12 = self.m_cells[cell_index]
        v12.m_popup = popup
        v12.m_objcode = popup.getObjectCode()
        v12.m_np = NodePath.anyPath(self).attachNewNode(popup)
        v12.m_np.setMat(v12.m_mat)
        self.m_popups[popup].m_cell = cell_index
        popup.m_cell_width = v12.m_cell_width
        popup.setVisible(True)

    def chooseCell(self, a2, a3):
        now = globalClock.getFrameTime()
        objcode = a2.getObjectCode()

        for cell in a3:
            v7 = self.m_cells[cell]
            if (v7.m_popup == a2 or v7.m_objcode == objcode) and (now - v7.m_time) <= 30.0:
                result = cell
                break

        else:
            for cell in a3[::-1][1:]:  # Iterate backwards, skip last item
                v10 = self.m_cells[cell]
                if (not v10.m_popup) or (now - v10.m_time) > 30.0:
                    result = cell
                    break

            else:
                result = a3[-1]

        a3.remove(result)
        return result

    def showVisibleNoConflict(self):
        cells = []
        for i, cell in enumerate(self.m_cells):
            if cell.m_available and not cell.m_np:
                cells.append(i)

        for handle in self.m_popups.values():
            v7 = handle.m_popup
            if handle.m_wants_visible and not v7.isVisible():
                v8 = self.chooseCell(v7, cells)
                self.show(v7, v8)

    def showVisibleResolveConflict(self):
        v4 = []

        for handle in self.m_popups.values():
            score = 0
            if handle.m_wants_visible:
                score = handle.m_score

            v4.append((handle, -score))

        v4 = sorted(v4, key=lambda a: a[-1])
        for handle in v4[self.m_num_available:]:
            if handle[0].m_popup.isVisible():
                self.hide(handle[0].m_cell)
                handle[0].m_cell = -1

        cells = []
        for i, cell in enumerate(self.m_cells):
            if cell.m_available and not cell.m_np:
                cells.append(i)

        for handle in v4[:self.m_num_available]:
            v7 = handle[0].m_popup
            if handle[0].m_wants_visible and not v7.isVisible():
                v8 = self.chooseCell(v7, cells)
                self.show(v7, v8)

    def update(self):
        num_want_visible = 0

        for handle in self.m_popups.values():
            popup = handle.m_popup
            handle.m_wants_visible = popup.considerVisible()
            if handle.m_wants_visible and handle.m_objcode:
                handle.m_score = popup.getScore()
                num_want_visible += 1

            elif popup.isVisible():
                self.hide(handle.m_cell)
                handle.m_cell = -1

        if num_want_visible > self.m_num_available:
            self.showVisibleResolveConflict()

        else:
            self.showVisibleNoConflict()

        for popup in self.m_popups.keys():
            popup.frameCallback()
