/*
 * This Source Code is subject to the terms of the Mozilla Public License
 * version 2.0 (the "License"). You can obtain a copy of the License at
 * http://mozilla.org/MPL/2.0/.
 */

//
// This file has been generated automatically from Adblock Plus source code
//

(function (_patchFunc0) {
  function Matcher() {
    this.clear();
  }
  Matcher.prototype = {
    filterByKeyword: null,
    keywordByFilter: null,
    clear: function () {
      this.filterByKeyword = {
        __proto__: null
      };
      this.keywordByFilter = {
        __proto__: null
      };
    }
    ,
    add: function (filter) {
      if (filter.text in this.keywordByFilter)
        return ;
      var keyword = this.findKeyword(filter);
      switch (typeof this.filterByKeyword[keyword]) {
        case "undefined": {
          this.filterByKeyword[keyword] = filter.text;
          break;
        }
        case "string": {
          this.filterByKeyword[keyword] = [this.filterByKeyword[keyword], filter.text];
          break;
        }
        default: {
          this.filterByKeyword[keyword].push(filter.text);
          break;
        }
      }
      this.keywordByFilter[filter.text] = keyword;
    }
    ,
    remove: function (filter) {
      if (!(filter.text in this.keywordByFilter))
        return ;
      var keyword = this.keywordByFilter[filter.text];
      var list = this.filterByKeyword[keyword];
      if (typeof list == "string")
        delete this.filterByKeyword[keyword];
       else {
        var index = list.indexOf(filter.text);
        if (index >= 0) {
          list.splice(index, 1);
          if (list.length == 1)
            this.filterByKeyword[keyword] = list[0];
        }
      }
      delete this.keywordByFilter[filter.text];
    }
    ,
    findKeyword: function (filter) {
      var defaultResult = (filter.contentType & RegExpFilter.typeMap.DONOTTRACK ? "donottrack" : "");
      var text = filter.text;
      if (Filter.regexpRegExp.test(text))
        return defaultResult;
      if (Filter.optionsRegExp.test(text))
        text = RegExp.leftContext;
      if (text.substr(0, 2) == "@@")
        text = text.substr(2);
      var candidates = text.toLowerCase().match(/[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/g);
      if (!candidates)
        return defaultResult;
      var hash = this.filterByKeyword;
      var result = defaultResult;
      var resultCount = 16777215;
      var resultLength = 0;
      for (var i = 0, l = candidates.length;
      i < l; i++) {
        var candidate = candidates[i].substr(1);
        var count;
        switch (typeof hash[candidate]) {
          case "undefined": {
            count = 0;
            break;
          }
          case "string": {
            count = 1;
            break;
          }
          default: {
            count = hash[candidate].length;
            break;
          }
        }
        if (count < resultCount || (count == resultCount && candidate.length > resultLength)) {
          result = candidate;
          resultCount = count;
          resultLength = candidate.length;
        }
      }
      return result;
    }
    ,
    hasFilter: function (filter) {
      return (filter.text in this.keywordByFilter);
    }
    ,
    getKeywordForFilter: function (filter) {
      if (filter.text in this.keywordByFilter)
        return this.keywordByFilter[filter.text];
       else
        return null;
    }
    ,
    _checkEntryMatch: function (keyword, location, contentType, docDomain, thirdParty) {
      var list = this.filterByKeyword[keyword];
      if (typeof list == "string") {
        var filter = Filter.knownFilters[list];
        if (!filter) {
          delete this.filterByKeyword[keyword];
          return null;
        }
        return (filter.matches(location, contentType, docDomain, thirdParty) ? filter : null);
      }
       else {
        for (var i = 0;
        i < list.length; i++) {
          var filter = Filter.knownFilters[list[i]];
          if (!filter) {
            if (list.length == 1) {
              delete this.filterByKeyword[keyword];
              return null;
            }
             else {
              list.splice(i--, 1);
              continue;
            }
          }
          if (filter.matches(location, contentType, docDomain, thirdParty))
            return filter;
        }
        return null;
      }
    }
    ,
    matchesAny: function (location, contentType, docDomain, thirdParty) {
      var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
      if (candidates === null)
        candidates = [];
      if (contentType == "DONOTTRACK")
        candidates.unshift("donottrack");
       else
        candidates.push("");
      for (var i = 0, l = candidates.length;
      i < l; i++) {
        var substr = candidates[i];
        if (substr in this.filterByKeyword) {
          var result = this._checkEntryMatch(substr, location, contentType, docDomain, thirdParty);
          if (result)
            return result;
        }
      }
      return null;
    }
    ,
    toCache: function (cache) {
      cache.filterByKeyword = this.filterByKeyword;
    }
    ,
    fromCache: function (cache) {
      this.filterByKeyword = cache.filterByKeyword;
      this.filterByKeyword.__proto__ = null;
      delete this.keywordByFilter;
      this.__defineGetter__("keywordByFilter", function () {
        var result = {
          __proto__: null
        };
        for (var k in this.filterByKeyword) {
          var list = this.filterByKeyword[k];
          if (typeof list == "string")
            result[list] = k;
           else
            for (var i = 0, l = list.length;
            i < l; i++)
              result[list[i]] = k;
        }
        return this.keywordByFilter = result;
      }
      );
      this.__defineSetter__("keywordByFilter", function (value) {
        delete this.keywordByFilter;
        return this.keywordByFilter = value;
      }
      );
    }
    
  };
  function CombinedMatcher() {
    this.blacklist = new Matcher();
    this.whitelist = new Matcher();
    this.keys = {
      __proto__: null
    };
    this.resultCache = {
      __proto__: null
    };
  }
  CombinedMatcher.maxCacheEntries = 1000;
  CombinedMatcher.prototype = {
    blacklist: null,
    whitelist: null,
    keys: null,
    resultCache: null,
    cacheEntries: 0,
    clear: function () {
      this.blacklist.clear();
      this.whitelist.clear();
      this.keys = {
        __proto__: null
      };
      this.resultCache = {
        __proto__: null
      };
      this.cacheEntries = 0;
    }
    ,
    add: function (filter) {
      if (filter instanceof WhitelistFilter) {
        if (filter.siteKeys) {
          for (var i = 0;
          i < filter.siteKeys.length; i++)
            this.keys[filter.siteKeys[i]] = filter.text;
        }
         else
          this.whitelist.add(filter);
      }
       else
        this.blacklist.add(filter);
      if (this.cacheEntries > 0) {
        this.resultCache = {
          __proto__: null
        };
        this.cacheEntries = 0;
      }
    }
    ,
    remove: function (filter) {
      if (filter instanceof WhitelistFilter) {
        if (filter.siteKeys) {
          for (var i = 0;
          i < filter.siteKeys.length; i++)
            delete this.keys[filter.siteKeys[i]];
        }
         else
          this.whitelist.remove(filter);
      }
       else
        this.blacklist.remove(filter);
      if (this.cacheEntries > 0) {
        this.resultCache = {
          __proto__: null
        };
        this.cacheEntries = 0;
      }
    }
    ,
    findKeyword: function (filter) {
      if (filter instanceof WhitelistFilter)
        return this.whitelist.findKeyword(filter);
       else
        return this.blacklist.findKeyword(filter);
    }
    ,
    hasFilter: function (filter) {
      if (filter instanceof WhitelistFilter)
        return this.whitelist.hasFilter(filter);
       else
        return this.blacklist.hasFilter(filter);
    }
    ,
    getKeywordForFilter: function (filter) {
      if (filter instanceof WhitelistFilter)
        return this.whitelist.getKeywordForFilter(filter);
       else
        return this.blacklist.getKeywordForFilter(filter);
    }
    ,
    isSlowFilter: function (filter) {
      var matcher = (filter instanceof WhitelistFilter ? this.whitelist : this.blacklist);
      if (matcher.hasFilter(filter))
        return !matcher.getKeywordForFilter(filter);
       else
        return !matcher.findKeyword(filter);
    }
    ,
    matchesAnyInternal: function (location, contentType, docDomain, thirdParty) {
      var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
      if (candidates === null)
        candidates = [];
      if (contentType == "DONOTTRACK")
        candidates.unshift("donottrack");
       else
        candidates.push("");
      var blacklistHit = null;
      for (var i = 0, l = candidates.length;
      i < l; i++) {
        var substr = candidates[i];
        if (substr in this.whitelist.filterByKeyword) {
          var result = this.whitelist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty);
          if (result)
            return result;
        }
        if (substr in this.blacklist.filterByKeyword && blacklistHit === null)
          blacklistHit = this.blacklist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty);
      }
      return blacklistHit;
    }
    ,
    matchesAny: function (location, contentType, docDomain, thirdParty) {
      var key = location + " " + contentType + " " + docDomain + " " + thirdParty;
      if (key in this.resultCache)
        return this.resultCache[key];
      var result = this.matchesAnyInternal(location, contentType, docDomain, thirdParty);
      if (this.cacheEntries >= CombinedMatcher.maxCacheEntries) {
        this.resultCache = {
          __proto__: null
        };
        this.cacheEntries = 0;
      }
      this.resultCache[key] = result;
      this.cacheEntries++;
      return result;
    }
    ,
    matchesByKey: function (location, key, docDomain) {
      key = key.toUpperCase();
      if (key in this.keys) {
        var filter = Filter.knownFilters[this.keys[key]];
        if (filter && filter.matches(location, "DOCUMENT", docDomain, false))
          return filter;
         else
          return null;
      }
       else
        return null;
    }
    ,
    toCache: function (cache) {
      cache.matcher = {
        whitelist: {
          
        },
        blacklist: {
          
        },
        keys: this.keys
      };
      this.whitelist.toCache(cache.matcher.whitelist);
      this.blacklist.toCache(cache.matcher.blacklist);
    }
    ,
    fromCache: function (cache) {
      this.whitelist.fromCache(cache.matcher.whitelist);
      this.blacklist.fromCache(cache.matcher.blacklist);
      this.keys = cache.matcher.keys;
    }
    
  };
  var defaultMatcher = new CombinedMatcher();
  if (typeof _patchFunc0 != "undefined")
    eval("(" + _patchFunc0.toString() + ")()");
  window.Matcher = Matcher;
  window.CombinedMatcher = CombinedMatcher;
  window.defaultMatcher = defaultMatcher;
}
)(window.MatcherPatch);
