// Not available in IE 11.
// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
    Object.defineProperty(Array.prototype, 'find', {
        value: function (predicate) {
            // 1. Let O be ? ToObject(this value).
            if (this == null) {
                throw new TypeError('"this" is null or not defined');
            }

            var o = Object(this);

            // 2. Let len be ? ToLength(? Get(O, "length")).
            var len = o.length >>> 0;

            // 3. If IsCallable(predicate) is false, throw a TypeError exception.
            if (typeof predicate !== 'function') {
                throw new TypeError('predicate must be a function');
            }

            // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
            var thisArg = arguments[1];

            // 5. Let k be 0.
            var k = 0;

            // 6. Repeat, while k < len
            while (k < len) {
                // a. Let Pk be ! ToString(k).
                // b. Let kValue be ? Get(O, Pk).
                // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
                // d. If testResult is true, return kValue.
                var kValue = o[k];
                if (predicate.call(thisArg, kValue, k, o)) {
                    return kValue;
                }
                // e. Increase k by 1.
                k++;
            }

            // 7. Return undefined.
            return undefined;
        }
    });
}

// https://tc39.github.io/ecma262/#sec-array.prototype.includes
if (!Array.prototype.includes) {
    Object.defineProperty(Array.prototype, 'includes', {
        value: function (searchElement, fromIndex) {

            // 1. Let O be ? ToObject(this value).
            if (this == null) {
                throw new TypeError('"this" is null or not defined');
            }

            var o = Object(this);

            // 2. Let len be ? ToLength(? Get(O, "length")).
            var len = o.length >>> 0;

            // 3. If len is 0, return false.
            if (len === 0) {
                return false;
            }

            // 4. Let n be ? ToInteger(fromIndex).
            //    (If fromIndex is undefined, this step produces the value 0.)
            var n = fromIndex | 0;

            // 5. If n ≥ 0, then
            //  a. Let k be n.
            // 6. Else n < 0,
            //  a. Let k be len + n.
            //  b. If k < 0, let k be 0.
            var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

            function sameValueZero(x, y) {
                return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
            }

            // 7. Repeat, while k < len
            while (k < len) {
                // a. Let elementK be the result of ? Get(O, ! ToString(k)).
                // b. If SameValueZero(searchElement, elementK) is true, return true.
                // c. Increase k by 1. 
                if (sameValueZero(o[k], searchElement)) {
                    return true;
                }
                k++;
            }

            // 8. Return false
            return false;
        }
    });
}

if (!String.prototype.includes) {
    String.prototype.includes = function (search, start) {
        'use strict';
        if (typeof start !== 'number') {
            start = 0;
        }

        if (start + search.length > this.length) {
            return false;
        } else {
            return this.indexOf(search, start) !== -1;
        }
    };
}

if (!String.prototype.startsWith) {
    String.prototype.startsWith = function (search, pos) {
        return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
    };
}

