/**
 * Copyright 2016 the WHATAP project authors. All rights reserved.
 * Use of this source code is governed by a license that
 * can be found in the LICENSE file.
 */

var conf        = require('../conf/configure'),
    PathTree    = require('../util/pathtree'),
    IntKeyLinkedMap = require('../util/intkey-linkedmap'),
    IntSet = require('../util/intset'),
    StringSet = require('../util/stringset'),
    HashUtil        = require('../util/hashutil'),
    last_conf_value = (conf.trace_normalize_urls || ''),
    trace_auto_normalize_enabled = conf.trace_auto_normalize_enabled;

var last_build = 0;
var pathMap = {
    pathParamUrlSet : new StringSet().setMax(500),
    noPathParamUrlHashSet : new IntSet().setMax(1000)
};

function ServiceURLPatternDetector() {
    this.restUrlTable= new PathTree();
    this.noNeedSet= new IntSet().setMax(2000);
    this.parsedSet = new IntKeyLinkedMap().setMax(2000);
}
ServiceURLPatternDetector.prototype.start = function (stime) {

};
ServiceURLPatternDetector.prototype.build = function (force) {
    try {
        var self = this;
        var now = Date.now();
        if(force === false && now < last_build + 10000) {
            return;
        }
        last_build = now;

        var pathTreeTmp = new PathTree();
        var noNeedTmp = new IntSet().setMax(2000);

        if(conf.trace_auto_normalize_enabled) {
            pathMap.pathParamUrlSet.forEach(function (val) {
                self.addPath(pathTreeTmp, val);
            });
            pathMap.noPathParamUrlHashSet.forEach(function (val) {
                noNeedTmp.add(val);
            });
        }

        var urls = conf.trace_normalize_urls.split(',').filter(function (el) {
            return el.length != 0;
        });
        if(urls != null) {
            for (var i = 0; i<urls.length; i++) {
                var u = urls[i];
                if (u && u.indexOf(':') >= 0) {
                    self.addPath(pathTreeTmp, u);
                } else {
                    noNeedTmp.add(HashUtil.hashFromString(u));
                }
            }
        }
        self.restUrlTable = pathTreeTmp;
        self.noNeedSet = noNeedTmp;
        self.parsedSet.clear();
    } catch (e) {
    }
};
ServiceURLPatternDetector.prototype.addPath = function (pathTree, path) {   
    if(path == null) { return; }
    path = path.trim();
    if(path.length < 3) {
        return;
    }

    var nodes = path.split('/').filter(function (el) {
        return el.length != 0;
    });

    if(nodes.length === 0) {
        return;
    }
    for(var i=0; i<nodes.length; i++) {
        if(nodes[i].startsWith(":")) {
            nodes[i] = "*";
        }
    }
    if(nodes.length === 1 && nodes[0] === '*') {
        return;
    }
    pathTree.insert(nodes, path);
};
ServiceURLPatternDetector.prototype.normalize = function (url) {
    if(conf.trace_normalize_enabled === false || this.restUrlTable.size()==0){
        return url;
    }
    var hash = HashUtil.hashFromString(url);
    if(this.noNeedSet.hasKey(hash)) {
        return url;
    }

    var newUrl = this.parsedSet.get(hash);
    if(newUrl != null) {
        return newUrl;
    }

    newUrl = this.restUrlTable.find(url);
    if(newUrl == null) {
        this.noNeedSet.add(hash);
        return url;
    }
    this.parsedSet.put(hash, newUrl);
    return newUrl;
};

exports.Detector = new ServiceURLPatternDetector();
exports.PathMap = pathMap;