package cview

import (
	
	
	

	
)

// TabbedPanels is a tabbed container for other primitives. The tab switcher
// may be positioned vertically or horizontally, before or after the content.
type TabbedPanels struct {
	*Flex
	Switcher *TextView
	panels   *Panels

	tabLabels  map[string]string
	currentTab string

	dividerStart string
	dividerMid   string
	dividerEnd   string

	switcherVertical     bool
	switcherAfterContent bool
	switcherHeight       int

	width, lastWidth int

	setFocus func(Primitive)

	sync.RWMutex
}

// NewTabbedPanels returns a new TabbedPanels object.
func () *TabbedPanels {
	 := &TabbedPanels{
		Flex:       NewFlex(),
		Switcher:   NewTextView(),
		panels:     NewPanels(),
		dividerMid: string(BoxDrawingsDoubleVertical),
		dividerEnd: string(BoxDrawingsLightVertical),
		tabLabels:  make(map[string]string),
	}

	 := .Switcher
	.SetDynamicColors(true)
	.SetHighlightForegroundColor(Styles.InverseTextColor)
	.SetHighlightBackgroundColor(Styles.PrimaryTextColor)
	.SetRegions(true)
	.SetScrollable(true)
	.SetWrap(true)
	.SetWordWrap(true)
	.SetHighlightedFunc(func(, ,  []string) {
		if len() == 0 {
			return
		}

		.ScrollToHighlight()
		.SetCurrentTab([0])
		if .setFocus != nil {
			.setFocus(.panels)
		}
	})

	.rebuild()

	return 
}

// SetChangedFunc sets a handler which is called whenever a tab is added,
// selected, reordered or removed.
func ( *TabbedPanels) ( func()) {
	.panels.SetChangedFunc()
}

// AddTab adds a new tab. Tab names should consist only of letters, numbers
// and spaces.
func ( *TabbedPanels) (,  string,  Primitive) {
	.Lock()
	.tabLabels[] = 
	.Unlock()

	.panels.AddPanel(, , true, false)

	.updateAll()
}

// RemoveTab removes a tab.
func ( *TabbedPanels) ( string) {
	.panels.RemovePanel()

	.updateAll()
}

// HasTab returns true if a tab with the given name exists in this object.
func ( *TabbedPanels) ( string) bool {
	.RLock()
	defer .RUnlock()

	for ,  := range .panels.panels {
		if .Name ==  {
			return true
		}
	}
	return false
}

// SetCurrentTab sets the currently visible tab.
func ( *TabbedPanels) ( string) {
	.Lock()

	if .currentTab ==  {
		.Unlock()
		return
	}

	.currentTab = 

	.updateAll()

	.Unlock()

	 := .Switcher.GetHighlights()
	var  bool
	for ,  := range  {
		if  ==  {
			 = true
			break
		}
	}
	if ! {
		.Switcher.Highlight(.currentTab)
	}
	.Switcher.ScrollToHighlight()
}

// GetCurrentTab returns the currently visible tab.
func ( *TabbedPanels) () string {
	.RLock()
	defer .RUnlock()
	return .currentTab
}

// SetTabLabel sets the label of a tab.
func ( *TabbedPanels) (,  string) {
	.Lock()
	defer .Unlock()

	if .tabLabels[] ==  {
		return
	}

	.tabLabels[] = 
	.updateTabLabels()
}

// SetTabTextColor sets the color of the tab text.
func ( *TabbedPanels) ( tcell.Color) {
	.Switcher.SetTextColor()
}

// SetTabTextColorFocused sets the color of the tab text when the tab is in focus.
func ( *TabbedPanels) ( tcell.Color) {
	.Switcher.SetHighlightForegroundColor()
}

// SetTabBackgroundColor sets the background color of the tab.
func ( *TabbedPanels) ( tcell.Color) {
	.Switcher.SetBackgroundColor()
}

// SetTabBackgroundColorFocused sets the background color of the tab when the
// tab is in focus.
func ( *TabbedPanels) ( tcell.Color) {
	.Switcher.SetHighlightBackgroundColor()
}

// SetTabSwitcherDivider sets the tab switcher divider text. Color tags are supported.
func ( *TabbedPanels) (, ,  string) {
	.Lock()
	defer .Unlock()
	.dividerStart, .dividerMid, .dividerEnd = , , 
}

// SetTabSwitcherHeight sets the tab switcher height. This setting only applies
// when rendering horizontally. A value of 0 (the default) indicates the height
// should automatically adjust to fit all of the tab labels.
func ( *TabbedPanels) ( int) {
	.Lock()
	defer .Unlock()

	.switcherHeight = 
	.rebuild()
}

