// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Improved 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 IMPROVED_DOUBLY_LINKED_LIST_H
#define IMPROVED_DOUBLY_LINKED_LIST_H

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

/* Forward declarations */
struct dll_node;
struct doubly_linked_list;
struct dll_iterator;

/* Function pointer types for generic operations */
typedef int (*dll_compare_func_t)(const void *a, const void *b);
typedef void (*dll_free_func_t)(void *data);
typedef void (*dll_print_func_t)(const void *data);
typedef void* (*dll_copy_func_t)(const void *data);

/* Error codes for better error handling */
typedef enum {
    DLL_SUCCESS = 0,
    DLL_ERROR_NULL_POINTER,
    DLL_ERROR_OUT_OF_MEMORY,
    DLL_ERROR_INDEX_OUT_OF_BOUNDS,
    DLL_ERROR_ELEMENT_NOT_FOUND,
    DLL_ERROR_INVALID_OPERATION
} dll_error_t;

/**
 * Node structure for doubly linked list
 * Generic node that can store any data type
 */
struct dll_node {
    void *data;                  /* generic data pointer */
    size_t data_size;           /* size of data in bytes */
    struct dll_node *next;      /* pointer to next node */
    struct dll_node *prev;      /* pointer to previous node */
};

/**
 * Iterator structure for traversing the list
 * Provides safe iteration with modification detection
 */
struct dll_iterator {
    struct dll_node *current;   /* current node */
    struct doubly_linked_list *list; /* parent list */
    size_t modification_count;  /* for detecting concurrent modifications */
    bool is_valid;              /* iterator validity flag */
};

/**
 * Enhanced doubly linked list structure
 * Generic list with configurable behavior and optimizations
 */
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 */
    size_t modification_count;  /* for iterator invalidation */
    
    /* Function pointers for generic operations */
    dll_compare_func_t compare_func;  /* comparison function */
    dll_free_func_t free_func;        /* data cleanup function */
    dll_print_func_t print_func;      /* data printing function */
    dll_copy_func_t copy_func;        /* data copying function */
    
    /* Performance optimization flags */
    bool enable_caching;        /* enable position caching */
    struct dll_node *cached_node; /* cached node for optimization */
    size_t cached_position;     /* position of cached node */
};

/* Core list operations */

/**
 * Create a new doubly linked list with optional function pointers
 * @param compare_func comparison function for sorting/searching (can be NULL)
 * @param free_func cleanup function for data (can be NULL)
 * @param print_func printing function for data (can be NULL)
 * @param copy_func copying function for data (can be NULL)
 * @return pointer to new list, NULL on failure
 */
struct doubly_linked_list *dll_create_advanced(
    dll_compare_func_t compare_func,
    dll_free_func_t free_func,
    dll_print_func_t print_func,
    dll_copy_func_t copy_func
);

/**
 * Create a simple doubly linked list for basic data types
 * @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
 * @return error code
 */
dll_error_t dll_destroy(struct doubly_linked_list *list);

/* Enhanced insertion operations */

/**
 * Insert data at the beginning of the list
 * @param list pointer to the list
 * @param data pointer to data to insert
 * @param data_size size of data in bytes
 * @return error code
 */
dll_error_t dll_insert_front(struct doubly_linked_list *list, const void *data, size_t data_size);

/**
 * Insert data at the end of the list
 * @param list pointer to the list
 * @param data pointer to data to insert
 * @param data_size size of data in bytes
 * @return error code
 */
dll_error_t dll_insert_back(struct doubly_linked_list *list, const void *data, size_t data_size);

/**
 * Insert data at specified position (0-based index)
 * @param list pointer to the list
 * @param position index where to insert (0 = front)
 * @param data pointer to data to insert
 * @param data_size size of data in bytes
 * @return error code
 */
dll_error_t dll_insert_at(struct doubly_linked_list *list, size_t position, const void *data, size_t data_size);

/**
 * Insert data in sorted order (requires compare function)
 * @param list pointer to the list
 * @param data pointer to data to insert
 * @param data_size size of data in bytes
 * @return error code
 */
dll_error_t dll_insert_sorted(struct doubly_linked_list *list, const void *data, size_t data_size);

/* Enhanced removal operations */

/**
 * Remove the first node from the list
 * @param list pointer to the list
 * @return error code
 */
dll_error_t dll_remove_front(struct doubly_linked_list *list);

/**
 * Remove the last node from the list
 * @param list pointer to the list
 * @return error code
 */
dll_error_t 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 error code
 */
dll_error_t 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 pointer to data to remove
 * @param data_size size of data in bytes
 * @return error code
 */
dll_error_t dll_remove_data(struct doubly_linked_list *list, const void *data, size_t data_size);

/**
 * Remove all occurrences of specified data
 * @param list pointer to the list
 * @param data pointer to data to remove
 * @param data_size size of data in bytes
 * @return number of elements removed, or negative error code
 */
