// TODO(anton): This code should be generated by some metaprogram at some point.


// Macro that generalises the code for setting the next implementation on
// a particular stack.
// The convention is that a node type has UI_<name_upper>Node,
// and the corresponding stack struct in the UI state has a top pointer, a free pointer and an auto_pop B32 value.
// And that struct is called <name_lower>_stack.
// The nodes have values of different types, which the <type> argument to this macro designates.
// A ParentNode, for example, has a UI_Box *value, and the PrefWidth has a UI_Size value.
#define UI_stack_top_impl(state, name_upper, name_lower) \
return state->name_lower##_stack.top->v;

#define UI_stack_push_impl(state, name_upper, name_lower, type, new_value) \
UI_##name_upper##Node *node = state->name_lower##_stack.free; \
if(node != 0) {StackPop(state->name_lower##_stack.free);} \
else {node = PushArrayZero(UI_frame_arena(), UI_##name_upper##Node, 1);} \
type old_value = state->name_lower##_stack.top->v; \
node->v = new_value; \
StackPush(state->name_lower##_stack.top, node); \
state->name_lower##_stack.auto_pop = 0; \
return old_value;

#define UI_stack_pop_impl(state, name_upper, name_lower) \
UI_##name_upper##Node *popped = state->name_lower##_stack.top;\
if(popped != &state->name_lower##_nil_stack_top)\
{\
StackPop(state->name_lower##_stack.top);\
StackPush(state->name_lower##_stack.free, popped);\
state->name_lower##_stack.auto_pop = 0;\
}\
return popped->v;\

// NOTE(anton): Only difference from push is auto pop = 1?
#define UI_stack_set_next_impl(state, name_upper, name_lower, type, new_value) \
UI_##name_upper##Node *node = state->name_lower##_stack.free; \
if(node != 0) {StackPop(state->name_lower##_stack.free);}\
else {node = PushArray(UI_frame_arena(), UI_##name_upper##Node, 1);}\
type old_value = state->name_lower##_stack.top->v;\
node->v = new_value;\
StackPush(state->name_lower##_stack.top, node);\
state->name_lower##_stack.auto_pop = 1;\
return old_value;


///////////////////////////////////////
//~ Stack functions

//- Top 
root_function UI_Box *UI_top_parent(void) { UI_stack_top_impl(ui_state, Parent, parent) }
root_function UI_BoxFlags UI_top_flags(void) { UI_stack_top_impl(ui_state, Flags, flags) }
root_function F32 UI_top_fixed_x(void) { UI_stack_top_impl(ui_state, FixedX, fixed_x) }
root_function F32 UI_top_fixed_y(void) { UI_stack_top_impl(ui_state, FixedY, fixed_y) }
root_function F32 UI_top_fixed_width(void) { UI_stack_top_impl(ui_state, FixedWidth, fixed_width) }
root_function F32 UI_top_fixed_height(void) { UI_stack_top_impl(ui_state, FixedHeight, fixed_height) }
root_function UI_Key  UI_top_seed_key(void) { UI_stack_top_impl(ui_state, SeedKey, seed_key) }
root_function UI_Size UI_top_pref_width(void) { UI_stack_top_impl(ui_state, PrefWidth, pref_width) }
root_function UI_Size UI_top_pref_height(void) { UI_stack_top_impl(ui_state, PrefHeight, pref_height) }
root_function Axis2 UI_top_child_layout_axis(void) { UI_stack_top_impl(ui_state, ChildLayoutAxis, child_layout_axis) }

//- Push 
root_function UI_Box *UI_push_parent(UI_Box *v) { UI_stack_push_impl(ui_state, Parent, parent, UI_Box *, v) }
root_function UI_BoxFlags UI_push_flags(UI_BoxFlags v) { UI_stack_push_impl(ui_state, Flags, flags, UI_BoxFlags, v) }
root_function F32 UI_push_fixed_x(F32 v) { UI_stack_push_impl(ui_state, FixedX, fixed_x, F32, v) }
root_function F32 UI_push_fixed_y(F32 v) { UI_stack_push_impl(ui_state, FixedY, fixed_y, F32, v) }
root_function F32 UI_push_fixed_width(F32 v) { UI_stack_push_impl(ui_state, FixedWidth, fixed_width, F32, v) }
root_function F32 UI_push_fixed_height(F32 v) { UI_stack_push_impl(ui_state, FixedHeight, fixed_height, F32, v) }
root_function UI_Key UI_push_seed_key(UI_Key v) { UI_stack_push_impl(ui_state, SeedKey, seed_key, UI_Key, v) }
root_function UI_Size UI_push_pref_width(UI_Size v) { UI_stack_push_impl(ui_state, PrefWidth, pref_width, UI_Size, v) }
root_function UI_Size UI_push_pref_height(UI_Size v) { UI_stack_push_impl(ui_state, PrefHeight, pref_height, UI_Size, v) }
root_function Axis2 UI_push_child_layout_axis(Axis2 v) { UI_stack_push_impl(ui_state, ChildLayoutAxis, child_layout_axis, Axis2, v) }

//- Pop 
root_function UI_Box *UI_pop_parent(void) { UI_stack_pop_impl(ui_state, Parent, parent) }
root_function UI_BoxFlags UI_pop_flags(void) { UI_stack_pop_impl(ui_state, Flags, flags) }
root_function F32 UI_pop_fixed_x(void) { UI_stack_pop_impl(ui_state, FixedX, fixed_x) }
root_function F32 UI_pop_fixed_y(void) { UI_stack_pop_impl(ui_state, FixedY, fixed_y) }
root_function F32 UI_pop_fixed_width(void) { UI_stack_pop_impl(ui_state, FixedWidth, fixed_width) }
root_function F32 UI_pop_fixed_height(void) { UI_stack_pop_impl(ui_state, FixedHeight, fixed_height) }
root_function UI_Key  UI_pop_seed_key(void) { UI_stack_pop_impl(ui_state, SeedKey, seed_key) }
root_function UI_Size UI_pop_pref_width(void) { UI_stack_pop_impl(ui_state, PrefWidth, pref_width) }
root_function UI_Size UI_pop_pref_height(void) { UI_stack_pop_impl(ui_state, PrefHeight, pref_height) }
root_function Axis2 UI_pop_child_layout_axis(void) { UI_stack_pop_impl(ui_state, ChildLayoutAxis, child_layout_axis) }

//- Set next 
root_function UI_Box *UI_set_next_parent(UI_Box *v) { UI_stack_set_next_impl(ui_state, Parent, parent, UI_Box *, v) }
root_function UI_BoxFlags UI_set_next_flags(UI_BoxFlags v) { UI_stack_set_next_impl(ui_state, Flags, flags, UI_BoxFlags, v) }
root_function F32 UI_set_next_fixed_x(F32 v) { UI_stack_set_next_impl(ui_state, FixedX, fixed_x, F32, v) }
root_function F32 UI_set_next_fixed_y(F32 v) { UI_stack_set_next_impl(ui_state, FixedY, fixed_y, F32, v) }
root_function F32 UI_set_next_fixed_width(F32 v) { UI_stack_set_next_impl(ui_state, FixedWidth, fixed_width, F32, v) }
root_function F32 UI_set_next_fixed_height(F32 v) { UI_stack_set_next_impl(ui_state, FixedHeight, fixed_height, F32, v) }
root_function UI_Key UI_set_next_seed_key(UI_Key v) { UI_stack_set_next_impl(ui_state, SeedKey, seed_key, UI_Key, v) }
root_function UI_Size UI_set_next_pref_width(UI_Size v) { UI_stack_set_next_impl(ui_state, PrefWidth, pref_width, UI_Size, v) }
root_function UI_Size UI_set_next_pref_height(UI_Size v) { UI_stack_set_next_impl(ui_state, PrefHeight, pref_height, UI_Size, v) }
root_function Axis2 UI_set_next_child_layout_axis(Axis2 v) { UI_stack_set_next_impl(ui_state, ChildLayoutAxis, child_layout_axis, Axis2, v) }

#define UI_auto_pop_stacks(state) \
if(state->parent_stack.auto_pop) { UI_pop_parent(); state->parent_stack.auto_pop = 0; }\
if(state->flags_stack.auto_pop) { UI_pop_flags(); state->flags_stack.auto_pop = 0; }\
if(state->fixed_x_stack.auto_pop) { UI_pop_fixed_x(); state->fixed_x_stack.auto_pop = 0; }\
if(state->fixed_y_stack.auto_pop) { UI_pop_fixed_y(); state->fixed_y_stack.auto_pop = 0; }\
if(state->fixed_x_stack.auto_pop) { UI_pop_fixed_width(); state->fixed_width_stack.auto_pop = 0; }\
if(state->fixed_y_stack.auto_pop) { UI_pop_fixed_height(); state->fixed_height_stack.auto_pop = 0; }\
if(state->seed_key_stack.auto_pop) { UI_pop_seed_key(); state->seed_key_stack.auto_pop = 0; }\
if(state->pref_width_stack.auto_pop) { UI_pop_pref_width(); state->pref_width_stack.auto_pop = 0; }\
if(state->pref_height_stack.auto_pop) { UI_pop_pref_height(); state->pref_height_stack.auto_pop = 0; }\
if(state->child_layout_axis_stack.auto_pop) { UI_pop_child_layout_axis(); state->child_layout_axis_stack.auto_pop = 0; }\

