// 15 august 2015
#import "uipriv_darwin.h"

// TODO need to jiggle on tab change too (second page disabled tab label initially ambiguous)

@interface tabPage : NSObject {
	uiprivSingleChildConstraints constraints;
	int margined;
	NSView *view;		// the NSTabViewItem view itself
	NSObject *pageID;
}
@property uiControl *c;
@property NSLayoutPriority oldHorzHuggingPri;
@property NSLayoutPriority oldVertHuggingPri;
- (id)initWithView:(NSView *)v pageID:(NSObject *)o;
- (NSView *)childView;
- (void)establishChildConstraints;
- (void)removeChildConstraints;
- (int)isMargined;
- (void)setMargined:(int)m;
@end

struct uiTab {
	uiDarwinControl c;
	NSTabView *tabview;
	NSMutableArray *pages;
	NSLayoutPriority horzHuggingPri;
	NSLayoutPriority vertHuggingPri;
	void (*onSelected)(uiTab *, void *);
	void *onSelectedData;
};

@implementation tabPage

- (id)initWithView:(NSView *)v pageID:(NSObject *)o
{
	self = [super init];
	if (self != nil) {
		self->view = [v retain];
		self->pageID = [o retain];
	}
	return self;
}

- (void)dealloc
{
	[self removeChildConstraints];
	[self->view release];
	[self->pageID release];
	[super dealloc];
}

- (NSView *)childView
{
	return (NSView *) uiControlHandle(self.c);
}

- (void)establishChildConstraints
{
	[self removeChildConstraints];
	if (self.c == NULL)
		return;
	uiprivSingleChildConstraintsEstablish(&(self->constraints),
		self->view, [self childView],
		uiDarwinControlHugsTrailingEdge(uiDarwinControl(self.c)),
		uiDarwinControlHugsBottom(uiDarwinControl(self.c)),
		self->margined,
		@"uiTab page");
}

- (void)removeChildConstraints
{
	uiprivSingleChildConstraintsRemove(&(self->constraints), self->view);
}

- (int)isMargined
{
	return self->margined;
}

- (void)setMargined:(int)m
{
	self->margined = m;
	uiprivSingleChildConstraintsSetMargined(&(self->constraints), self->margined);
}

@end

@interface uiprivTabDelegate: NSObject<NSTabViewDelegate> {
	uiTab *tab;
}
- (id)initWithTab:(uiTab *)t;
- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem;
@end

@implementation uiprivTabDelegate

- (id)initWithTab:(uiTab *)t
{
	self = [super init];
	if (self)
		self->tab = t;
	return self;

}

- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
{
	uiTab *t = self->tab;
	(*(t->onSelected))(t, t->onSelectedData);
}

@end

static void defaultOnSelected(uiTab *t, void*data)
{
	// do nothing
}

static void uiTabDestroy(uiControl *c)
{
	uiTab *t = uiTab(c);
	tabPage *page;
	uiprivTabDelegate *delegate;

	uiTabOnSelected(t, defaultOnSelected, NULL);
	// first remove all tab pages so we can destroy all the children
	while ([t->tabview numberOfTabViewItems] != 0)
		[t->tabview removeTabViewItem:[t->tabview tabViewItemAtIndex:0]];
	// then destroy all the children
	for (page in t->pages) {
		[page removeChildConstraints];
		uiControlSetParent(page.c, NULL);
		uiDarwinControlSetSuperview(uiDarwinControl(page.c), nil);
		uiControlDestroy(page.c);
	}
	// and finally destroy ourselves
	delegate = [t->tabview delegate];
	[t->tabview setDelegate:nil];
	[delegate release];
	[t->pages release];
	[t->tabview release];
	uiFreeControl(uiControl(t));
}

uiDarwinControlDefaultHandle(uiTab, tabview)
uiDarwinControlDefaultParent(uiTab, tabview)
uiDarwinControlDefaultSetParent(uiTab, tabview)
uiDarwinControlDefaultToplevel(uiTab, tabview)
uiDarwinControlDefaultVisible(uiTab, tabview)
uiDarwinControlDefaultShow(uiTab, tabview)
uiDarwinControlDefaultHide(uiTab, tabview)
uiDarwinControlDefaultEnabled(uiTab, tabview)
uiDarwinControlDefaultEnable(uiTab, tabview)
uiDarwinControlDefaultDisable(uiTab, tabview)

static void uiTabSyncEnableState(uiDarwinControl *c, int enabled)
{
	uiTab *t = uiTab(c);
	tabPage *page;

	if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(t), enabled))
		return;
	for (page in t->pages)
		uiDarwinControlSyncEnableState(uiDarwinControl(page.c), enabled);
}

uiDarwinControlDefaultSetSuperview(uiTab, tabview)

static void tabRelayout(uiTab *t)
{
	tabPage *page;

	for (page in t->pages)
		[page establishChildConstraints];
	// and this gets rid of some weird issues with regards to box alignment
	uiprivJiggleViewLayout(t->tabview);
}

BOOL uiTabHugsTrailingEdge(uiDarwinControl *c)
{
	uiTab *t = uiTab(c);

	return t->horzHuggingPri < NSLayoutPriorityWindowSizeStayPut;
}

BOOL uiTabHugsBottom(uiDarwinControl *c)
{
	uiTab *t = uiTab(c);

	return t->vertHuggingPri < NSLayoutPriorityWindowSizeStayPut;
}