if (typeof Object.assign != 'function') {
    // Must be writable: true, enumerable: false, configurable: true
    Object.defineProperty(Object, "assign", {
        value: function assign(target, varArgs) { // .length of function is 2
            'use strict';
            if (target == null) { // TypeError if undefined or null
                throw new TypeError('Cannot convert undefined or null to object');
            }

            var to = Object(target);

            for (var index = 1; index < arguments.length; index++) {
                var nextSource = arguments[index];

                if (nextSource != null) { // Skip over if undefined or null
                    for (var nextKey in nextSource) {
                        // Avoid bugs when hasOwnProperty is shadowed
                        if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
                            to[nextKey] = nextSource[nextKey];
                        }
                    }
                }
            }
            return to;
        },
        writable: true,
        configurable: true
    });
}
(function (calico) {
    // Displays error modal with message, returns a promise that resolves
    // when the modal is dismissed
    calico.showErrorDialogAsync = function (message) {
        $("#calico-error-message").html(message);
        $("#calico-error-modal").modal("show");

        var deferred = $.Deferred();
        // using 'one' not 'on' in the event the modal is displayed multiple times we don't want
        // the dismissedCallback to fire more than once;
        $("#calico-error-modal").one('hide.bs.modal', function () {
            deferred.resolve();
        });

        return deferred.promise();
    }

    // Displays modal with title and message, returns a promise that resolves
    // when the modal is dismissed
    calico.showMessageDialogAsync = function (title, message) {
        if (title != null && title.length) {
            $("#calico-message-modal-title").text(title);
        }
        $("#calico-message").text(message);
        $("#calico-message-modal").modal("show");

        var deferred = $.Deferred();
        // using 'one' not 'on' in the event the modal is displayed multiple times we don't want
        // the dismissedCallback to fire more than once;
        $("#calico-message-modal").one('hide.bs.modal', function () {
            deferred.resolve();
        });

        return deferred.promise();
    }

    var confirmDeferred = null;
    $(document).ready(function () {
        $("#calico-confirm-confirmation-button").click(function () {
            $("#calico-confirm-modal").modal("hide");
            if (confirmDeferred)
                confirmDeferred.resolve(true);
            confirmDeferred = null;
        });
        $("#calico-confirm-cancel-button").click(function () {
            $("#calico-confirm-modal").modal("hide");
            if (confirmDeferred)
                confirmDeferred.resolve(false);
            confirmDeferred = null;
        });
    });

    // Displays modal with title and message, returns a promise that resolves
    // when the modal is dismissed
    calico.showConfirmDialogAsync = function (title, message, confirmText, cancelText) {
        if (confirmDeferred)
            confirmDeferred.reject();
        confirmDeferred = null;

        if (title != null && title.length) {
            $("#calico-confirm-modal-title").text(title);
        }

        if (confirmText != null && confirmText.length) {
            $("#calico-confirm-confirmation-button").text(confirmText);
        }

        if (cancelText != null && cancelText.length) {
            $("#calico-confirm-cancel-button").text(cancelText);
        }

        $("#calico-confirm-message").text(message);
        $("#calico-confirm-modal").modal("show");

        confirmDeferred = $.Deferred();

        return confirmDeferred.promise();
    }

    // Deprecated function names
    calico.ShowErrorDialog = calico.showErrorDialogAsync;
    calico.ShowMessageModal = calico.showMessageDialogAsync;

})(window.calico = window.calico || {});


