314 lines
7.5 KiB
Go
314 lines
7.5 KiB
Go
package widget
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Manager manages widgets within a zone
|
|
type Manager struct {
|
|
widgets map[int32]*Widget // Widget ID -> Widget
|
|
widgetsByDBID map[int32]*Widget // Database ID -> Widget
|
|
widgetTimers map[*Widget]*time.Timer // Active timers for widgets
|
|
timerCallbacks map[*Widget]func() // Timer callbacks
|
|
mutex sync.RWMutex
|
|
timerMutex sync.Mutex
|
|
}
|
|
|
|
// NewManager creates a new widget manager
|
|
func NewManager() *Manager {
|
|
return &Manager{
|
|
widgets: make(map[int32]*Widget),
|
|
widgetsByDBID: make(map[int32]*Widget),
|
|
widgetTimers: make(map[*Widget]*time.Timer),
|
|
timerCallbacks: make(map[*Widget]func()),
|
|
}
|
|
}
|
|
|
|
// AddWidget adds a widget to the manager
|
|
func (m *Manager) AddWidget(widget *Widget) {
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
|
|
if widget.GetWidgetID() > 0 {
|
|
m.widgets[widget.GetWidgetID()] = widget
|
|
}
|
|
|
|
if widget.GetDatabaseID() > 0 {
|
|
m.widgetsByDBID[widget.GetDatabaseID()] = widget
|
|
}
|
|
}
|
|
|
|
// RemoveWidget removes a widget from the manager
|
|
func (m *Manager) RemoveWidget(widgetID int32) {
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
|
|
if widget, exists := m.widgets[widgetID]; exists {
|
|
// Cancel any active timers
|
|
m.cancelWidgetTimer(widget)
|
|
|
|
// Remove from maps
|
|
delete(m.widgets, widgetID)
|
|
if widget.GetDatabaseID() > 0 {
|
|
delete(m.widgetsByDBID, widget.GetDatabaseID())
|
|
}
|
|
}
|
|
}
|
|
|
|
// GetWidget gets a widget by ID
|
|
func (m *Manager) GetWidget(widgetID int32) *Widget {
|
|
m.mutex.RLock()
|
|
defer m.mutex.RUnlock()
|
|
|
|
return m.widgets[widgetID]
|
|
}
|
|
|
|
// GetWidgetByDatabaseID gets a widget by database ID
|
|
func (m *Manager) GetWidgetByDatabaseID(databaseID int32) *Widget {
|
|
m.mutex.RLock()
|
|
defer m.mutex.RUnlock()
|
|
|
|
return m.widgetsByDBID[databaseID]
|
|
}
|
|
|
|
// GetAllWidgets returns all widgets
|
|
func (m *Manager) GetAllWidgets() []*Widget {
|
|
m.mutex.RLock()
|
|
defer m.mutex.RUnlock()
|
|
|
|
widgets := make([]*Widget, 0, len(m.widgets))
|
|
for _, widget := range m.widgets {
|
|
widgets = append(widgets, widget)
|
|
}
|
|
|
|
return widgets
|
|
}
|
|
|
|
// GetWidgetsByType returns all widgets of a specific type
|
|
func (m *Manager) GetWidgetsByType(widgetType int8) []*Widget {
|
|
m.mutex.RLock()
|
|
defer m.mutex.RUnlock()
|
|
|
|
widgets := make([]*Widget, 0)
|
|
for _, widget := range m.widgets {
|
|
if widget.GetWidgetType() == widgetType {
|
|
widgets = append(widgets, widget)
|
|
}
|
|
}
|
|
|
|
return widgets
|
|
}
|
|
|
|
// AddWidgetTimer adds a timer for a widget
|
|
func (m *Manager) AddWidgetTimer(widget *Widget, seconds float32, callback func()) {
|
|
m.timerMutex.Lock()
|
|
defer m.timerMutex.Unlock()
|
|
|
|
// Cancel existing timer if any
|
|
m.cancelWidgetTimerLocked(widget)
|
|
|
|
// Create new timer
|
|
duration := time.Duration(seconds * float32(time.Second))
|
|
timer := time.AfterFunc(duration, func() {
|
|
m.handleWidgetTimer(widget)
|
|
})
|
|
|
|
m.widgetTimers[widget] = timer
|
|
if callback != nil {
|
|
m.timerCallbacks[widget] = callback
|
|
} else {
|
|
// Default callback for auto-close
|
|
m.timerCallbacks[widget] = func() {
|
|
widget.HandleTimerUpdate()
|
|
}
|
|
}
|
|
}
|
|
|
|
// HasWidgetTimer checks if a widget has an active timer
|
|
func (m *Manager) HasWidgetTimer(widget *Widget) bool {
|
|
m.timerMutex.Lock()
|
|
defer m.timerMutex.Unlock()
|
|
|
|
_, exists := m.widgetTimers[widget]
|
|
return exists
|
|
}
|
|
|
|
// CancelWidgetTimer cancels a widget's timer
|
|
func (m *Manager) CancelWidgetTimer(widget *Widget) {
|
|
m.timerMutex.Lock()
|
|
defer m.timerMutex.Unlock()
|
|
|
|
m.cancelWidgetTimerLocked(widget)
|
|
}
|
|
|
|
// cancelWidgetTimerLocked cancels a timer (must hold timerMutex)
|
|
func (m *Manager) cancelWidgetTimerLocked(widget *Widget) {
|
|
if timer, exists := m.widgetTimers[widget]; exists {
|
|
timer.Stop()
|
|
delete(m.widgetTimers, widget)
|
|
delete(m.timerCallbacks, widget)
|
|
}
|
|
}
|
|
|
|
// cancelWidgetTimer cancels a timer (must hold timerMutex)
|
|
func (m *Manager) cancelWidgetTimer(widget *Widget) {
|
|
m.timerMutex.Lock()
|
|
defer m.timerMutex.Unlock()
|
|
|
|
m.cancelWidgetTimerLocked(widget)
|
|
}
|
|
|
|
// handleWidgetTimer handles a widget timer expiration
|
|
func (m *Manager) handleWidgetTimer(widget *Widget) {
|
|
m.timerMutex.Lock()
|
|
callback, exists := m.timerCallbacks[widget]
|
|
if exists {
|
|
delete(m.widgetTimers, widget)
|
|
delete(m.timerCallbacks, widget)
|
|
}
|
|
m.timerMutex.Unlock()
|
|
|
|
// Execute callback outside of lock
|
|
if callback != nil {
|
|
callback()
|
|
}
|
|
}
|
|
|
|
// ProcessWidgetTimers processes all widget timers (called periodically)
|
|
func (m *Manager) ProcessWidgetTimers() {
|
|
// Timers are handled automatically by time.AfterFunc
|
|
// This method is here for compatibility but doesn't need to do anything
|
|
}
|
|
|
|
// GetDoorWidgets returns all door widgets
|
|
func (m *Manager) GetDoorWidgets() []*Widget {
|
|
return m.GetWidgetsByType(WidgetTypeDoor)
|
|
}
|
|
|
|
// GetLiftWidgets returns all lift widgets
|
|
func (m *Manager) GetLiftWidgets() []*Widget {
|
|
return m.GetWidgetsByType(WidgetTypeLift)
|
|
}
|
|
|
|
// GetOpenWidgets returns all open widgets
|
|
func (m *Manager) GetOpenWidgets() []*Widget {
|
|
m.mutex.RLock()
|
|
defer m.mutex.RUnlock()
|
|
|
|
widgets := make([]*Widget, 0)
|
|
for _, widget := range m.widgets {
|
|
if widget.IsOpen() {
|
|
widgets = append(widgets, widget)
|
|
}
|
|
}
|
|
|
|
return widgets
|
|
}
|
|
|
|
// GetWidgetsByHouseID returns all widgets for a house
|
|
func (m *Manager) GetWidgetsByHouseID(houseID int32) []*Widget {
|
|
m.mutex.RLock()
|
|
defer m.mutex.RUnlock()
|
|
|
|
widgets := make([]*Widget, 0)
|
|
for _, widget := range m.widgets {
|
|
if widget.GetHouseID() == houseID {
|
|
widgets = append(widgets, widget)
|
|
}
|
|
}
|
|
|
|
return widgets
|
|
}
|
|
|
|
// GetLinkedWidgets returns all widgets linked to the given widget
|
|
func (m *Manager) GetLinkedWidgets(widget *Widget) []*Widget {
|
|
m.mutex.RLock()
|
|
defer m.mutex.RUnlock()
|
|
|
|
linked := make([]*Widget, 0)
|
|
|
|
// Add linked spawn
|
|
if widget.GetLinkedSpawnID() > 0 {
|
|
if linkedWidget := m.widgetsByDBID[widget.GetLinkedSpawnID()]; linkedWidget != nil {
|
|
linked = append(linked, linkedWidget)
|
|
}
|
|
}
|
|
|
|
// Add action spawn
|
|
if widget.GetActionSpawnID() > 0 {
|
|
if actionWidget := m.widgetsByDBID[widget.GetActionSpawnID()]; actionWidget != nil {
|
|
linked = append(linked, actionWidget)
|
|
}
|
|
}
|
|
|
|
// Find widgets that link to this one
|
|
for _, w := range m.widgets {
|
|
if w.GetLinkedSpawnID() == widget.GetDatabaseID() ||
|
|
w.GetActionSpawnID() == widget.GetDatabaseID() {
|
|
linked = append(linked, w)
|
|
}
|
|
}
|
|
|
|
return linked
|
|
}
|
|
|
|
// ResolveLinkedSpawns resolves all linked spawn references
|
|
func (m *Manager) ResolveLinkedSpawns() {
|
|
m.mutex.RLock()
|
|
defer m.mutex.RUnlock()
|
|
|
|
for _, widget := range m.widgets {
|
|
// Resolve linked spawn
|
|
if widget.GetLinkedSpawnID() > 0 && widget.GetLinkedSpawn() == nil {
|
|
if linked := m.widgetsByDBID[widget.GetLinkedSpawnID()]; linked != nil {
|
|
widget.SetLinkedSpawn(linked)
|
|
}
|
|
}
|
|
|
|
// Resolve action spawn
|
|
if widget.GetActionSpawnID() > 0 && widget.GetActionSpawn() == nil {
|
|
if action := m.widgetsByDBID[widget.GetActionSpawnID()]; action != nil {
|
|
widget.SetActionSpawn(action)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clear removes all widgets and cancels all timers
|
|
func (m *Manager) Clear() {
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
|
|
// Cancel all timers
|
|
m.timerMutex.Lock()
|
|
for widget, timer := range m.widgetTimers {
|
|
timer.Stop()
|
|
delete(m.widgetTimers, widget)
|
|
delete(m.timerCallbacks, widget)
|
|
}
|
|
m.timerMutex.Unlock()
|
|
|
|
// Clear maps
|
|
m.widgets = make(map[int32]*Widget)
|
|
m.widgetsByDBID = make(map[int32]*Widget)
|
|
}
|
|
|
|
// GetStatistics returns widget statistics
|
|
func (m *Manager) GetStatistics() map[string]interface{} {
|
|
m.mutex.RLock()
|
|
defer m.mutex.RUnlock()
|
|
|
|
stats := make(map[string]interface{})
|
|
stats["total_widgets"] = len(m.widgets)
|
|
stats["door_count"] = len(m.GetDoorWidgets())
|
|
stats["lift_count"] = len(m.GetLiftWidgets())
|
|
stats["open_count"] = len(m.GetOpenWidgets())
|
|
|
|
m.timerMutex.Lock()
|
|
stats["active_timers"] = len(m.widgetTimers)
|
|
m.timerMutex.Unlock()
|
|
|
|
return stats
|
|
}
|