// (C) Copyright 2020 Hewlett-Packard Enterprise Company, L.P.
define(['hp/services/REST',  
        'hp/services/IndexFilter', 
        'jquery'],
function(REST, IndexFilter) { "use strict";

    var IndexThrottler = (function() {

        // Max len of HTTP GET for IE8 is 2K bytes. see http://support.microsoft.com/kb/208427
        var HTTP_REQUEST_THRESHOLD = 2000,
            BATCH_SIZE = 5,
            URI_PROP_NAME = '_uri',
            PREFIX_OR = ' OR ';

        /**
         * Constructor
         */
        function IndexThrottler() {
            var urlPrefix;
            var version;
            var filter;
            var handlers;
            var restUriArray;
            var total;
            var batchLength;
            var done;
            var data;
            var isAssociation;
            
            function mergeResult(data, indexResources) {
                data.count += indexResources.count;
                data.total += indexResources.total;
                if (data.members && indexResources.members) {
                    $.merge(data, indexResources);
                }
            }

            // REST call throttling
            function processNextBatch(handlers) {
                // Support REST call throttling.
                var batchUris = restUriArray.splice(0, BATCH_SIZE);
                batchLength = batchUris.length;
                $.each(batchUris, function (index, uri) {
                    REST.getURI(uri, handlers, {apiVersion: version});
                });                
            }
            
            // Encode one or more uris stored in the uriArray into an array of restUri string so that
            // each would contain one uri like so:
            // e.g. "...&filter="_uri:'/rest/index/resource/item1'"
            // For V1, only 1 uri can be encoded in each REST call.
            function getRestUriArrayV1(uriStr, uriArray) {
                var totalUriCount = uriArray.length;
                var restUri;
                var urisArray=[];
                
                for (var i=0; i<totalUriCount; i++) {
                    restUri = uriStr + '&filter="_uri:\'' + uriArray[i] + '\'"';
                    urisArray.push(restUri);                    
                }
                return urisArray;
            }
            
            // Encode one or more uris stored in the uriArray into an array of restUri string so that
            // each would contain one or more uri like so:
            // e.g. ...&query="(_uri:'/rest/index/resource/item1' OR _uri:'/rest/index/resource/item2')"
            // Each restUri should not be longer than the threshold (2000). 
            function getRestUriArray(uriStr, uriArray) {
                var totalUriCount = uriArray.length;
                // baseUriStr should have one of the following syntax
                // 1) ...?query="(something) AND (
                // 2) ...?query="(
                var baseUriStr = uriStr;
                var restUri = baseUriStr;
                var prefix = '';
                var uriItem;
                var urisArray=[];
                
                for (var i=0; i<totalUriCount; i++) {
                    uriItem = prefix + '_uri:\'' + uriArray[i] + '\'';
                    if (prefix === '') {
                        prefix = PREFIX_OR;
                    }
                    
                    // If the current REST uri is already full, start a new one
                    if ((restUri.length + uriItem.length) > HTTP_REQUEST_THRESHOLD) {
                        restUri += ')"';
                        urisArray.push(restUri); 
                        restUri = baseUriStr;
                        uriItem = '_uri:\'' + uriArray[i] + '\'';
                    }
                    restUri += uriItem;
                    
                    // If this is the last item, wrap up this restUri and start a new one.
                    if (i === totalUriCount-1) {
                        restUri  += ')"';
                        urisArray.push(restUri);
                        restUri = baseUriStr;
                        prefix = '';
                    }
                }
                return urisArray;
            }
            
            function onGetError(errorInfo, xhr) {
                if (!done) {
                    done = true;
                    handlers.error(errorInfo);
                }                            
            }
            
            function onGetSuccess(indexResources) {
                if (!done) {
                    // lazily get this, because of circular dependency
                    require(['hp/services/IndexService'], function(indexService) {
                        indexService.convertIndexResources(indexResources);
                    });
                    --batchLength;
                    if (!data) {
                        data = indexResources;
                    } else {
                        mergeResult(data, indexResources);
                    }
                    done = (restUriArray.length === 0) && (batchLength === 0);
                        
                    if ((data.total === total) || done) {
                        if (handlers && handlers.success) {
                             handlers.success(data);
                        }
                    } else if (batchLength === 0) {
                        processNextBatch({
                            success: onGetSuccess, 
                            error: onGetError
                        });
                    }
                }
            }
            
            // extract the "query" param from the params array
            function extractQueryParam(params) {
                var queryParam = null;
                for (var i=0; i<params.length; i++) {
                    if (params[i].indexOf('query=') === 0) {
                        queryParam = params[i];
                        params.splice(i,1);
                        break;
                    }
                }
                return queryParam;
            }
            
            this.getFilteredUris = function() {
                var uriStr = urlPrefix + '/resources?';
                var uriArray = filter.data.properties[URI_PROP_NAME];
                var myFilter = new IndexFilter(filter);
                var params;
                var queryParam;

                // create a base uriStr for REST call without uris array
                myFilter.unsetProperty(URI_PROP_NAME);
                params = myFilter.toRESTParameters(version);
                
                if (version === 1) {
                    uriStr += params.join('&');
                    restUriArray = getRestUriArrayV1(uriStr, uriArray);
                } else {
                    // remove 'query=' param from the params array first
                    queryParam = extractQueryParam(params);
                    if (queryParam) {
                        // replace the ending double quote with ' AND ('
                        queryParam = queryParam.substring(0, queryParam.length - 1) + ' AND (';
                    } else {
                        queryParam = 'query="(';
                    }
                    
                    uriStr += params.join('&');
                    uriStr = uriStr + '&' + queryParam;
                    
                    restUriArray = getRestUriArray(uriStr, uriArray);
                }
                total = restUriArray.length;
                processNextBatch({
                    success: onGetSuccess, 
                    error: onGetError
                });
            };
            
            this.init = function(arg) {
                urlPrefix = arg.urlPrefix;
                version = arg.version;
                filter = arg.filter;
                handlers = arg.handlers;
                batchLength = 0;
                done = false;
                data = null;
                isAssociation= filter.data.hasOwnProperty('associationName');
                if (isAssociation && version > 1) {
                    // the prefix should be '/rest/index/associations' starting version 2
                    urlPrefix += '/associations';
                }
            };
        }

        return IndexThrottler;
    }());
    return IndexThrottler;
});