package cview

import (
	

	
)

// WindowManager provides an area which windows may be added to.
type WindowManager struct {
	*Box

	windows []*Window

	sync.RWMutex
}

// NewWindowManager returns a new window manager.
func () *WindowManager {
	return &WindowManager{
		Box: NewBox(),
	}
}

// Add adds a window to the manager.
func ( *WindowManager) ( ...*Window) {
	.Lock()
	defer .Unlock()

	for ,  := range  {
		.SetBorder(true)
	}

	.windows = append(.windows, ...)
}

// Clear removes all windows from the manager.
func ( *WindowManager) () {
	.Lock()
	defer .Unlock()

	.windows = nil
}

// Focus is called when this primitive receives focus.
func ( *WindowManager) ( func( Primitive)) {
	.Lock()
	defer .Unlock()

	if len(.windows) == 0 {
		return
	}

	.windows[len(.windows)-1].Focus()
}

// HasFocus returns whether or not this primitive has focus.
func ( *WindowManager) () bool {
	.RLock()
	defer .RUnlock()

	for ,  := range .windows {
		if .HasFocus() {
			return true
		}
	}

	return false
}

// Draw draws this primitive onto the screen.
func ( *WindowManager) ( tcell.Screen) {
	if !.GetVisible() {
		return
	}

	.RLock()
	defer .RUnlock()

	.Box.Draw()

	, , ,  := .GetInnerRect()

	var  bool
	for ,  := range .windows {
		if !.fullscreen || !.GetVisible() {
			continue
		}

		 = true
		.SetRect(-1, , +2, +1)

		.Draw()
	}
	if  {
		return
	}

	for ,  := range .windows {
		if !.GetVisible() {
			continue
		}

		// Reposition out of bounds windows
		 := 3
		, , ,  := .GetRect()
		,  := , 
		if  > +- {
			 =  +  - 
		}
		if + < + {
			 =  -  + 
		}
		if  > +- {
			 =  +  - 
		}
		if  <  {
			 =  // No top margin
		}
		if  !=  ||  !=  {
			.SetRect(, , , )
		}

		.Draw()
	}
}

// MouseHandler returns the mouse handler for this primitive.
func ( *WindowManager) () func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
	return .WrapMouseHandler(func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
		if !.InRect(.Position()) {
			return false, nil
		}

		if  == MouseMove {
			,  := .Position()

			for ,  := range .windows {
				if .dragWX != -1 || .dragWY != -1 {
					 := .x - 
					 := .y - 

					.x -=  + .dragWX
					.y -=  + .dragWY

					.updateInnerRect()
					 = true
				}

				if .dragX != 0 {
					if .dragX == -1 {
						 := .x - 

						if .width+ >= Styles.WindowMinWidth {
							.x -= 
							.width += 
						}
					} else {
						 :=  - (.x + .width) + 1

						if .width+ >= Styles.WindowMinWidth {
							.width += 
						}
					}

					.updateInnerRect()
					 = true
				}

				if .dragY != 0 {
					if .dragY == -1 {
						 :=  - (.y + .height) + 1

						if .height+ >= Styles.WindowMinHeight {
							.height += 
						}
					} else {
						 := .y - 

						if .height+ >= Styles.WindowMinHeight {
							.y -= 
							.height += 
						}
					}

					.updateInnerRect()
					 = true
				}
			}
		} else if  == MouseLeftUp {
			for ,  := range .windows {
				.dragX, .dragY = 0, 0
				.dragWX, .dragWY = -1, -1
			}
		}

		// Focus window on mousedown
		var (
			      *Window
			 int
		)
		for  := len(.windows) - 1;  >= 0; -- {
			if .windows[].InRect(.Position()) {
				 = .windows[]
				 = 
				break
			}
		}
		if  != nil {
			if  == MouseLeftDown ||  == MouseMiddleDown ||  == MouseRightDown {
				for ,  := range .windows {
					if  !=  {
						.Blur()
					}
				}

				.windows = append(append(.windows[:], .windows[+1:]...), )
			}

			return .MouseHandler()(, , )
		}

		return , nil
	})
}