(function (calico) {
    // When requests to show the please wait dialog come in, if we don't
    // properly manage the appearance of the modal along with multiple requests
    // to show or hide then we can end up in a state where the UI can't be interacted with 
    // (often caused by issues with calls to show/hide the bootstrap modal)

    // Tunable parameters:
    // Give a quarter second for very quick requests to complete with out visual interruption
    // the UI will always be blocked immediately
    var showModalWaitMs = 250;
    // If we do have to show the modal, show for at least half a second for smoother transitions
    var hideModalWaitMs = 500;
    // end of tunable parameters

    var showRequestCount = 0;
    var modalShowing = false;
    var processingDiv = null;
    var modalManagerTimerRunning = false;
    var uiIsBlocked = false;
    var transitionToWarmingTimestamp = null;
    var coolDownStartedTimestamp = null;

    var AWAITING_REQUESTS_STATE = "awaiting_requests_state";
    var WARMING_UP_STATE = "warming_up_state";
    var COOLING_DOWN_STATE = "cooling_down_state";
    var SHOWING_MODAL_STATE = "showing_modal_state";
    var modalManagerState = AWAITING_REQUESTS_STATE;

    // Hook into the modal's events so we know when the animations start and complete
    $(document).ready(function () {
        processingDiv = $("#processing-modal");
        if (!processingDiv)
            return;

        processingDiv.on('show.bs.modal', function (e) {
            modalShowing = true;
        });
        processingDiv.on('hidden.bs.modal', function (e) {
            modalShowing = false;
        });

        // Add the block overlay
        $("html").append($('<div id="preventClickOverlay" onclick="return false;" style="display:none;"></div>'));
    });

    // Functions to toggle the ajax processing div to modalize the screen while ajax operations are happening.
    // The 'processing-modal' div is defined in the _Layout.cshtml file at the root of the shared views folder.
    calico.showPleaseWait = function (message) {
        if (!processingDiv)
            return;

        if ((message) && (message.length > 0)) {
            $("#processing-modal-message").html(message);
        } else {
            $("#processing-modal-message").html("Processing...");
        }

        // When a show request comes in
        // - Increment a request counter
        // - If its the first request, block the UI and set blocked UI flag
        // - Start a 200ms repeating timer, if it hasn't started already. 
        ++showRequestCount;
        _debug("incrementing");
        if (!uiIsBlocked) {
            uiIsBlocked = true;
            // Immedately prevent interaction by putting a blocking div on the page
            // The modal manager will hide this when no more requests have come in
            $("#preventClickOverlay").show();
        }
        _ensureModalManagerRunning();
    };

    calico.hidePleaseWait = function () {
        if (!processingDiv)
            return;

        // When a hide request comes in
        // - Decrement the request counter (floor at zero), the modal manager will do the rest
        if (showRequestCount > 0) {
            --showRequestCount;
            _debug("decrementing");
        }
    };

    function _ensureModalManagerRunning() {
        if (modalManagerTimerRunning) 
            return;

        modalManagerTimerRunning = true;
        _debug("starting timer");
        var timerHandle = setInterval(function () {
            // Modal manager state machine
            _debug("timer fired");
            switch (modalManagerState) {
                case AWAITING_REQUESTS_STATE:
                    if (modalShowing) {
                        _debug("waiting for modal to hide");
                        // If the modal is animating then return and wait for that to complete
                        break;
                    }

                    if (showRequestCount > 0) {
                        // Transition to the warming up state
                        transitionToWarmingTimestamp = new Date();
                        modalManagerState = WARMING_UP_STATE;
                        _debug("warming up");
                    } else {
                        // No requests currently
                        // Check if the UI is blocked and unblock immediately
                        if (uiIsBlocked) {
                            $("#preventClickOverlay").hide();
                            uiIsBlocked = false;
                        }

                        _debug("sleeping timer");
                        // Go back to sleep until the next call showPleaseWait comes in
                        modalManagerTimerRunning = false;
                        // Stop the JS timer
                        clearInterval(timerHandle);
                    }
                    break;
                case WARMING_UP_STATE:
                    if (showRequestCount > 0) {
                        // We have requests, check to see if we exceeded the warmup time
                        // if so, lets show a modal
                        var timeWarmingUpMs = new Date() - transitionToWarmingTimestamp;
                        if (timeWarmingUpMs > showModalWaitMs) {
                            modalManagerState = SHOWING_MODAL_STATE;
                            _debug("showing");
                            processingDiv.modal("show");
                        }
                    } else {
                        // No more requests are running return to the awaiting state
                        modalManagerState = AWAITING_REQUESTS_STATE;
                    }
                    break;
                case SHOWING_MODAL_STATE:
                    if (showRequestCount < 1) {
                        coolDownStartedTimestamp = new Date();
                        modalManagerState = COOLING_DOWN_STATE;
                        _debug("cooling down");
                    }
                    break;
                case COOLING_DOWN_STATE:
                    if (showRequestCount > 0) {
                        // More requests came in, keep showing modal
                        modalManagerState = SHOWING_MODAL_STATE;
                        _debug("warming back up");
                    } else {
                        var timeCoolingDown = new Date() - coolDownStartedTimestamp;
                        if (timeCoolingDown > hideModalWaitMs) {
                            modalManagerState = AWAITING_REQUESTS_STATE;
                            _debug("hiding");
                            processingDiv.modal("hide");
                        }
                    }
                    break;
                default:
            }
        }, 200) // ms
    }

    function _debug(message) {
        // Uncomment for debug output
        //console.log(message);
    }
})(window.calico = window.calico || {});


