/**
 * Copyright (c) 2021 Dominic Masters
 * 
 * This software is released under the MIT License.
 * https://opensource.org/licenses/MIT
 */

#pragma once
#include "../libs.h"
#include "rand.h"

/**
 * Definition of a callback that is used to sort an array.
 * 
 * @param left The left element in the array.
 * @param right The right element in the array.
 * @return -1 for Left priority, 1 for Right and 0 for Equal.
 */
typedef int32_t arraysort_t(const void*, const void*);

/**
 * Callback used when calculating the sum of an array that match a state.
 * @param item Item within the array.
 * @return True if counted, otherwise false.
 */
typedef bool arraysumcallback_t(void*);

/**
 * Retreive the pointer to an elment within the array of unknown type.
 * 
 * @param size Size of each element within the array.
 * @param array Array to get from.
 * @param index Index to get
 * @return Pointer to the item in the array.
 */
void * arrayGet(size_t size, void *array, int32_t index);

/**
 * Set an object into the array.
 * 
 * @param size Size of the element to set.
 * @param array Array to set in to.
 * @param index Index to set into.
 * @param data Data to set into the array.
 * @return void* 
 */
void arraySet(size_t size, void *array, int32_t index, void *data);

/**
 * Randomizes the contents of an array.
 * 
 * @param size Size of each element within the array.
 * @param array Array to shuffle.
 * @param arrayLength Length of the array.
 */
void arrayShuffle(size_t size, void *array, int32_t arrayLength);

/**
 * Find the index within the array that matches the given pointer.
 * 
 * @param size Size of each element within the array.
 * @param array Array to get from.
 * @param length Max length to check to.
 * @param value Pointer to the value to look for. This is memory compared.
 * @returns The index within the array that matches, or -1 if no match.
 */
int32_t arrayFind(size_t size, void *array, int32_t length, void *value);

/**
 * Compares each item in an array with the specified value, and returns true if 
 * found within the array. This is a shorthand for arrayFind without an int32_t 
 * being returned.
 * 
 * @param size Size of each element within the array.
 * @param array Array to get from.
 * @param length Max length to check to.
 * @param value Pointer to the value to look for. This is memory compared.
 * @returns True if the array contains the value, otherwise false.
 */
bool arrayContains(size_t size, void *array, int32_t length, void *value);

/**
 * Copies the raw contents from the source array to the destination array.
 * 
 * @param size Size of each element within the array.
 * @param source Source array.
 * @param length Length of the source array.
 * @param dest Destination array.
 */
void arrayCopy(size_t size, void *source, int32_t length, void *dest);

/**
 * Sort an array based on the result of an array sort callback.
 * 
 * @param size Size of each element within the array.
 * @param array Array to sort.
 * @param length Max length to sort to.
 * @param sort Callback to use to sort.
 */
void arraySort(size_t size, void *array, int32_t length, arraysort_t *sort);

/**
 * Sort an int32 array.
 * 
 * @param array Array to sort.
 * @param length Max length to sort.
 */
void arraySortInt32(int32_t *array, int32_t length);
/** Internal int32_t array sorter. */
int32_t _arraySorterInt32(const void *left, const void* right);

/**
 * Sort a uint8_t array.
 * 
 * @param array Array to sort.
 * @param length Max Length to sort.
 */
void arraySortUint8(uint8_t *array, int32_t length);
/** Internal uint8_t array sorter. */
int32_t _arraySorterUint8(const void* left, const void* right);

/**
 * Find the index of a string within a string array. (Array of char pointers).
 * 
 * @param array Array to check
 * @param arrayLength Length of th earray.
 * @param value The value to search for.
 * @return The index that the strings exists within the array.
 */
int32_t arrayFindString(char **array, int32_t arrayLength, char *value);

/**
 * Rewinds an array backwards. This is used to take an array that has some data
 * used towards the end of an array, but the data near the start is no longer
 * used. This will take the end data and put it back at the start.
 * 
 * @param size The size of each element within the array.
 * @param source The array itself.
 * @param length The total length of the array.
 * @param start The first index within the array that you want to keep.
 * @param count Count of items after start to use. Use -1 to take the remaining.
 */
void arrayRewind(size_t size, void *source, int32_t length, int32_t start,
  int32_t count
);

/**
 * Remove some elements from an array. This will cause the elements after the
 * removed items to be shifted down into their place.
 * 
 * @param size Size of each element within the array. 
 * @param array Array itself.
 * @param start The first index you want to remove.
 * @param count The count of elements to remove.
 * @param length The length of the total array.
 */
void arraySplice(
  size_t size, void *array, int32_t start, int32_t count, int32_t length
);

/**
 * Sums the count of items that match a given filter in an array. The filter
 * is a callback method that the user can define.
 * 
 * @param size Size of each element within the array.
 * @param array Array itself.
 * @param length Length of the array.
 * @param callback Callback that will return true/false when called.
 * @return The count of items that matched the callback invokation.
 */
int32_t arraySum(
  size_t size, void *array, int32_t length, arraysumcallback_t *callback
);