//https://habr.com/ru/post/279867/


////Использование
//arr.sort(ArrayCompare()); //Обычная типобезопасная сортировка по возрастанию
//arr.sort(ArrayCompare(-1)); //Обычная типобезопасная сортировка по убыванию
//arr.sort(ArrayCompare('field')); //Сортировка по свойству field по возрастанию
//arr.sort(ArrayCompare('field', -1)); //Сортировка по свойству field по убыванию
///* Сортировка сначала по полю field1
//   при совпадении по полю field2, а если и оно совпало, то по полю field3
//   все по возрастанию */
//arr.sort(compare('field1', 'field2', 'field3'));
///* Сортировка сначала по полю field1 по возрастанию
//   при совпадении по полю field2 по убыванию */
//arr.sort(compare({
//    field1: 1,
//    field2: -1
//}));


//Метод сравнения элементов для сортировки
//field - имя свойства сущности
//order порядок 0 - возрастание, 1 - убывание
export default function ArrayCompare(field, order) {
    var len = arguments.length;
    if (len === 0) {
        return (a, b) => (a < b && -1) || (a > b && 1) || 0;
    }
    if (len === 1) {
        switch (typeof field) {
            case 'number':
                return field < 0 ?
                    ((a, b) => (a < b && 1) || (a > b && -1) || 0) :
                    ((a, b) => (a < b && -1) || (a > b && 1) || 0);
            case 'string':
                return (a, b) => (a[field] < b[field] && -1) || (a[field] > b[field] && 1) || 0;
        }
    }
    if (len === 2 && typeof order === 'number') {
        return order < 0 ?
            ((a, b) => (a[field] < b[field] && 1) || (a[field] > b[field] && -1) || 0) :
            ((a, b) => (a[field] < b[field] && -1) || (a[field] > b[field] && 1) || 0);
    }
    var fields, orders;
    if (typeof field === 'object') {
        fields = Object.getOwnPropertyNames(field);
        orders = fields.map(key => field[key]);
        len = fields.length;
    } else {
        fields = new Array(len);
        orders = new Array(len);
        for (let i = len; i--;) {
            fields[i] = arguments[i];
            orders[i] = 1;
        }
    }
    return (a, b) => {
        for (let i = 0; i < len; i++) {
            if (a[fields[i]] < b[fields[i]]) return orders[i];
            if (a[fields[i]] > b[fields[i]]) return -orders[i];
        }
        return 0;
    };
}