(function (calico) {
    // Just like jQuery.ajax this function returns a promise so the 'then' function can be called on the result
    // to easily execute code after the request finishes. (See: http://api.jquery.com/category/deferred-object/)
    // Options and defaults:
    //        type: 'POST'
    //        cache: false
    //        showProcessing: true
    //        data: undefined
    //        updateDiv: undefined
    //        showDefaultError: true
    //        showDefaultSuccess: true
    // Example:
    //        // It is OK to omit the second 'options' argument if you are using the defaults
    //        window.calico.ajaxAsync('test/url')
    //        .then(function (data) {
    //            // Do interesting things with the data
    //        })
    //        .catch(function (xhr, error) {
    //            // Handle error, this is called after the 'OK' button is clicked on
    //            // the default error message dialog
    //            // further cleanup can be done like refreshing the page or resetting UI state
    //        });
    // Modifying default options:
    //        window.calico.ajaxAsync('test/url', { type: 'GET' })
    //        .then(function (data) {
    //            // Do interesting things with the data
    //        });
    // Don't show the default error modal:
    //        window.calico.ajaxAsync('test/url', { showDefaultError: false })
    //        .then(function (data) {
    //            // Do interesting things with the data
    //        })
    //        .catch(function (error) {
    //            // Handle error, this is called immediately on request failure 
    //        });
    // Example passing another named function:
    //        window.calico.ajaxAsync('test/url').then(doInterestingWork);
    //
    //        function doInterestingWork(data) {
    //            // Do interesting things with the data
    //        });
    // Chain dependent ajax requests:
    //        window.calico.ajaxAsync('test/url')
    //        .then(function (data) {
    //            return window.calico.ajaxAsync('test/url', { 
    //                data: { newData: "some new data based on the result of the first request"}
    //            });
    //        })
    //        .then(function (data) {
    //            // Do interesting things with the result of the second ajaxAsync
    //        });
    // Make concurrent ajax calls and do something when they all complete:
    //        var ajaxCallOne = window.calico.ajaxAsync('test/url');
    //        var ajaxCallTwo = window.calico.ajaxAsync('test/url');
    //        $.when(ajaxCallOne, ajaxCallTwo)
    //        .then(function (responseOne, responseTwo) {
    //            // Do interesting things with the results of all the calls
    //        });
    //
    calico.ajaxAsync = function (url, options) {
        options = Object.assign({
            // defaults
            type: "POST",
            cache: false,
            updateDiv: null,
            showProcessing: true,
            showDefaultError: true,
            showDefaultSuccess: true,
        }, options);

        // This promise will be returned to the function caller
        var operationPromise = $.Deferred();

        if (options.showProcessing === true) {
            calico.showPleaseWait();
        }

        var ajaxOptions = {
            type: options.type || "POST",
            url: url,
            cache: options.cache || false,
            data: options.data,
            success: function (data) {
                // Todo: check if request was redirected, possible?
                // Todo: check data to make sure its valid html, maybe hidden value in html
                if (options.updateDiv) {
                    options.updateDiv.html(data);
                }
                if (options.showProcessing === true) {
                    calico.hidePleaseWait();
                }
                var dataHasUserMessage = data.UserMessage && data.UserMessage.length > 0;
                if (data.Success === true) {
                    if (options.showDefaultSuccess && dataHasUserMessage) {
                        calico.ShowMessageModal("Success", data.UserMessage)
                            .then(function () {
                                operationPromise.resolve(data);
                            });
                    } else {
                        operationPromise.resolve(data);
                    }
                } else if (data.Success === false) {
                    if (options.showDefaultError === true && dataHasUserMessage) {
                        calico.ShowErrorDialog(data.UserMessage, "Error", function () {
                            // the dialog has now been dismissed and we can reject the promise
                            // so the caller can do whatever cleanup may be necessary
                            operationPromise.reject(data);
                        });
                    } else {
                        // the caller set showDefaultError to false, promise is rejected
                        // so the caller can do whatever error handling is needed
                        operationPromise.reject(data);
                    }
                } else {
                    // It looks like we got some other kind of data just pass it through
                    operationPromise.resolve(data);
                }
            },
            error: function (jqXHR, textStatus, errorThrown) {
                if (options.showProcessing === true) {
                    calico.hidePleaseWait();
                }
                var errorObject = { success: false, statusCode: jqXHR.status };
                var errorMessage;
                // We've reached a more serious unrecoverable error, the user will need some more information
                // to give them context for the error
                // i.e. Server 500 error, timeout 
                errorMessage = "There was an error loading a resource on the page. You may need to refresh the page to continue working. <br>Error: " + textStatus + "<br>" + errorThrown;
                if (options.showDefaultError === true) {
                    calico.ShowErrorDialog(errorMessage, "Error", function () {
                        // the dialog has now been dismissed and we can reject the promise
                        // so the caller can do whatever cleanup may be necessary
                        operationPromise.reject(errorObject, jqXHR);
                    });
                } else {
                    // the caller set showDefaultError to false, promise is rejected
                    // so the caller can do whatever error handling is needed
                    operationPromise.reject(errorObject, jqXHR);
                }
            }
        }
        $.ajax(ajaxOptions);

        return operationPromise;
    }
})(window.calico = window.calico || {});


