package ui

import (
	"opslag.de/schobers/geom"
	"opslag.de/schobers/zntg"
)

var _ Control = &Overlays{}

type OverlayVisibilityChangedArgs struct {
	Name    string
	Visible bool
}

type Overlays struct {
	Proxy

	overlays map[string]Overlay
	order    []string
	visible  map[string]bool

	overlayHidden     zntg.Events
	overlayShown      zntg.Events
	visibilityChanged zntg.Events
}

func NewOverlays(over Control) *Overlays {
	return &Overlays{
		Proxy: Proxy{Content: over},

		overlays: map[string]Overlay{},
		visible:  map[string]bool{},
	}
}

func (o *Overlays) setVisibility(name string, visible bool) {
	if o.visible[name] == visible {
		return
	}
	o.visible[name] = visible
	overlay, ok := o.overlays[name].(Overlay)
	if ok {
		if visible {
			overlay.Shown()
		} else {
			overlay.Hidden()
		}
	}
	o.visibilityChanged.Notify(OverlayVisibilityChangedArgs{Name: name, Visible: visible})
	if visible {
		o.overlayShown.Notify(name)
	} else {
		o.overlayHidden.Notify(name)
	}
}

func (o *Overlays) AddOnTop(name string, overlay Overlay, visible bool) {
	o.order = append(o.order, name)
	o.overlays[name] = overlay
	o.visible[name] = visible
}

func (o *Overlays) AddOnBottom(name string, overlay Overlay, visible bool) {
	o.order = append([]string{name}, o.order...)
	o.overlays[name] = overlay
	o.visible[name] = visible
}

func (o *Overlays) Arrange(ctx Context, bounds geom.RectangleF32, offset geom.PointF32, parent Control) {
	o.Proxy.Arrange(ctx, bounds, offset, parent)
	for _, overlay := range o.overlays {
		overlay.Arrange(ctx, bounds, offset, parent)
	}
}

func (o *Overlays) Handle(ctx Context, e Event) bool {
	for overlay, visible := range o.visible {
		if visible {
			o.overlays[overlay].Handle(ctx, e) // ignore handled state on overlays
		}
	}
	return o.Proxy.Handle(ctx, e)
}

func (o *Overlays) Hide(name string) {
	o.visible[name] = false
}

func (o *Overlays) Render(ctx Context) {
	o.Proxy.Render(ctx)
	for overlay, visible := range o.visible {
		if visible {
			o.overlays[overlay].Render(ctx)
		}
	}
}

func (o *Overlays) SetVisibility(name string, visible bool) { o.setVisibility(name, visible) }

func (o *Overlays) Show(name string) { o.SetVisibility(name, true) }

func (o *Overlays) Toggle(name string) { o.SetVisibility(name, false) }