# Source: utils/comparators.js

    /**
     * Developer: Stepan Burguchev
     * Date: 9/4/2014
     * Copyright: 2009-2016 Comindware®
     *       All Rights Reserved
     * Published under the MIT license
     */

    /* global define, require, moment */

    define(['core/meta'],
        function (meta) {
            'use strict';

            var stringComparator2Asc = function (a, b) {
                if (a) {
                    if (b) {
                        return a.localeCompare(b);
                    } else {
                        return -1;
                    }
                } else if (b) {
                    return 1;
                }
                return 0;
            };

            var stringComparator2Desc = function (a, b) {
                if (a) {
                    if (b) {
                        return -a.localeCompare(b);
                    } else {
                        return 1;
                    }
                } else if (b) {
                    return -1;
                }
                return 0;
            };

            var numberComparator2Asc = function (a, b) {
                return a - b;
            };

            var numberComparator2Desc = function (a, b) {
                return b - a;
            };

            var durationComparator2Asc = function (a, b) {
                if (a) {
                    a = moment.duration(a);
                }
                if (b) {
                    b = moment.duration(b);
                }
                return a ? (b ? a - b : 1) : (b ? -1 : 0);
            };

            var durationComparator2Desc = function (a, b) {
                if (a) {
                    a = moment.duration(a);
                }
                if (b) {
                    b = moment.duration(b);
                }
                return b ? (a ? b - a : 1) : (a ? -1 : 0);
            };

            var booleanComparator2Asc = function (a, b) {
                // true goes first
                return a ? (b ? 0 : -1) : (b ? 1 : 0);
            };

            var dateComparator2Asc = function (a, b) {
                if (a) {
                    a = moment(a);
                }
                if (b) {
                    b = moment(b);
                }
                return a ? (b ? a - b : 1) : ( b ? -1 : 0);
            };

            var dateComparator2Desc = function (a, b) {
                if (a) {
                    a = moment(a);
                }
                if (b) {
                    b = moment(b);
                }
                return b ? (a ? b - a : 1) : (a ? -1 : 0);
            };

            var booleanComparator2Desc = function (a, b) {
                return a ? (b ? 0 : 1) : (b ? -1 : 0);
            };

            var referenceComparator2Asc = function(a, b) {
                var effectiveA = a ? a.name ? a.name : "" : "";
                var effectiveB = b ? b.name ? b.name : "" : "";
                return stringComparator2Asc(effectiveA, effectiveB);
            };

            var referenceComparator2Desc = function(a, b) {
                var effectiveA = a ? a.name ? a.name : "" : "";
                var effectiveB = b ? b.name ? b.name : "" : "";
                return stringComparator2Desc(effectiveA, effectiveB);
            };

            var getComparatorByDataType = function (dataType, sorting) {
                var comparator,
                    isDesc = sorting === 'desc';
                switch (dataType) {
                case meta.objectPropertyTypes.STRING:
                    comparator = isDesc ? stringComparator2Desc : stringComparator2Asc;
                    break;
                case meta.objectPropertyTypes.DOUBLE:
                case meta.objectPropertyTypes.INTEGER:
                case meta.objectPropertyTypes.DECIMAL:
                    comparator = isDesc ? numberComparator2Desc : numberComparator2Asc;
                    break;
                case meta.objectPropertyTypes.DURATION:
                    comparator = isDesc ? durationComparator2Desc : durationComparator2Asc;
                    break;
                case meta.objectPropertyTypes.DATETIME:
                    comparator = isDesc ? dateComparator2Desc : dateComparator2Asc;
                    break;
                case meta.objectPropertyTypes.BOOLEAN:
                    comparator = isDesc ? booleanComparator2Desc : booleanComparator2Asc;
                    break;
                case meta.objectPropertyTypes.ACCOUNT:
                case meta.objectPropertyTypes.INSTANCE:
                case meta.objectPropertyTypes.DOCUMENT:
                case meta.objectPropertyTypes.ENUM:
                    comparator = isDesc ? referenceComparator2Desc : referenceComparator2Asc;
                    break;
                default:
                    comparator = isDesc ? stringComparator2Desc : stringComparator2Asc;
                    break;
                }

                return comparator;
            };

            return /** @lends module:core.utils.comparators */ {
                /**
                 * @param {String} a Argument A.
                 * @return {String} An object to compare with simple operators (><=).
                 * */
                stringComparator1: function (a) {
                    return a;
                },
                /**
                 * @function
                 * @param {String} a Argument A.
                 * @param {String} b Argument B.
                 * @return {Number} Result as follows:
                 * <ul>
                 *     <li><code>-1</code> - if A < B.</li>
                 *     <li><code>0</code> - if A == B.</li>
                 *     <li><code>1</code> - if A > B.</li>
                 * </ul>
                 * */
                stringComparator2Asc: stringComparator2Asc,
                /**
                 * @function
                 * @param {String} a Argument A.
                 * @param {String} b Argument B.
                 * @return {Number} Result as follows:
                 * <ul>
                 *     <li><code>-1</code> - if A < B.</li>
                 *     <li><code>0</code> - if A == B.</li>
                 *     <li><code>1</code> - if A > B.</li>
                 * </ul>
                 * */
                stringComparator2Desc: stringComparator2Desc,
                /**
                 * Empty comparator.
                 * @function
                 * @return {Number} Always 0 (means equals).
                 * */
                emptyComparator: function () {
                    return 0;
                },
                /**
                 * @function
                 * @param {Date|String|moment} a Argument A. Javascript <code>Date</code>, date string in ISO8691 or momentJS date.
                 * @param {Date|String|moment} b Argument B. Javascript <code>Date</code>, date string in ISO8691 or momentJS date.
                 * @return {Number} Result as follows:
                 * <ul>
                 *     <li><code>-1</code> - if A < B.</li>
                 *     <li><code>0</code> - if A == B.</li>
                 *     <li><code>1</code> - if A > B.</li>
                 * </ul>
                 * */
                dateComparator2Asc: dateComparator2Asc,
                /**
                 * @function
                 * @param {Date|String|moment} a Argument A. Javascript <code>Date</code>, date string in ISO8691 or momentJS date.
                 * @param {Date|String|moment} b Argument B. Javascript <code>Date</code>, date string in ISO8691 or momentJS date.
                 * @return {Number} Result as follows:
                 * <ul>
                 *     <li><code>-1</code> - if A < B.</li>
                 *     <li><code>0</code> - if A == B.</li>
                 *     <li><code>1</code> - if A > B.</li>
                 * </ul>
                 * */
                dateComparator2Desc: dateComparator2Desc,
                /**
                 * @function
                 * @param {Number} a Argument A.
                 * @param {Number} b Argument B.
                 * @return {Number} Result as follows:
                 * <ul>
                 *     <li><code>-1</code> - if A < B.</li>
                 *     <li><code>0</code> - if A == B.</li>
                 *     <li><code>1</code> - if A > B.</li>
                 * </ul>
                 * */
                numberComparator2Asc: numberComparator2Asc,
                /**
                 * @function
                 * @param {Number} a Argument A.
                 * @param {Number} b Argument B.
                 * @return {Number} Result as follows:
                 * <ul>
                 *     <li><code>-1</code> - if A < B.</li>
                 *     <li><code>0</code> - if A == B.</li>
                 *     <li><code>1</code> - if A > B.</li>
                 * </ul>
                 * */
                numberComparator2Desc: numberComparator2Desc,
                /**
                 * @function
                 * @param {String|Object} a Argument A. An ISO8601 duration string ('P1Y2M3DT4H5M6S'), a string separated by colons like '7.23:59:59.999'
                 * or MomentJS object like <code>{ seconds: 2, minutes: 2, hours: 2, days: 2, weeks: 2, months: 2, years: 2 }</code>.
                 * @param {String|Object} a Argument B. An ISO8601 duration string ('P1Y2M3DT4H5M6S'), a string separated by colons like '7.23:59:59.999'
                 * or MomentJS object like <code>{ seconds: 2, minutes: 2, hours: 2, days: 2, weeks: 2, months: 2, years: 2 }</code>.
                 * @return {Number} Result as follows:
                 * <ul>
                 *     <li><code>-1</code> - if A < B.</li>
                 *     <li><code>0</code> - if A == B.</li>
                 *     <li><code>1</code> - if A > B.</li>
                 * </ul>
                 * */
                durationComparator2Asc: durationComparator2Asc,
                /**
                 * @function
                 * @param {String|Object} a Argument A. An ISO8601 duration string ('P1Y2M3DT4H5M6S'), a string separated by colons like '7.23:59:59.999'
                 * or MomentJS object like <code>{ seconds: 2, minutes: 2, hours: 2, days: 2, weeks: 2, months: 2, years: 2 }</code>.
                 * @param {String|Object} a Argument B. An ISO8601 duration string ('P1Y2M3DT4H5M6S'), a string separated by colons like '7.23:59:59.999'
                 * or MomentJS object like <code>{ seconds: 2, minutes: 2, hours: 2, days: 2, weeks: 2, months: 2, years: 2 }</code>.
                 * @return {Number} Result as follows:
                 * <ul>
                 *     <li><code>-1</code> - if A < B.</li>
                 *     <li><code>0</code> - if A == B.</li>
                 *     <li><code>1</code> - if A > B.</li>
                 * </ul>
                 * */
                durationComparator2Desc: durationComparator2Desc,
                /**
                 * @function
                 * @param {Boolean} a Argument A.
                 * @param {Boolean} b Argument B.
                 * @return {Number} Result as follows:
                 * <ul>
                 *     <li><code>-1</code> - if A < B.</li>
                 *     <li><code>0</code> - if A == B.</li>
                 *     <li><code>1</code> - if A > B.</li>
                 * </ul>
                 * */
                booleanComparator2Asc: booleanComparator2Asc,
                /**
                 * @function
                 * @param {Boolean} a Argument A.
                 * @param {Boolean} b Argument B.
                 * @return {Number} Result as follows:
                 * <ul>
                 *     <li><code>-1</code> - if A < B.</li>
                 *     <li><code>0</code> - if A == B.</li>
                 *     <li><code>1</code> - if A > B.</li>
                 * </ul>
                 * */
                booleanComparator2Desc: booleanComparator2Desc,
                /**
                 * Method to compare objects by it's <code>name</code> property.
                 * @function
                 * @param {Object} a Argument A.
                 * @param {Object} b Argument B.
                 * @return {Number} Result as follows:
                 * <ul>
                 *     <li><code>-1</code> - if A < B.</li>
                 *     <li><code>0</code> - if A == B.</li>
                 *     <li><code>1</code> - if A > B.</li>
                 * </ul>
                 * */
                referenceComparator2Asc: referenceComparator2Asc,
                /**
                 * Method to compare objects by it's <code>name</code> property.
                 * @function
                 * @param {Object} a Argument A.
                 * @param {Object} b Argument B.
                 * @return {Number} Result as follows:
                 * <ul>
                 *     <li><code>-1</code> - if A < B.</li>
                 *     <li><code>0</code> - if A == B.</li>
                 *     <li><code>1</code> - if A > B.</li>
                 * </ul>
                 * */
                referenceComparator2Desc: referenceComparator2Desc,
                /**
                 * Method returns comparator function based on type name.
                 * @function
                 * @param {String} dataType Data type as in <code>core.meta.objectPropertyTypes</code>.
                 * @param {String} sorting What sorting do we need? Options: <ul><li><code>'asc'</code></li><li><code>'desc'</code></li></ul>
                 * @return {Function} Comparator function.
                 * */
                getComparatorByDataType: getComparatorByDataType
            };
        });