$(document).ready(function () {
    $("#btnSubmitGrowerRequest").click(function () {
        var permitNumber = $("#txtPermitNumber").val();
        var countyId = $('#ConnectGrowerCountyId').val();

        if ((typeof permitNumber === "undefined") || (permitNumber.length === 0)) {
            alert("Please enter a permit Number");
            return false;
        }
        else if (permitNumber.match(/^[0-9a-zA-Z]{7}$/) === null) {
            alert("Permit number entered in the wrong format");
            return false;
        }

        if ((typeof countyId === "undefined") || (countyId.length === 0)) {
            alert("Please select a home county");
            return false;
        }
        var modal = $("#addPermitModal");
        modal.modal("hide");

        var postData = {
            countyId: countyId,
            permitNumber: permitNumber,
        }

        var options = {
            data: postData,
        }

        calico.ajaxAsync("/GrowerApplicator/SubmitRequestToAddGrowerPermitToBeeWhere", options)
    });

    $("#addPermitModal").on("show.bs.modal", function () {
        $("#txtPermitNumber").val("");
        $("#GrowerHomeCountyId").val("");
    });

    $("#addPermitModal").on("shown.bs.modal", function () {
        $("#txtPermitNumber").focus();
    });

    // request add applicator modal
    $("#btnSubmitApplicatorRequest").click(function () {
        var licenseNo = $("#txtApplicatorLicenseNumber").val();
        var countyId = $("#ConnectApplicatorCountyId").val();
        var licenseType = $("#ConnectApplicatorLicenseType").val();

        if ((!licenseNo) || (licenseNo.length === 0)) {
            alert("Please enter your License Number");
            return false;
        }

        if ((!licenseType) || (licenseType.length === 0)) {
            alert("Please select a license type");
            return false;
        }

        if ((!countyId) || (countyId.length === 0)) {
            alert("Please select a home county");
            return false;
        }


        var modal = $("#addLicenseModal");
        modal.modal("hide");

        var url = "/GrowerApplicator/SubmitRequestToConnectApplicatorLicense";

        var postData = {
            countyId: countyId,
            licenseNumber: licenseNo,
            licenseType: licenseType,
        }

        var options = {
            data: postData,
        }

        calico.ajaxAsync(url, options)
    });

    $("#addLicenseModal").on("show.bs.modal", function () {
        $("#txtApplicatorLicenseNumber").val("");
        $("#ApplicatorHomeCountyId").val("");
        $("#LicenseType").val("");
    });

    $("#addLicenseModal").on("shown.bs.modal", function () {
        $("#txtApplicatorLicenseNumber").focus();
    });
});

