1// workspace_operations.go - Workspace operation methods with validation and safety
2package browser
3
4import (
5 "fmt"
6 "log"
7
8 "github.com/bnema/dumber/pkg/webkit"
9)
10
11// SplitPane performs a split operation with validation and safety checks
12func (wm *WorkspaceManager) SplitPane(target *paneNode, direction string) (*paneNode, error) {
13 if wm == nil {
14 return nil, fmt.Errorf("workspace manager is nil")
15 }
16
17 // Validate direction parameter
18 validDirections := map[string]bool{
19 "left": true,
20 "right": true,
21 "up": true,
22 "down": true,
23 }
24 if !validDirections[direction] {
25 return nil, fmt.Errorf("invalid split direction '%s', expected one of: left, right, up, down", direction)
26 }
27
28 log.Printf("[workspace] Starting split operation: target=%p direction=%s", target, direction)
29
30 // Step 1: Validate geometry constraints (only in DebugBasic+)
31 if wm.debugLevel >= DebugBasic {
32 validation := wm.geometryValidator.ValidateSplit(target, direction)
33 if !validation.IsValid {
34 if wm.debugLevel == DebugFull {
35 return nil, fmt.Errorf("split validation failed: %s", validation.Reason)
36 }
37 log.Printf("[workspace] WARNING: Split validation failed but allowing operation: %s", validation.Reason)
38 }
39
40 // Log if re-validation will be needed due to pending widget allocation
41 if validation.RequiresRevalidation {
42 log.Printf("[workspace] Split validation passed with pending allocation - operation will proceed")
43 }
44
45 // Step 3: Validate tree invariants before operation
46 if err := wm.treeValidator.ValidateTree(wm.root, "before_split"); err != nil {
47 if wm.debugLevel == DebugFull {
48 return nil, fmt.Errorf("tree validation failed before split: %w", err)
49 }
50 log.Printf("[workspace] WARNING: Tree validation failed before split but allowing operation: %v", err)
51 }
52 }
53
54 // Step 2: Execute directly if we're already on the GTK main thread
55 if webkit.IsMainThread() {
56 log.Printf("[workspace] Already on main thread, executing split directly")
57 newNode, err := wm.splitNode(target, direction, nil)
58 if err != nil {
59 return nil, err
60 }
61
62 if wm.debugLevel >= DebugBasic {
63 if err := wm.treeValidator.ValidateTree(wm.root, "after_split"); err != nil {
64 log.Printf("[workspace] Tree validation failed after split: %v", err)
65 }
66 }
67
68 // Tree rebalancing is only needed after close promotions. Splits have correct allocation from GTK.
69
70 log.Printf("[workspace] Split operation completed successfully (direct execution): newNode=%p", newNode)
71 return newNode, nil
72 }
73
74 // Step 3: Not on main thread, marshal via IdleAdd
75 log.Printf("[workspace] Not on main thread, marshalling split via IdleAdd")
76 var newNode *paneNode
77 var splitErr error
78 done := make(chan struct{})
79
80 _ = webkit.IdleAdd(func() bool {
81 newNode, splitErr = wm.splitNode(target, direction, nil)
82 if splitErr == nil {
83 if wm.debugLevel >= DebugBasic {
84 if verr := wm.treeValidator.ValidateTree(wm.root, "after_split"); verr != nil {
85 log.Printf("[workspace] Tree validation failed after split: %v", verr)
86 }
87 }
88 }
89 close(done)
90 return false
91 })
92
93 <-done
94
95 if splitErr != nil {
96 return nil, splitErr
97 }
98
99 log.Printf("[workspace] Split operation completed successfully: newNode=%p", newNode)
100 return newNode, nil
101}
102
103// ClosePane performs a close operation with validation and safety checks
104func (wm *WorkspaceManager) ClosePane(node *paneNode) error {
105 if wm == nil {
106 return fmt.Errorf("workspace manager is nil")
107 }
108
109 log.Printf("[workspace] Starting close operation: node=%p", node)
110 wm.paneCloseLogf("start bulletproof close node=%p", node)
111 wm.dumpTreeState("before_close")
112
113 // Step 1: Validate tree invariants before operation (only in DebugBasic+)
114 if wm.debugLevel >= DebugBasic {
115 if err := wm.treeValidator.ValidateTree(wm.root, "before_close"); err != nil {
116 if wm.debugLevel == DebugFull {
117 return fmt.Errorf("tree validation failed before close: %w", err)
118 }
119 log.Printf("[workspace] WARNING: Tree validation failed before close but allowing operation: %v", err)
120 }
121 }
122
123 // Step 3: Check if this is a stacked pane and use enhanced lifecycle management
124 if node.parent != nil && node.parent.isStacked {
125 log.Printf("[workspace] Using enhanced stack lifecycle management for close")
126 return wm.stackLifecycleManager.CloseStackedPaneWithLifecycle(node)
127 }
128
129 // Step 4: Execute directly when already on the GTK main thread
130 if webkit.IsMainThread() {
131 log.Printf("[workspace] Already on main thread, executing close directly")
132
133 wm.paneCloseLogf("invoking closePane node=%p", node)
134 promoted, err := wm.closePane(node)
135 if err != nil {
136 wm.paneCloseLogf("closePane failed node=%p err=%v", node, err)
137 wm.dumpTreeState("after_close_error")
138 return err
139 }
140
141 if wm.debugLevel >= DebugBasic {
142 if err := wm.treeValidator.ValidateTree(wm.root, "after_close"); err != nil {
143 log.Printf("[workspace] Tree validation failed after close: %v", err)
144 }
145 }
146 wm.paneCloseLogf("closePane succeeded node=%p promoted=%p root=%p", node, promoted, wm.root)
147 wm.dumpTreeState("after_close_success")
148
149 if wm.treeRebalancer != nil {
150 if err := wm.treeRebalancer.RebalanceAfterClose(node, promoted); err != nil {
151 log.Printf("[workspace] Tree rebalancing failed after close: %v", err)
152 }
153 }
154
155 log.Printf("[workspace] Close operation completed successfully (direct execution)")
156 return nil
157 }
158
159 // Step 5: Not on main thread, marshal via IdleAdd
160 log.Printf("[workspace] Not on main thread, marshalling close via IdleAdd")
161 var promoted *paneNode
162 var closeErr error
163 done := make(chan struct{})
164
165 _ = webkit.IdleAdd(func() bool {
166 wm.paneCloseLogf("invoking closePane node=%p", node)
167 promoted, closeErr = wm.closePane(node)
168 if closeErr != nil {
169 wm.paneCloseLogf("closePane failed node=%p err=%v", node, closeErr)
170 wm.dumpTreeState("after_close_error")
171 } else {
172 if wm.debugLevel >= DebugBasic {
173 if verr := wm.treeValidator.ValidateTree(wm.root, "after_close"); verr != nil {
174 log.Printf("[workspace] Tree validation failed after close: %v", verr)
175 }
176 }
177 wm.paneCloseLogf("closePane succeeded node=%p promoted=%p root=%p", node, promoted, wm.root)
178 wm.dumpTreeState("after_close_success")
179
180 if wm.treeRebalancer != nil {
181 if rerr := wm.treeRebalancer.RebalanceAfterClose(node, promoted); rerr != nil {
182 log.Printf("[workspace] Tree rebalancing failed after close: %v", rerr)
183 }
184 }
185 }
186 close(done)
187 return false
188 })
189
190 <-done
191
192 if closeErr != nil {
193 return closeErr
194 }
195
196 log.Printf("[workspace] Close operation completed successfully")
197 return nil
198}
199
200// StackPane performs a stack operation with validation and safety checks
201func (wm *WorkspaceManager) StackPane(target *paneNode) (*paneNode, error) {
202 if wm == nil {
203 return nil, fmt.Errorf("workspace manager is nil")
204 }
205
206 log.Printf("[workspace] Starting stack operation: target=%p", target)
207
208 // Step 1: Validate stack operation constraints (only in DebugBasic+)
209 if wm.debugLevel >= DebugBasic {
210 validation := wm.geometryValidator.ValidateStackOperation(target)
211 if !validation.IsValid {
212 if wm.debugLevel == DebugFull {
213 return nil, fmt.Errorf("stack validation failed: %s", validation.Reason)
214 }
215 log.Printf("[workspace] WARNING: Stack validation failed but allowing operation: %s", validation.Reason)
216 }
217
218 // Log if re-validation will be needed due to pending widget allocation
219 if validation.RequiresRevalidation {
220 log.Printf("[workspace] Stack validation passed with pending allocation - operation will proceed")
221 }
222 }
223
224 // Step 2: Validate tree invariants before operation (only in DebugBasic+)
225 if wm.debugLevel >= DebugBasic {
226 if err := wm.treeValidator.ValidateTree(wm.root, "before_stack"); err != nil {
227 if wm.debugLevel == DebugFull {
228 return nil, fmt.Errorf("tree validation failed before stack: %w", err)
229 }
230 log.Printf("[workspace] WARNING: Tree validation failed before stack but allowing operation: %v", err)
231 }
232 }
233
234 // Step 3: Execute directly if already on the GTK main thread
235 if webkit.IsMainThread() {
236 log.Printf("[workspace] Already on main thread, executing stack directly")
237 newNode, err := wm.stackedPaneManager.StackPane(target)
238 if err != nil {
239 return nil, err
240 }
241
242 if wm.debugLevel >= DebugBasic {
243 if err := wm.treeValidator.ValidateTree(wm.root, "after_stack"); err != nil {
244 log.Printf("[workspace] Tree validation failed after stack: %v", err)
245 }
246 }
247
248 log.Printf("[workspace] Stack operation completed successfully (direct execution): newNode=%p", newNode)
249 return newNode, nil
250 }
251
252 // Step 4: Not on main thread, marshal via IdleAdd
253 log.Printf("[workspace] Not on main thread, marshalling stack via IdleAdd")
254 var newNode *paneNode
255 var stackErr error
256 done := make(chan struct{})
257
258 _ = webkit.IdleAdd(func() bool {
259 newNode, stackErr = wm.stackedPaneManager.StackPane(target)
260 if stackErr == nil {
261 if wm.debugLevel >= DebugBasic {
262 if verr := wm.treeValidator.ValidateTree(wm.root, "after_stack"); verr != nil {
263 log.Printf("[workspace] Tree validation failed after stack: %v", verr)
264 }
265 }
266 }
267 close(done)
268 return false
269 })
270
271 <-done
272
273 if stackErr != nil {
274 return nil, stackErr
275 }
276
277 log.Printf("[workspace] Stack operation completed successfully: newNode=%p", newNode)
278 return newNode, nil
279}
280
281// EnableEnhancedMode enables all enhanced validation features
282func (wm *WorkspaceManager) EnableEnhancedMode() {
283 if wm.treeValidator != nil {
284 wm.treeValidator.Enable()
285 }
286 if wm.treeRebalancer != nil {
287 wm.treeRebalancer.Enable()
288 }
289 log.Printf("[workspace] Enhanced validation mode enabled")
290}
291
292// DisableEnhancedMode disables enhanced features for performance
293func (wm *WorkspaceManager) DisableEnhancedMode() {
294 if wm.treeValidator != nil {
295 wm.treeValidator.Disable()
296 }
297 if wm.treeRebalancer != nil {
298 wm.treeRebalancer.Disable()
299 }
300 log.Printf("[workspace] Enhanced validation mode disabled")
301}
302
303// SetEnhancedDebugMode enables/disables debug mode for all enhanced validation components
304func (wm *WorkspaceManager) SetEnhancedDebugMode(debug bool) {
305 if wm.treeValidator != nil {
306 wm.treeValidator.SetDebugMode(debug)
307 }
308 if wm.geometryValidator != nil {
309 wm.geometryValidator.SetDebugMode(debug)
310 }
311 log.Printf("[workspace] Enhanced debug mode set to: %v", debug)
312}
313
314// GetEnhancedStats returns comprehensive statistics about all enhanced validation components
315func (wm *WorkspaceManager) GetEnhancedStats() map[string]interface{} {
316 stats := make(map[string]interface{})
317
318 if wm.treeValidator != nil {
319 stats["tree_validation"] = wm.treeValidator.GetValidationStats()
320 }
321
322 if wm.treeRebalancer != nil {
323 stats["tree_rebalancing"] = wm.treeRebalancer.GetRebalancingStats()
324 }
325
326 // Geometry validator no longer tracks stats - simplified
327
328 return stats
329}
330
331// ValidateWorkspaceIntegrity performs a comprehensive validation of the workspace
332func (wm *WorkspaceManager) ValidateWorkspaceIntegrity() error {
333 log.Printf("[workspace] Performing comprehensive workspace integrity check")
334
335 // Tree structure validation
336 if wm.treeValidator != nil {
337 if err := wm.treeValidator.ValidateTree(wm.root, "integrity_check"); err != nil {
338 return fmt.Errorf("tree validation failed: %w", err)
339 }
340 }
341
342 // Geometry validation simplified - ValidateWorkspaceLayout removed
343
344 log.Printf("[workspace] Workspace integrity check completed successfully")
345 return nil
346}
347
348// ShutdownEnhancedComponents gracefully shuts down all enhanced validation components
349func (wm *WorkspaceManager) ShutdownEnhancedComponents() {
350 log.Printf("[workspace] Shutting down enhanced validation components")
351
352 // Other components don't require explicit shutdown currently
353 log.Printf("[workspace] Enhanced validation components shutdown complete")
354}