Source: lib/bucket_proxy.js

var check = require("check-types");
var Immutable = require('immutable');
var _ = require("underscore");

/**
	Caches a copy of inserted links to reduce time in bucket creation.
	@constructor
	@author Tilak Patidar <tilakpatidar@gmail.com>
*/
var BucketProxy = function constructor_bucket_proxy(limit) {

    /**
    	Urls are stored in it. Key is domain and each domain has another json
    	with keys representing levels and each level has an Immutable Set of urls.
    	@private
    	@type Object
    */
    var store = {};

    /**
    	Represents max cache size.
    	@type number
    	@private
    */
    var cache_limit;
    if (!check.assigned(limit)) {
        cache_limit = 10000;
    } else {
        cache_limit = limit;
    }


    /**
    	Represents current size of cache.
    	@private
    	@type number
    */
    var current_size = 0;


    /**
        Stores count of urls in domains and various levels.
        @private
        @type Object

    */
    var count_store = {};


    /**
    	Pushes a url in the cache.
    	@public
    	@param {Url} url
    	@returns {boolean} -status of insertion

    */
    this.pushURL = function pushURL(url) {

        //console.log(current_size,"current_size ",cache_limit);

        if (current_size >= cache_limit) {
            //console.log("BLOCKED");
            var l = url.level;
            if (check.assigned(count_store[url.domain])) {

                //free space

                var url_levels = Object.keys(count_store[url.domain]);

                url_levels.sort();
                url_levels.reverse();

                var found = false;

                _.each(url_levels, function(url_level) {

                    
                    if (url.level < count_store[url.domain][url_level]) {

                        //console.log("freed  ", store[url.domain][url_level].size);
                        store[url.domain][url_level] = store[url.domain][url_level].remove(store[url.domain][url_level].last());
                        //console.log("freeed  ", store[url.domain][url_level].size);

                        if (check.assigned(count_store[url.domain][url_level])) {
                            count_store[url.domain][url_level] -= 1;
                        }

                        found = true;
                        return {}; //break

                    }

                });

                if (!found) {
                    return false;
                }

            } else {
                return false;
            }

        }



        var level = url.level;
        //console.log('here adding');


        if (check.assigned(store[url.domain])) {
            //domain present in the store

            if (check.assigned(store[url.domain][level])) {
                store[url.domain][level] = store[url.domain][level].add(JSON.stringify(url));
            } else {
                store[url.domain][level] = Immutable.Set();
                store[url.domain][level] = store[url.domain][level].add(JSON.stringify(url));

            }


        } else {
            store[url.domain] = {};
            store[url.domain][level] = Immutable.Set();
            store[url.domain][level] = store[url.domain][level].add(JSON.stringify(url));
        }



        if (check.assigned(count_store[url.domain])) {

            if (check.assigned(count_store[url.domain][level])) {
                count_store[url.domain][level] += 1;
            } else {
                count_store[url.domain][level] = 1;
            }

        } else {
            count_store[url.domain] = {};
            count_store[url.domain][level] = 1;
        }


        //console.log("current_size before  ", current_size );
        ++current_size;
        //console.log("current_size after  ", current_size );
        return true;

    };


    /**
    	Fetches urls from the cache.
    	@public
    	@param {String} domain - Domain required
    	@param {number} num - number of urls to return
    */
    this.fetchURLs = function fetchURLs(domain, num) {
        //console.log(current_size,"current_size ",cache_limit);
        if (!check.assigned(num)) {
            num = 1;
        }

        if (check.assigned(store[domain])) {
            var count = 0;
            var levels = Object.keys(store[domain]);
            levels.sort();
            var output = [];

            _.each(levels, function(level, index) {
                
                var arr = store[domain][level].slice(0, num);
                store[domain][level] = store[domain][level].subtract(arr);
                var tmp = arr.toArray();
                //console.log(count_store[domain], tmp.length);
                count_store[domain][level] -= tmp.length;
                output = output.concat(tmp);
                current_size -= tmp.length;
                if (output.length >= num) {
                    return {}; //break
                }

            });

            var temp = [];

            _.each(output, function(item) {
                temp.push(JSON.parse(item));
            });


            return temp;



        } else {
            return [];
        }



    }
};

module.exports = BucketProxy;