// SetTabSwitcherVertical sets the orientation of the tab switcher.
func ( *TabbedPanels) ( bool) {
	.Lock()
	defer .Unlock()

	if .switcherVertical ==  {
		return
	}

	.switcherVertical = 
	.rebuild()
}

// SetTabSwitcherAfterContent sets whether the tab switcher is positioned after content.
func ( *TabbedPanels) ( bool) {
	.Lock()
	defer .Unlock()

	if .switcherAfterContent ==  {
		return
	}

	.switcherAfterContent = 
	.rebuild()
}

func ( *TabbedPanels) () {
	 := .Flex
	if .switcherVertical {
		.SetDirection(FlexColumn)
	} else {
		.SetDirection(FlexRow)
	}
	.RemoveItem(.panels)
	.RemoveItem(.Switcher)
	if .switcherAfterContent {
		.AddItem(.panels, 0, 1, true)
		.AddItem(.Switcher, 1, 1, false)
	} else {
		.AddItem(.Switcher, 1, 1, false)
		.AddItem(.panels, 0, 1, true)
	}

	.updateTabLabels()

	.Switcher.SetMaxLines(.switcherHeight)
}

func ( *TabbedPanels) () {
	if len(.panels.panels) == 0 {
		.Switcher.SetText("")
		.Flex.ResizeItem(.Switcher, 0, 1)
		return
	}

	 := 0
	for ,  := range .panels.panels {
		 := .tabLabels[.Name]
		if len() >  {
			 = len()
		}
	}

	var  bytes.Buffer
	if !.switcherVertical {
		.WriteString(.dividerStart)
	}
	 := len(.panels.panels)
	 := []byte(" ")
	for ,  := range .panels.panels {
		if  > 0 && .switcherVertical {
			.WriteRune('\n')
		}

		if .switcherVertical && .switcherAfterContent {
			.WriteString(.dividerMid)
			.WriteRune(' ')
		}

		 := .tabLabels[.Name]
		if !.switcherVertical {
			 = " " + 
		}

		if .switcherVertical {
			 = bytes.Repeat([]byte(" "), -len()+1)
		}

		.WriteString(fmt.Sprintf(`["%s"]%s%s[""]`, .Name, , ))

		if  == -1 && !.switcherVertical {
			.WriteString(.dividerEnd)
		} else if !.switcherAfterContent {
			.WriteString(.dividerMid)
		}
	}
	.Switcher.SetText(.String())

	var  int
	if .switcherVertical {
		 =  + 2
	} else {
		if .switcherHeight > 0 {
			 = .switcherHeight
		} else {
			 = len(WordWrap(.Switcher.GetText(true), .width))
			if  < 1 {
				 = 1
			}
		}
	}
	.Flex.ResizeItem(.Switcher, , 1)
}

func ( *TabbedPanels) () {
	 := .panels.panels

	var  string

	var  bool
	for ,  := range  {
		if .Name == .currentTab {
			 = .Name
			 = true
			break
		}
	}
	if ! {
		for ,  := range  {
			if .Name != "" {
				 = .Name
				break
			}
		}
	}

	if .currentTab !=  {
		.SetCurrentTab()
		return
	}

	for ,  := range  {
		if .Name == .currentTab {
			.panels.ShowPanel(.Name)
		} else {
			.panels.HidePanel(.Name)
		}
	}
}

func ( *TabbedPanels) () {
	.updateTabLabels()
	.updateVisibleTabs()
}

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

	.Box.Draw()

	_, _, .width, _ = .GetInnerRect()
	if .width != .lastWidth {
		.updateTabLabels()
	}
	.lastWidth = .width

	.Flex.Draw()
}

// InputHandler returns the handler for this primitive.
func ( *TabbedPanels) () func( *tcell.EventKey,  func( Primitive)) {
	return .WrapInputHandler(func( *tcell.EventKey,  func( Primitive)) {
		if .setFocus == nil {
			.setFocus = 
		}
		.Flex.InputHandler()(, )
	})
}

// MouseHandler returns the mouse handler for this primitive.
func ( *TabbedPanels) () func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
	return .WrapMouseHandler(func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
		if .setFocus == nil {
			.setFocus = 
		}

		,  := .Position()
		if !.InRect(, ) {
			return false, nil
		}

		if .Switcher.InRect(, ) {
			if .setFocus != nil {
				defer .setFocus(.panels)
			}
			defer .Switcher.MouseHandler()(, , )
			return true, nil
		}

		return .Flex.MouseHandler()(, , )
	})
}