package ocelot.desktop.node.nodes import ocelot.desktop.geometry.{Rect2D, Size2D, Vector2D} import ocelot.desktop.graphics.{Graphics, IconSource} import ocelot.desktop.inventory.Item import ocelot.desktop.inventory.item.{DiskDriveMountableItem, RackMountableItem, ServerItem} import ocelot.desktop.node.Node.{HighlightThickness, NoHighlightSize, Size, TexelCount} import ocelot.desktop.node.{ComputerAwareNode, NodePort} import ocelot.desktop.ui.event.ClickEvent import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry} import ocelot.desktop.ui.widget.window.Window import ocelot.desktop.util.DrawUtils import ocelot.desktop.windows.RackWindow import totoro.ocelot.brain.entity.Rack import totoro.ocelot.brain.entity.traits.{ComponentInventory, Environment, Inventory, RackMountable} import totoro.ocelot.brain.network import totoro.ocelot.brain.util.Direction class RackNode(val rack: Rack) extends ComputerAwareNode(rack) { override val icon: String = "nodes/rack/Empty" override def exposeAddress = false override def ports: Array[NodePort] = Array( NodePort(Some(Direction.Bottom)), NodePort(Some(Direction.Top)), NodePort(Some(Direction.Back)), NodePort(Some(Direction.Right)), NodePort(Some(Direction.Left)) ) override def getNodeByPort(port: NodePort): network.Node = rack.sidedNode(port.direction.get) override def shouldReceiveEventsFor(address: String): Boolean = super.shouldReceiveEventsFor(address) || rack.inventory.entities.exists { case mountable: RackMountable if mountable.node.address == address => true case mountable: RackMountable with ComponentInventory => mountable.inventory.entities.exists { case environment: Environment => environment.node.address == address } case _ => false } override def setupContextMenu(menu: ContextMenu, event: ClickEvent): Unit = { RackNode.addContextMenuEntriesOfMountable(menu, getMountableByClick(event)) super.setupContextMenu(menu, event) } override def draw(g: Graphics): Unit = { super.draw(g) val x = position.x + HighlightThickness val y = position.y + HighlightThickness var prefix: String = null for (i <- 0 until 4) { Slot(i).get match { case Some(serverItem: ServerItem) => prefix = s"nodes/rack/server/$i/" // Background g.sprite( s"${prefix}Default", x, y, NoHighlightSize, NoHighlightSize ) // Activity overlay DrawUtils.drawComputerNodeActivity( g, x, y, serverItem.server.machine, prefix ) case Some(diskDriveMountableItem: DiskDriveMountableItem) => prefix = s"nodes/rack/drive/$i/" // Background g.sprite( s"${prefix}Default", x, y, NoHighlightSize, NoHighlightSize ) diskDriveMountableItem.drawActivityAndFloppy( g, Rect2D( x, y, NoHighlightSize, NoHighlightSize ), prefix ) case _ => } } } override def dispose(): Unit = { for (i <- 0 until 4) { Slot(i).get match { case Some(serverItem: ServerItem) => serverItem.onRemoved() case _=> } } super.dispose() } // -------------------------------- Inventory -------------------------------- override type I = Item with RackMountableItem override def brainInventory: Inventory = rack.inventory.owner // -------------------------------- Window -------------------------------- private lazy val currentWindow = new RackWindow(this) override def window: Option[Window] = Some(currentWindow) // ---------------------------- ShiftClickNode ---------------------------- private def getMountableByClick(event: ClickEvent): Option[RackMountableItem] = { val horizontalMargin = HighlightThickness + (1 / TexelCount) * Size val verticalMargin = HighlightThickness + (2 / TexelCount) * Size val localPosition = Vector2D( event.mousePos.x - position.x - horizontalMargin, event.mousePos.y - position.y - verticalMargin ) val m = Size2D( this.width - horizontalMargin * 2, this.height - verticalMargin * 2 ) // Checking if click was inside mountables area if (localPosition.x < 0 || localPosition.y < 0 || localPosition.x > m.width || localPosition.y > m.height) return None val mountableIndex = (localPosition.y / m.height * 4).toInt Slot(mountableIndex).get.collect { case item: RackMountableItem => item } } override protected def onShiftClick(event: ClickEvent): Unit = { getMountableByClick(event) match { case Some(serverItem: ServerItem) => serverItem.toggleIsTurnedOn() case Some(diskDriveMountableItem: DiskDriveMountableItem) => if (diskDriveMountableItem.isFloppyItemPresent) diskDriveMountableItem.eject() case _ => } } override protected def hoveredShiftStatusBarText: String = "Turn server on/off" } object RackNode { def addContextMenuEntriesOfMountable(menu: ContextMenu, item: Option[RackMountableItem]): Unit = { item match { case Some(serverItem: ServerItem) => menu.addEntry(ContextMenuEntry("Set up", IconSource.Window) { serverItem.window.get.open() }) if (serverItem.isInRack) { menu.addSeparator() serverItem.addPowerContextMenuEntries(menu) } serverItem.addTierContextMenuEntries(menu) menu.addSeparator() case Some(diskDriveMountableItem: DiskDriveMountableItem) => if (diskDriveMountableItem.isFloppyItemPresent) { diskDriveMountableItem.addDiskDriveMenuEntries(menu) menu.addSeparator() } case _ => } } }