static void uiTabChildEdgeHuggingChanged(uiDarwinControl *c)
{
	uiTab *t = uiTab(c);

	tabRelayout(t);
}

static NSLayoutPriority uiTabHuggingPriority(uiDarwinControl *c, NSLayoutConstraintOrientation orientation)
{
	uiTab *t = uiTab(c);

	if (orientation == NSLayoutConstraintOrientationHorizontal)
		return t->horzHuggingPri;
	return t->vertHuggingPri;
}

static void uiTabSetHuggingPriority(uiDarwinControl *c, NSLayoutPriority priority, NSLayoutConstraintOrientation orientation)
{
	uiTab *t = uiTab(c);

	if (orientation == NSLayoutConstraintOrientationHorizontal)
		t->horzHuggingPri = priority;
	else
		t->vertHuggingPri = priority;
	uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(t));
}

static void uiTabChildVisibilityChanged(uiDarwinControl *c)
{
	uiTab *t = uiTab(c);

	tabRelayout(t);
}

void uiTabAppend(uiTab *t, const char *name, uiControl *child)
{
	uiTabInsertAt(t, name, [t->pages count], child);
}

void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child)
{
	tabPage *page;
	NSView *view;
	NSTabViewItem *i;
	NSObject *pageID;

	uiControlSetParent(child, uiControl(t));

	view = [[[NSView alloc] initWithFrame:NSZeroRect] autorelease];
	// note: if we turn off the autoresizing mask, nothing shows up
	uiDarwinControlSetSuperview(uiDarwinControl(child), view);
	uiDarwinControlSyncEnableState(uiDarwinControl(child), uiControlEnabledToUser(uiControl(t)));

	// the documentation says these can be nil but the headers say these must not be; let's be safe and make them non-nil anyway
	pageID = [NSObject new];
	page = [[[tabPage alloc] initWithView:view pageID:pageID] autorelease];
	page.c = child;

	// don't hug, just in case we're a stretchy tab
	page.oldHorzHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(page.c), NSLayoutConstraintOrientationHorizontal);
	page.oldVertHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(page.c), NSLayoutConstraintOrientationVertical);
	uiDarwinControlSetHuggingPriority(uiDarwinControl(page.c), NSLayoutPriorityDefaultLow, NSLayoutConstraintOrientationHorizontal);
	uiDarwinControlSetHuggingPriority(uiDarwinControl(page.c), NSLayoutPriorityDefaultLow, NSLayoutConstraintOrientationVertical);

	[t->pages insertObject:page atIndex:n];

	i = [[[NSTabViewItem alloc] initWithIdentifier:pageID] autorelease];
	[i setLabel:uiprivToNSString(name)];
	[i setView:view];
	[t->tabview insertTabViewItem:i atIndex:n];

	tabRelayout(t);
}

void uiTabDelete(uiTab *t, int n)
{
	tabPage *page;
	uiControl *child;
	NSTabViewItem *i;

	page = (tabPage *) [t->pages objectAtIndex:n];

	uiDarwinControlSetHuggingPriority(uiDarwinControl(page.c), page.oldHorzHuggingPri, NSLayoutConstraintOrientationHorizontal);
	uiDarwinControlSetHuggingPriority(uiDarwinControl(page.c), page.oldVertHuggingPri, NSLayoutConstraintOrientationVertical);

	child = page.c;
	[page removeChildConstraints];
	[t->pages removeObjectAtIndex:n];

	uiControlSetParent(child, NULL);
	uiDarwinControlSetSuperview(uiDarwinControl(child), nil);

	i = [t->tabview tabViewItemAtIndex:n];
	[t->tabview removeTabViewItem:i];

	tabRelayout(t);
}

int uiTabNumPages(uiTab *t)
{
	return [t->pages count];
}

int uiTabMargined(uiTab *t, int n)
{
	tabPage *page;

	page = (tabPage *) [t->pages objectAtIndex:n];
	return [page isMargined];
}

void uiTabSetMargined(uiTab *t, int n, int margined)
{
	tabPage *page;

	page = (tabPage *) [t->pages objectAtIndex:n];
	[page setMargined:margined];
}


int uiTabSelected(uiTab *t)
{
	NSTabViewItem *selectedTabViewItem = [t->tabview selectedTabViewItem];
	return [t->tabview indexOfTabViewItem:selectedTabViewItem];
}

void uiTabSetSelected(uiTab *t, int index)
{
	[t->tabview selectTabViewItemAtIndex:index];
}

void uiTabOnSelected(uiTab *t, void (*f)(uiTab *, void *), void *data)
{
	t->onSelected = f;
	t->onSelectedData = data;
}

uiTab *uiNewTab(void)
{
	uiTab *t;
	uiprivTabDelegate *delegate;

	uiDarwinNewControl(uiTab, t);

	t->tabview = [[NSTabView alloc] initWithFrame:NSZeroRect];
	delegate = [[uiprivTabDelegate alloc] initWithTab:t];
	[t->tabview setDelegate:delegate];
	// also good for NSTabView (same selector and everything)
	uiDarwinSetControlFont((NSControl *) (t->tabview), NSRegularControlSize);

	t->pages = [NSMutableArray new];

	// default to low hugging to not hug edges
	t->horzHuggingPri = NSLayoutPriorityDefaultLow;
	t->vertHuggingPri = NSLayoutPriorityDefaultLow;

	uiTabOnSelected(t, defaultOnSelected, NULL);
	return t;
}