int dll_remove_all_data(struct doubly_linked_list *list, const void *data, size_t data_size);

/* Enhanced access operations */

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

/**
 * 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
 * @param data_size pointer to store size of retrieved data
 * @return error code
 */
dll_error_t dll_get_at(struct doubly_linked_list *list, size_t position, void **data, size_t *data_size);

/**
 * Get data at front of list
 * @param list pointer to the list
 * @param data pointer to store retrieved data
 * @param data_size pointer to store size of retrieved data
 * @return error code
 */
dll_error_t dll_get_front(struct doubly_linked_list *list, void **data, size_t *data_size);

/**
 * Get data at back of list
 * @param list pointer to the list
 * @param data pointer to store retrieved data
 * @param data_size pointer to store size of retrieved data
 * @return error code
 */
dll_error_t dll_get_back(struct doubly_linked_list *list, void **data, size_t *data_size);

/* Utility operations */

/**
 * 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);

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

/**
 * Create a copy of the list (requires copy function)
 * @param list pointer to the list to copy
 * @return pointer to new list copy, NULL on failure
 */
struct doubly_linked_list *dll_copy(struct doubly_linked_list *list);

/**
 * Reverse the order of elements in the list
 * @param list pointer to the list
 * @return error code
 */
dll_error_t dll_reverse(struct doubly_linked_list *list);

/**
 * Sort the list (requires compare function)
 * @param list pointer to the list
 * @return error code
 */
dll_error_t dll_sort(struct doubly_linked_list *list);

/**
 * Merge two sorted lists into one (requires compare function)
 * @param list1 pointer to first sorted list
 * @param list2 pointer to second sorted list
 * @return pointer to merged list, NULL on failure
 */
struct doubly_linked_list *dll_merge_sorted(struct doubly_linked_list *list1, struct doubly_linked_list *list2);

/* Iterator operations */

/**
 * Create an iterator for the list
 * @param list pointer to the list
 * @return iterator structure, or invalid iterator on failure
 */
struct dll_iterator dll_iterator_create(struct doubly_linked_list *list);

/**
 * Check if iterator has next element
 * @param iter pointer to iterator
 * @return true if next element exists, false otherwise
 */
bool dll_iterator_has_next(struct dll_iterator *iter);

/**
 * Check if iterator has previous element
 * @param iter pointer to iterator
 * @return true if previous element exists, false otherwise
 */
bool dll_iterator_has_prev(struct dll_iterator *iter);

/**
 * Move iterator to next element and get data
 * @param iter pointer to iterator
 * @param data pointer to store retrieved data
 * @param data_size pointer to store size of retrieved data
 * @return error code
 */
dll_error_t dll_iterator_next(struct dll_iterator *iter, void **data, size_t *data_size);

/**
 * Move iterator to previous element and get data
 * @param iter pointer to iterator
 * @param data pointer to store retrieved data
 * @param data_size pointer to store size of retrieved data
 * @return error code
 */
dll_error_t dll_iterator_prev(struct dll_iterator *iter, void **data, size_t *data_size);

/**
 * Reset iterator to beginning of list
 * @param iter pointer to iterator
 * @return error code
 */
dll_error_t dll_iterator_reset(struct dll_iterator *iter);

/**
 * Remove current element through iterator
 * @param iter pointer to iterator
 * @return error code
 */
dll_error_t dll_iterator_remove(struct dll_iterator *iter);

/* Display operations */

/**
 * 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);

/**
 * Get string representation of error code
 * @param error error code
 * @return string description of error
 */
const char *dll_error_string(dll_error_t error);

/* Convenience functions for common data types */

/**
 * Create list for integers
 * @return pointer to new list configured for integers
 */
struct doubly_linked_list *dll_create_int(void);

/**
 * Create list for strings
 * @return pointer to new list configured for strings
 */
struct doubly_linked_list *dll_create_string(void);

/**
 * Insert integer at front
 * @param list pointer to the list
 * @param value integer value to insert
 * @return error code
 */
dll_error_t dll_insert_int_front(struct doubly_linked_list *list, int value);

/**
 * Insert integer at back
 * @param list pointer to the list
 * @param value integer value to insert
 * @return error code
 */
dll_error_t dll_insert_int_back(struct doubly_linked_list *list, int value);

/**
 * Insert string at front
 * @param list pointer to the list
 * @param str string to insert
 * @return error code
 */
dll_error_t dll_insert_string_front(struct doubly_linked_list *list, const char *str);

/**
 * Insert string at back
 * @param list pointer to the list
 * @param str string to insert
 * @return error code
 */
dll_error_t dll_insert_string_back(struct doubly_linked_list *list, const char *str);

#endif /* IMPROVED_DOUBLY_LINKED_LIST_H */