<commit_before>(function() {
    'use strict';

    angular.module('chaise.record')

    .factory('constants', [function(){
        return {
            defaultPageSize: 25,
            MAX_CONCURENT_REQUEST: 6
        };
    }])

    .factory('recordAppUtils',
             ['constants', 'DataUtils', 'Errors', 'ErrorService', '$log', 'logActions', 'modalBox', '$q', 'recordTableUtils', '$rootScope',
             function (constants, DataUtils, Errors, ErrorService, $log, logActions, modalBox, $q, recordTableUtils, $rootScope) {

        /**
         * returns true if we have free slots for requests.
         * @private
         */
        function _haveFreeSlot() {
            var res = $rootScope.recordFlowControl.occupiedSlots < $rootScope.recordFlowControl.maxRequests;
            if (!res) {
                $log.debug("No free slot available.");
            }
            return res;
        }

        /**
         * @private
         * Flow-control logic for record app.
         * This will go through different sections of the page and will update them
         * if it's needed to.
         */
        function _processRequests(isUpdate) {
            if (!_haveFreeSlot() || $rootScope.pauseRequests) return;

            if ($rootScope.isMainDirty) {
                readMainEntity().then(function (tuple) {
                    $rootScope.isMainDirty = false;
                    _processRequests(isUpdate);
                }).catch(function (err) {
                    // show modal with different text if 400 Query Timeout Error
                    if (err instanceof ERMrest.QueryTimeoutError) {
                        err.subMessage = err.message;
                        err.message = "The main entity cannot be retrieved.";
                        ErrorService.handleException(err, true);
                    } else {
                        if (DataUtils.isObjectAndKeyDefined(err.errorData, 'redirectPath')) {
                            var redirectLink = UriUtils.createRedirectLinkFromPath(err.errorData.redirectPath);
                            err.errorData.redirectUrl = redirectLink.replace('record', 'recordset');
                        }
                        throw err;
                    }
                });
                return;
            }

            var i = 0, model, logObject;

            // inline entities
            for (i = 0; i < $rootScope.columnModels.length && $rootScope.hasInline; i++) {
                model = $rootScope.columnModels[i];
                if (!model.isInline || !model.tableModel.dirtyResult) continue;
                if (!_haveFreeSlot()) return;
                model.tableModel.logObject = _getTableModelLogObject(model.tableModel, isUpdate ? logActions.recordInlineUpdate : logActions.recordInlineRead);
                recordTableUtils.updateMainEntity(model.tableModel, _processRequests, !isUpdate, false);
            }

            // main aggregates
            if ($rootScope.hasAggregate) {
                readMainAggregates(isUpdate);
            }

            // related entites
            for (i = 0; i < $rootScope.relatedTableModels.length; i++) {
                model = $rootScope.relatedTableModels[i];
                if (!model.tableModel.dirtyResult) continue;
                if (!_haveFreeSlot()) return;
                model.tableModel.logObject = _getTableModelLogObject(model.tableModel, isUpdate ? logActions.recordRelatedUpdate : logActions.recordRelatedRead);
                recordTableUtils.updateMainEntity(model.tableModel, _processRequests, !isUpdate, false);
            }

            // aggregates in inline
            for (i = 0; i < $rootScope.columnModels.length && $rootScope.hasInline; i++) {
                model = $rootScope.columnModels[i];
                if (!model.isInline || model.tableModel.dirtyResult) continue;
                if (!_haveFreeSlot()) return;
                logObject = _getTableModelLogObject(model.tableModel, isUpdate ? logActions.recordInlineAggregateUpdate : logActions.recordInlineAggregate);
                recordTableUtils.updateColumnAggregates(model.tableModel, _processRequests, logObject, !isUpdate);
            }

            // aggregates in related
            for (i = 0; i < $rootScope.relatedTableModels.length; i++) {
                model = $rootScope.relatedTableModels[i];
                if (model.tableModel.dirtyResult) continue;
                if (!_haveFreeSlot()) return;
                logObject = _getTableModelLogObject(model.tableModel, isUpdate ? logActions.recordRelatedAggregateUpdate : logActions.recordRelatedAggregate);
                recordTableUtils.updateColumnAggregates(model.tableModel, _processRequests, logObject, !isUpdate);
            }
        }

        /**
         * Read data for the main entity
         * @returns {Promise} It will be resolved with Page object.
         */
        function readMainEntity() {
            var defer = $q.defer();

            $rootScope.reference.read(1, {action: logActions.recordRead}).then(function (page) {
                $log.info("Page: ", page);

                /*
                *  recordSetLink should be used to present user with  an option in case of no data found/more data found(>1)
                *  This could be link to RECORDSET or SEARCH.
                */
                var recordSetLink = page.reference.unfilteredReference.contextualize.compact.appLink;
                var tableDisplayName = page.reference.displayname.value;
                if (page.tuples.length < 1) {
                    throw new Errors.noRecordError({}, tableDisplayName, recordSetLink);
                }
                else if(page.hasNext || page.hasPrevious){
                    throw new Errors.multipleRecordError(tableDisplayName, recordSetLink);
                }

                $rootScope.page = page;
                var tuple = $rootScope.tuple = page.tuples[0];

                // Used directly in the record-display directive
                $rootScope.recordDisplayname = tuple.displayname;

                // Collate tuple.isHTML and tuple.values into an array of objects
                // i.e. {isHTML: false, value: 'sample'}
                $rootScope.recordValues = [];
                tuple.values.forEach(function(value, index) {
                    $rootScope.recordValues.push({
                        isHTML: tuple.isHTML[index],
                        value: value
                    });
                });

                $rootScope.displayReady = true;
                defer.resolve(page);
            }).catch(function (err) {
                defer.reject(err);
            });

            return defer.promise;
        }

        /**
         * @private
         * creates the read request for aggregate columns of the main entity
         */
        function readMainAggregates(isUpdate) {
            $rootScope.columnModels.forEach(function (model, index) {
                if (!model.isAggregate || !_haveFreeSlot() || !model.dirtyResult) return;
                $rootScope.recordFlowControl.occupiedSlots++;
                model.dirtyResult = false;
                model.isLoading = true;
                _readMainColumnAggregate(model.column, index, $rootScope.recordFlowControl.counter).then(function (res) {
                    $rootScope.recordFlowControl.occupiedSlots--;
                    model.dirtyResult = !res;
                    _processRequests(isUpdate);
                }).catch(function (err) {
                    model.isLoading = false;
                    if (err instanceof ERMrest.QueryTimeoutError) {
                        // TODO: how to show column aggregates error
                        // is this columns in a related table? should it be `!` on the column header?
                        model.hasError = true;
                    } else {
                        if (DataUtils.isObjectAndKeyDefined(err.errorData, 'redirectPath')) {
                            var redirectLink = UriUtils.createRedirectLinkFromPath(err.errorData.redirectPath);
                            err.errorData.redirectUrl = redirectLink.replace('record', 'recordset');
                        }
                        throw err;
                    }
                });
            });
        }

        /**
         * @private
         * Generate request for each individual aggregate columns.
         * Returns a promise. The resolved value denotes the success or failure.
         */
        function _readMainColumnAggregate(column, index, current) {
            var defer = $q.defer();
            var logObject = column.reference.defaultLogInfo;
            logObject.action = logActions.recordAggregate;
            logObject.referrer = $rootScope.reference.defaultLogInfo;

            column.getAggregatedValue($rootScope.page, logObject).then(function (values) {
                $rootScope.columnModels[index].isLoading = false;
                if ($rootScope.recordFlowControl.counter !== current) {<commit_msg>remove comment<commit_after>(function() {
    'use strict';

    angular.module('chaise.record')

    .factory('constants', [function(){
        return {
            defaultPageSize: 25,
            MAX_CONCURENT_REQUEST: 6
        };
    }])

    .factory('recordAppUtils',
             ['constants', 'DataUtils', 'Errors', 'ErrorService', '$log', 'logActions', 'modalBox', '$q', 'recordTableUtils', '$rootScope',
             function (constants, DataUtils, Errors, ErrorService, $log, logActions, modalBox, $q, recordTableUtils, $rootScope) {

        /**
         * returns true if we have free slots for requests.
         * @private
         */
        function _haveFreeSlot() {
            var res = $rootScope.recordFlowControl.occupiedSlots < $rootScope.recordFlowControl.maxRequests;
            if (!res) {
                $log.debug("No free slot available.");
            }
            return res;
        }

        /**
         * @private
         * Flow-control logic for record app.
         * This will go through different sections of the page and will update them
         * if it's needed to.
         */
        function _processRequests(isUpdate) {
            if (!_haveFreeSlot() || $rootScope.pauseRequests) return;

            if ($rootScope.isMainDirty) {
                readMainEntity().then(function (tuple) {
                    $rootScope.isMainDirty = false;
                    _processRequests(isUpdate);
                }).catch(function (err) {
                    // show modal with different text if 400 Query Timeout Error
                    if (err instanceof ERMrest.QueryTimeoutError) {
                        err.subMessage = err.message;
                        err.message = "The main entity cannot be retrieved.";
                        ErrorService.handleException(err, true);
                    } else {
                        if (DataUtils.isObjectAndKeyDefined(err.errorData, 'redirectPath')) {
                            var redirectLink = UriUtils.createRedirectLinkFromPath(err.errorData.redirectPath);
                            err.errorData.redirectUrl = redirectLink.replace('record', 'recordset');
                        }
                        throw err;
                    }
                });
                return;
            }

            var i = 0, model, logObject;

            // inline entities
            for (i = 0; i < $rootScope.columnModels.length && $rootScope.hasInline; i++) {
                model = $rootScope.columnModels[i];
                if (!model.isInline || !model.tableModel.dirtyResult) continue;
                if (!_haveFreeSlot()) return;
                model.tableModel.logObject = _getTableModelLogObject(model.tableModel, isUpdate ? logActions.recordInlineUpdate : logActions.recordInlineRead);
                recordTableUtils.updateMainEntity(model.tableModel, _processRequests, !isUpdate, false);
            }

            // main aggregates
            if ($rootScope.hasAggregate) {
                readMainAggregates(isUpdate);
            }

            // related entites
            for (i = 0; i < $rootScope.relatedTableModels.length; i++) {
                model = $rootScope.relatedTableModels[i];
                if (!model.tableModel.dirtyResult) continue;
                if (!_haveFreeSlot()) return;
                model.tableModel.logObject = _getTableModelLogObject(model.tableModel, isUpdate ? logActions.recordRelatedUpdate : logActions.recordRelatedRead);
                recordTableUtils.updateMainEntity(model.tableModel, _processRequests, !isUpdate, false);
            }

            // aggregates in inline
            for (i = 0; i < $rootScope.columnModels.length && $rootScope.hasInline; i++) {
                model = $rootScope.columnModels[i];
                if (!model.isInline || model.tableModel.dirtyResult) continue;
                if (!_haveFreeSlot()) return;
                logObject = _getTableModelLogObject(model.tableModel, isUpdate ? logActions.recordInlineAggregateUpdate : logActions.recordInlineAggregate);
                recordTableUtils.updateColumnAggregates(model.tableModel, _processRequests, logObject, !isUpdate);
            }

            // aggregates in related
            for (i = 0; i < $rootScope.relatedTableModels.length; i++) {
                model = $rootScope.relatedTableModels[i];
                if (model.tableModel.dirtyResult) continue;
                if (!_haveFreeSlot()) return;
                logObject = _getTableModelLogObject(model.tableModel, isUpdate ? logActions.recordRelatedAggregateUpdate : logActions.recordRelatedAggregate);
                recordTableUtils.updateColumnAggregates(model.tableModel, _processRequests, logObject, !isUpdate);
            }
        }

        /**
         * Read data for the main entity
         * @returns {Promise} It will be resolved with Page object.
         */
        function readMainEntity() {
            var defer = $q.defer();

            $rootScope.reference.read(1, {action: logActions.recordRead}).then(function (page) {
                $log.info("Page: ", page);

                /*
                *  recordSetLink should be used to present user with  an option in case of no data found/more data found(>1)
                *  This could be link to RECORDSET or SEARCH.
                */
                var recordSetLink = page.reference.unfilteredReference.contextualize.compact.appLink;
                var tableDisplayName = page.reference.displayname.value;
                if (page.tuples.length < 1) {
                    throw new Errors.noRecordError({}, tableDisplayName, recordSetLink);
                }
                else if(page.hasNext || page.hasPrevious){
                    throw new Errors.multipleRecordError(tableDisplayName, recordSetLink);
                }

                $rootScope.page = page;
                var tuple = $rootScope.tuple = page.tuples[0];

                // Used directly in the record-display directive
                $rootScope.recordDisplayname = tuple.displayname;

                // Collate tuple.isHTML and tuple.values into an array of objects
                // i.e. {isHTML: false, value: 'sample'}
                $rootScope.recordValues = [];
                tuple.values.forEach(function(value, index) {
                    $rootScope.recordValues.push({
                        isHTML: tuple.isHTML[index],
                        value: value
                    });
                });

                $rootScope.displayReady = true;
                defer.resolve(page);
            }).catch(function (err) {
                defer.reject(err);
            });

            return defer.promise;
        }

        /**
         * @private
         * creates the read request for aggregate columns of the main entity
         */
        function readMainAggregates(isUpdate) {
            $rootScope.columnModels.forEach(function (model, index) {
                if (!model.isAggregate || !_haveFreeSlot() || !model.dirtyResult) return;
                $rootScope.recordFlowControl.occupiedSlots++;
                model.dirtyResult = false;
                model.isLoading = true;
                _readMainColumnAggregate(model.column, index, $rootScope.recordFlowControl.counter).then(function (res) {
                    $rootScope.recordFlowControl.occupiedSlots--;
                    model.dirtyResult = !res;
                    _processRequests(isUpdate);
                }).catch(function (err) {
                    model.isLoading = false;
                    if (err instanceof ERMrest.QueryTimeoutError) {
                        model.hasError = true;
                    } else {
                        if (DataUtils.isObjectAndKeyDefined(err.errorData, 'redirectPath')) {
                            var redirectLink = UriUtils.createRedirectLinkFromPath(err.errorData.redirectPath);
                            err.errorData.redirectUrl = redirectLink.replace('record', 'recordset');
                        }
                        throw err;
                    }
                });
            });
        }

        /**
         * @private
         * Generate request for each individual aggregate columns.
         * Returns a promise. The resolved value denotes the success or failure.
         */
        function _readMainColumnAggregate(column, index, current) {
            var defer = $q.defer();
            var logObject = column.reference.defaultLogInfo;
            logObject.action = logActions.recordAggregate;
            logObject.referrer = $rootScope.reference.defaultLogInfo;

            column.getAggregatedValue($rootScope.page, logObject).then(function (values) {
                $rootScope.columnModels[index].isLoading = false;
                if ($rootScope.recordFlowControl.counter !== current) {
{'fraction_non_alphanumeric': 0.09617315630927145, 'fraction_numerical': 0.0016735468035256054, 'mean_word_length': 1.6844863731656186, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7622487', 'n_tokens_mistral': 4496, 'n_tokens_neox': 4272, 'n_words': 952}