import { SortOrder } from '../../AdaptableState/Common/Enums';
export function GetLength(arrayToCheck) {
    return IsNotNull(arrayToCheck) ? arrayToCheck.length : 0;
}
export function CorrectLength(arrayToCheck, requiredLength) {
    return GetLength(arrayToCheck) == requiredLength;
}
export function NotCorrectLength(arrayToCheck, requiredLength) {
    return !CorrectLength(arrayToCheck, requiredLength);
}
export function AddItem(array, itemToAdd) {
    if (NotContainsItem(array, itemToAdd)) {
        array.push(itemToAdd);
    }
}
export function ContainsItem(array, itemToCheck) {
    if (array == null) {
        return false;
    }
    return array.indexOf(itemToCheck) > -1;
}
export function ContainsAnyItem(array, itemsToCheck) {
    if (array == null) {
        return false;
    }
    let foundItem = false;
    itemsToCheck.forEach((item) => {
        if (!foundItem) {
            if (ContainsItem(array, item)) {
                foundItem = true;
            }
        }
    });
    return foundItem;
}
export function NotContainsItem(array, itemToCheck) {
    return !ContainsItem(array, itemToCheck);
}
export function RetrieveDistinct(array) {
    return Array.from(new Set(array.map((item) => item)));
}
export function IsNull(arrayToCheck) {
    return arrayToCheck == null || arrayToCheck == undefined;
}
export function IsNotNull(arrayToCheck) {
    return !IsNull(arrayToCheck);
}
export function IsEmpty(arrayToCheck) {
    return arrayToCheck?.length == 0;
}
export function IsNotEmpty(arrayToCheck) {
    return !IsEmpty(arrayToCheck);
}
export function IsNullOrEmpty(arrayToCheck) {
    return IsNull(arrayToCheck) || IsEmpty(arrayToCheck);
}
export function IsNotNullOrEmpty(arrayToCheck) {
    return IsNotNull(arrayToCheck) && IsNotEmpty(arrayToCheck);
}
export function IsNullOrEmptyOrContainsSingleEmptyValue(arrayToCheck) {
    if (IsNullOrEmpty(arrayToCheck)) {
        return true;
    }
    if (HasSingleEmptyValue(arrayToCheck)) {
        return true;
    }
    return false;
}
export function IsNotNullOrEmptyNorContainsSingleEmptyValue(arrayToCheck) {
    return !IsNullOrEmptyOrContainsSingleEmptyValue(arrayToCheck);
}
export function HasSingleEmptyValue(arrayToCheck) {
    if (arrayToCheck.length == 1 && arrayToCheck[0] == '') {
        return true;
    }
    return false;
}
export function getOccurrence(arrayToCheck, valueToCheck) {
    var count = 0;
    arrayToCheck.forEach((v) => v === valueToCheck && count++);
    return count;
}
export function hasOneItem(arrayToCheck) {
    return hasItemsOfCount(arrayToCheck, 1);
}
export function hasItemsOfCount(arrayToCheck, numberOfItems) {
    return arrayToCheck.length == numberOfItems;
}
export function moveArray(array, from, to) {
    array.splice(to, 0, array.splice(from, 1)[0]);
}
//This deliberately only checks contents equality and not positional so [1, 2, 3]== [1, 3, 2]
export function areArraysEqual(arr1, arr2) {
    if (IsNullOrEmpty(arr1) && IsNotNullOrEmpty(arr2)) {
        return false;
    }
    if (IsNotNullOrEmpty(arr1) && IsNullOrEmpty(arr2)) {
        return false;
    }
    if (arr1.length !== arr2.length) {
        return false;
    }
    return arr1.every((x) => arr2.indexOf(x) != -1);
}
export function areArraysNotEqual(arr1, arr2) {
    return !areArraysEqual(arr1, arr2);
}
export function areArraysEqualWithOrder(arr1, arr2) {
    if (arr1 == null) {
        return true;
    }
    if (arr1.length !== arr2.length) {
        return false;
    }
    return arr1.every((x, index) => arr2.indexOf(x) == index);
}
export function areArraysEqualWithOrderandProperties(value, other) {
    const type = Object.prototype.toString.call(value);
    // If the two objects are not the same type, return false
    if (type !== Object.prototype.toString.call(other)) {
        return false;
    }
    // If items are not an object or array, return false
    if (['[object Array]', '[object Object]'].indexOf(type) < 0) {
        return false;
    }
    // Compare the length of the length of the two items
    const valueLen = type === '[object Array]' ? value.length : Object.keys(value).length;
    const otherLen = type === '[object Array]' ? other.length : Object.keys(other).length;
    if (valueLen !== otherLen) {
        return false;
    }
    // Compare two items
    const compare = function (item1, item2) {
        // Get the object type
        const itemType = Object.prototype.toString.call(item1);
        // If an object or array, compare recursively
        if (['[object Array]', '[object Object]'].indexOf(itemType) >= 0) {
            if (!areArraysEqualWithOrderandProperties(item1, item2)) {
                return false;
            }
        }
        // Otherwise, do a simple comparison
        else {
            // If the two items are not the same type, return false
            if (itemType !== Object.prototype.toString.call(item2)) {
                return false;
            }
            // Else if it's a function, convert to a string and compare
            // Otherwise, just compare
            if (itemType === '[object Function]') {
                if (item1.toString() !== item2.toString()) {
                    return false;
                }
            }
            else {
                if (item1 !== item2) {
                    return false;
                }
            }
        }
    };
    // Compare properties
    if (type === '[object Array]') {
        for (let i = 0; i < valueLen; i++) {
            if (compare(value[i], other[i]) === false) {
                return false;
            }
        }
    }
    else {
        for (let key in value) {
            if (value.hasOwnProperty(key)) {
                if (compare(value[key], other[key]) === false) {
                    return false;
                }
            }
        }
    }
    // If nothing failed, return true
    return true;
}
export function sortArrayWithProperty(sortOrder, values, sortProperty) {
    if (sortProperty) {
        let newValues = [].concat(values);
        let direction = 1;
        if (sortOrder == SortOrder.Desc) {
            direction = -1;
        }
        return newValues.sort((a, b) => {
            let aSortProperty = a[sortProperty];
            let bSortProperty = b[sortProperty];
            if (typeof aSortProperty == 'string' && typeof bSortProperty == 'string') {
                return aSortProperty.localeCompare(bSortProperty) * direction;
            }
            else {
                return aSortProperty < bSortProperty
                    ? -1 * direction
                    : aSortProperty > bSortProperty
                        ? 1 * direction
                        : 0;
            }
        });
    }
    else {
        return sortArray(values, sortOrder);
    }
}
export function sortArray(values, sortOrder = SortOrder.Asc) {
    const newValues = [].concat(values);
    const direction = sortOrder == SortOrder.Asc ? 1 : -1;
    return newValues.sort((a, b) => (a < b ? -1 * direction : a > b ? 1 * direction : 0));
}
export function sortCellValueArray(cellValues, sortOrder = SortOrder.Asc) {
    const newValues = [].concat(cellValues);
    const direction = sortOrder == SortOrder.Asc ? 1 : -1;
    return newValues.sort((a, b) => a.rawValue < b.rawValue ? -1 * direction : a.rawValue > b.rawValue ? 1 * direction : 0);
}
export function sortCellValueArrayNumeric(cellValues, sortOrder = SortOrder.Asc) {
    const direction = sortOrder == SortOrder.Asc ? 1 : -1;
    const newValues = [].concat(cellValues);
    return newValues.sort((a, b) => {
        const valueAAsNumber = Number(a.rawValue);
        const valueBAsNumber = Number(b.rawValue);
        if (isNaN(valueAAsNumber)) {
            return 0;
        }
        if (isNaN(valueBAsNumber)) {
            return 0;
        }
        return valueAAsNumber < valueBAsNumber
            ? -1 * direction
            : valueAAsNumber > valueBAsNumber
                ? 1 * direction
                : 0;
    });
}
export function sortCellValueArrayDates(cellValues, sortOrder = SortOrder.Asc) {
    cellValues.sort((a, b) => {
        return sortOrder == SortOrder.Asc
            ? +new Date(a.rawValue) - +new Date(b.rawValue)
            : +new Date(b.rawValue) - +new Date(a.rawValue);
    });
    return cellValues;
}
export function groupArrayBy(array, prop) {
    return array.reduce((acc, item) => {
        let key = item[prop];
        acc[key] = acc[key] || [];
        acc[key].push(item);
        return acc;
    }, {});
}
export function createCommaSeparatedString(values) {
    return values.join(', ');
}
export function SumArray(array) {
    return array.filter((num) => typeof num === 'number' && !isNaN(num)).reduce((a, b) => a + b, 0);
}
export function reorderArray(array, startIndex, endIndex) {
    const result = [...array];
    if (startIndex > array.length - 1) {
        // not much that we can do if the dragged item is out of bounds...
        return result;
    }
    if (endIndex > array.length - 1) {
        endIndex = array.length - 1;
    }
    const [removed] = result.splice(startIndex, 1);
    result.splice(endIndex, 0, removed);
    return result;
}
export function sortArrayWithOrder(array, order, 
/**
 *
 * The array can contain items which are not listed in the order array.
 * So sortUnorderedItems decides whether to leave these items untouched
 * in the current order in which they are in the array (sortUnorderedItems: false)
 * or to sort them using normal comparison rules
 */
{ sortUnorderedItems }) {
    const itemsToIndex = array.reduce((acc, x, i) => {
        acc.set(x, i);
        return acc;
    }, new Map());
    const orderItemsToIndex = order.reduce((acc, x, i) => {
        acc.set(x, i);
        return acc;
    }, new Map());
    function compareItemsOfCustomSort(valueA, valueB) {
        const orderContainsFirstElement = orderItemsToIndex.has(valueA);
        const indexInOrderOfFirstElement = orderContainsFirstElement
            ? orderItemsToIndex.get(valueA)
            : -1;
        const orderContainsSecondElement = orderItemsToIndex.has(valueB);
        const indexInOrderSecondElement = orderContainsSecondElement
            ? orderItemsToIndex.get(valueB)
            : -1;
        //if none of the element are in the order list we just return normal compare
        if (!orderContainsFirstElement && !orderContainsSecondElement) {
            if (!sortUnorderedItems) {
                // keep the original order
                return itemsToIndex.get(valueA) - itemsToIndex.get(valueB);
            }
            if (valueA == valueB) {
                return 0;
            }
            return valueA < valueB ? -1 : 1;
        }
        //if first item not in the list make sure we put it after the second item
        if (!orderContainsFirstElement) {
            return 1;
        }
        //if second item not in the list make sure we put it after the first item
        if (!orderContainsSecondElement) {
            return -1;
        }
        //return the comparison from the list if the two items are in the list
        return indexInOrderOfFirstElement - indexInOrderSecondElement;
    }
    return [].concat(array).sort(compareItemsOfCustomSort);
}
export const ArrayExtensions = {
    GetLength,
    CorrectLength,
    NotCorrectLength,
    groupArrayBy,
    AddItem,
    ContainsItem,
    NotContainsItem,
    ContainsAnyItem,
    RetrieveDistinct,
    IsNull,
    IsNotNull,
    IsEmpty,
    IsNotEmpty,
    IsNullOrEmpty,
    IsNotNullOrEmpty,
    IsNullOrEmptyOrContainsSingleEmptyValue,
    IsNotNullOrEmptyNorContainsSingleEmptyValue,
    HasSingleEmptyValue,
    getOccurrence,
    hasOneItem,
    hasItemsOfCount,
    moveArray,
    areArraysEqual,
    areArraysNotEqual,
    areArraysEqualWithOrder,
    areArraysEqualWithOrderandProperties,
    sortArray,
    sortCellValueArray,
    sortCellValueArrayNumeric,
    sortCellValueArrayDates,
    sortArrayWithProperty,
    createCommaSeparatedString,
    SumArray,
    reorderArray,
    sortArrayWithOrder,
};
export default ArrayExtensions;