function isCharacterKey(e) {
    return (
        (e.which != 9) &&  // tab
        (e.which != 13) &&  // enter
        (e.which != 16) &&  // shift
        (e.which != 17) &&  // ctrl
        (e.which != 18) &&  // alt
        (e.which != 19) &&  // pause/break
        (e.which != 20) &&  // caps lock
        (e.which != 27) &&  // escape
        (e.which != 33) &&  // page up
        (e.which != 34) &&  // page down
        (e.which != 35) &&  // end
        (e.which != 36) &&  // home
        (e.which != 37) &&  // left arrow
        (e.which != 38) &&  // up arrow
        (e.which != 39) &&  // right arrow
        (e.which != 40) &&  // down arrow
        (e.which != 44) &&  // print screen
        (e.which != 45) &&  // insert
        (e.which != 46)     // delete
    );
}
function checkPassword(currentPasswordElementName, newPasswordElementName, confirmPasswordElementName, minLengthCheckElementName, caseCheckElementName, numberCheckElementName, symbolCheckElementName, submitElementName) {
    var currentPasswordElement = $("#" + currentPasswordElementName);
    var newPasswordElement = $("#" + newPasswordElementName);
    var confirmPasswordElement = $("#" + confirmPasswordElementName);

    var newPasswordIsOk = false;
    var newPassword;
    if (newPasswordElement.length > 0) {

        newPassword = newPasswordElement.val();
        var minLengthOk = false;
        var lowerCaseOk = false;
        var upperCaseOk = false;
        var numbersOk = false;
        var symbolsOk = false;

        // Validate length
        if (newPassword.length >= 8) {
            minLengthOk = true;
        }

        // Validate lowercase letters
        var lowerCaseLetters = /[a-z]/g;
        if (newPassword.match(lowerCaseLetters)) {
            lowerCaseOk = true;
        }

        // Validate capital letters
        var upperCaseLetters = /[A-Z]/g;
        if (newPassword.match(upperCaseLetters)) {
            upperCaseOk = true;
        }

        // Validate numbers
        var numbers = /[0-9]/g;
        if (newPassword.match(numbers)) {
            numbersOk = true;
        }

        // Validate symbols
        var symbols = /[^A-Za-z 0-9]/g;
        if (newPassword.match(symbols)) {
            symbolsOk = true;
        }

        if (minLengthOk) {
            $("#" + minLengthCheckElementName).show();
        } else {
            $("#" + minLengthCheckElementName).hide();
        }

        if ((lowerCaseOk === true) && (upperCaseOk === true)) {
            $("#" + caseCheckElementName).show();
        } else {
            $("#" + caseCheckElementName).hide();
        }

        if (numbersOk) {
            $("#" + numberCheckElementName).show();
        } else {
            $("#" + numberCheckElementName).hide();
        }

        if (symbolsOk) {
            $("#" + symbolCheckElementName).show();
        } else {
            $("#" + symbolCheckElementName).hide();
        }

        if ((minLengthOk === true) && (lowerCaseOk === true) && (upperCaseOk === true) && (numbersOk === true) && (symbolsOk === true)) {
            newPasswordIsOk = true;
        } else {
            newPasswordIsOk = false;
        }
    }

    var currentPasswordIsOk = false;
    if (currentPasswordElement.length > 0) {
        var currentPassword = currentPasswordElement.val();
        if (currentPassword.length > 0) {
            currentPasswordIsOk = true;
        } else {
            currentPasswordIsOk = false;
        }
    } else {
        // If it's not shown no need to check for it
        currentPasswordIsOk = true;
    }

    var confirmPasswordIsOk = false;
    if (confirmPasswordElement.length > 0) {
        var confirmPassword = confirmPasswordElement.val();
        if (confirmPassword === newPassword) {
            confirmPasswordIsOk = true;
        } else {
            confirmPasswordIsOk = false;
        }
    } else {
        // If it's not shown no need to check for it
        confirmPasswordIsOk = true;
    }

    if ((currentPasswordIsOk === true) && (newPasswordIsOk === true) && (confirmPasswordIsOk === true)) {
        $("#" + submitElementName).removeClass("disabled");
    } else {
        $("#" + submitElementName).addClass("disabled");
    }
}

