/*
 * Copyright 2024 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "action_menu_hierarchy.h"
#include "action_menu_window_private.h"

#include "applib/applib_malloc.auto.h"
#include "kernel/pbl_malloc.h"

// Item
/////////////////////////////////
char *action_menu_item_get_label(const ActionMenuItem *item) {
  if (item == NULL) {
    return NULL;
  }
  return (char *)item->label;
}

void *action_menu_item_get_action_data(const ActionMenuItem *item) {
  if (item == NULL || !item->is_leaf) {
    return NULL;
  }
  return (void *)item->action_data;
}

// Level
/////////////////////////////////

ActionMenuLevel *action_menu_level_create(uint16_t max_items) {
  // TODO add applib-malloc padding
  ActionMenuLevel *level = applib_malloc(applib_type_size(ActionMenuLevel) +
                                         max_items * applib_type_size(ActionMenuItem));
  if (!level) return NULL;
  *level = (ActionMenuLevel){
    .max_items = max_items,
    .display_mode = ActionMenuLevelDisplayModeWide,
  };

  return level;
}

void action_menu_level_set_display_mode(ActionMenuLevel *level,
                                        ActionMenuLevelDisplayMode display_mode) {
  if (!level) return;
  level->display_mode = display_mode;
}

ActionMenuItem *action_menu_level_add_action(ActionMenuLevel *level,
                             const char *label,
                             ActionMenuPerformActionCb cb,
                             void *action_data) {
  if (!level || !label || !cb ||
      (level->num_items >= level->max_items)) {
    return NULL;
  }

  ActionMenuItem *item = &level->items[level->num_items];
  *item = (ActionMenuItem) {
    .label = label,
    .perform_action = cb,
    .action_data = action_data,
  };
  ++level->num_items;
  return item;
}

ActionMenuItem *action_menu_level_add_child(ActionMenuLevel *level,
                                 ActionMenuLevel *child,
                                 const char *label) {
  if (!level || !child || !label ||
      (level->num_items >= level->max_items)) {
    return NULL;
  }

  child->parent_level = level;

  ActionMenuItem *item = &level->items[level->num_items];
  *item = (ActionMenuItem) {
    .label = label,
    .next_level = child,
  };
  ++level->num_items;

  return item;
}

// Hierarchy
/////////////////////////////////

static void prv_cleanup_helper(const ActionMenuLevel *level,
                               ActionMenuEachItemCb each_cb,
                               void *context) {
  for (int i = 0; i < level->num_items; ++i) {
    const ActionMenuItem *item = &level->items[i];
    if (!item->is_leaf && item->next_level) {
      prv_cleanup_helper(item->next_level, each_cb, context);
    }
    if (each_cb) {
      each_cb(item, context);
    }
  }

  applib_free((void *)level);
}

void action_menu_hierarchy_destroy(const ActionMenuLevel *root,
                                   ActionMenuEachItemCb each_cb,
                                   void *context) {
  if (root) {
    prv_cleanup_helper(root, each_cb, context);
  }
}
