// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Doubly Linked List Project
//
// 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.

#ifndef doubly_linked_list_h
#define doubly_linked_list_h

#include <stdio.h>   /* for printf, NULL */
#include <stdlib.h>  /* for malloc, free */
#include <stdbool.h> /* for bool type */

/**
 * Node structure for doubly linked list
 * Each node contains data and pointers to previous and next nodes
 */
struct dll_node {
    int data;                    /* data stored in the node */
    struct dll_node *next;       /* pointer to next node */
    struct dll_node *prev;       /* pointer to previous node */
};

/**
 * Doubly linked list structure
 * Contains pointers to head and tail nodes, and size counter
 */
struct doubly_linked_list {
    struct dll_node *head;       /* pointer to first node */
    struct dll_node *tail;       /* pointer to last node */
    size_t size;                 /* current number of nodes */
};

/* Function declarations */

/**
 * Create a new doubly linked list
 * @return pointer to new list, NULL on failure
 */
struct doubly_linked_list *dll_create(void);

/**
 * Destroy the doubly linked list and free all memory
 * @param list pointer to the list to destroy
 */
void dll_destroy(struct doubly_linked_list *list);

/**
 * Insert data at the beginning of the list
 * @param list pointer to the list
 * @param data data to insert
 * @return true on success, false on failure
 */
bool dll_insert_front(struct doubly_linked_list *list, int data);

/**
 * Insert data at the end of the list
 * @param list pointer to the list
 * @param data data to insert
 * @return true on success, false on failure
 */
bool dll_insert_back(struct doubly_linked_list *list, int data);

/**
 * Insert data at specified position (0-based index)
 * @param list pointer to the list
 * @param position index where to insert (0 = front)
 * @param data data to insert
 * @return true on success, false on failure
 */
bool dll_insert_at(struct doubly_linked_list *list, size_t position, int data);

/**
 * Remove the first node from the list
 * @param list pointer to the list
 * @return true on success, false if list is empty
 */
bool dll_remove_front(struct doubly_linked_list *list);

/**
 * Remove the last node from the list
 * @param list pointer to the list
 * @return true on success, false if list is empty
 */
bool dll_remove_back(struct doubly_linked_list *list);

/**
 * Remove node at specified position (0-based index)
 * @param list pointer to the list
 * @param position index of node to remove
 * @return true on success, false on failure
 */
bool dll_remove_at(struct doubly_linked_list *list, size_t position);

/**
 * Remove first occurrence of specified data
 * @param list pointer to the list
 * @param data data to remove
 * @return true if found and removed, false otherwise
 */
bool dll_remove_data(struct doubly_linked_list *list, int data);

/**
 * Search for data in the list
 * @param list pointer to the list
 * @param data data to search for
 * @return position of data (0-based), SIZE_MAX if not found
 */
size_t dll_search(struct doubly_linked_list *list, int data);

/**
 * Get data at specified position
 * @param list pointer to the list
 * @param position index of node (0-based)
 * @param data pointer to store retrieved data
 * @return true on success, false on failure
 */
bool dll_get_at(struct doubly_linked_list *list, size_t position, int *data);

/**
 * Get the size of the list
 * @param list pointer to the list
 * @return number of nodes in the list, 0 if list is NULL
 */
size_t dll_get_size(struct doubly_linked_list *list);

/**
 * Check if the list is empty
 * @param list pointer to the list
 * @return true if empty or NULL, false otherwise
 */
bool dll_is_empty(struct doubly_linked_list *list);

/**
 * Print the list from front to back
 * @param list pointer to the list
 */
void dll_print_forward(struct doubly_linked_list *list);

/**
 * Print the list from back to front
 * @param list pointer to the list
 */
void dll_print_backward(struct doubly_linked_list *list);

/**
 * Clear all nodes from the list but keep the list structure
 * @param list pointer to the list
 */
void dll_clear(struct doubly_linked_list *list);

#endif /* doubly_linked_list_h */