/*\
title: $:/core/modules/indexers/tag-indexer.js
type: application/javascript
module-type: indexer

Indexes the tiddlers with each tag

\*/
(function(){

/*jslint node: true, browser: true */
/*global modules: false */
"use strict";

function TagIndexer(wiki) {
	this.wiki = wiki;
}

TagIndexer.prototype.init = function() {
	this.subIndexers = [
		new TagSubIndexer(this,"each"),
		new TagSubIndexer(this,"eachShadow"),
		new TagSubIndexer(this,"eachTiddlerPlusShadows"),
		new TagSubIndexer(this,"eachShadowPlusTiddlers")
	];
	$tw.utils.each(this.subIndexers,function(subIndexer) {
		subIndexer.addIndexMethod();
	});
};

TagIndexer.prototype.rebuild = function() {
	$tw.utils.each(this.subIndexers,function(subIndexer) {
		subIndexer.rebuild();
	});
};

TagIndexer.prototype.update = function(updateDescriptor) {
	$tw.utils.each(this.subIndexers,function(subIndexer) {
		subIndexer.update(updateDescriptor);
	});
};

function TagSubIndexer(indexer,iteratorMethod) {
	this.indexer = indexer;
	this.iteratorMethod = iteratorMethod;
	this.index = null; // Hashmap of tag title to {isSorted: bool, titles: [array]} or null if not yet initialised
}

TagSubIndexer.prototype.addIndexMethod = function() {
	var self = this;
	this.indexer.wiki[this.iteratorMethod].byTag = function(tag) {
		return self.lookup(tag).slice(0);
	};
};

TagSubIndexer.prototype.rebuild = function() {
	var self = this;
	// Hashmap by tag of array of {isSorted:, titles:[]}
	this.index = Object.create(null);
	// Add all the tags
	this.indexer.wiki[this.iteratorMethod](function(tiddler,title) {
		$tw.utils.each(tiddler.fields.tags,function(tag) {
			if(!self.index[tag]) {
				self.index[tag] = {isSorted: false, titles: [title]};
			} else {
				self.index[tag].titles.push(title);
			}
		});
	});
};

TagSubIndexer.prototype.update = function(updateDescriptor) {
	this.index = null;
};

TagSubIndexer.prototype.lookup = function(tag) {
	// Update the index if it has yet to be built
	if(this.index === null) {
		this.rebuild();
	}
	var indexRecord = this.index[tag];
	if(indexRecord) {
		if(!indexRecord.isSorted) {
			if(this.indexer.wiki.sortByList) {
				indexRecord.titles = this.indexer.wiki.sortByList(indexRecord.titles,tag);
			}
			indexRecord.isSorted = true;
		}
		return indexRecord.titles;
	} else {
		return [];
	}
};


exports.TagIndexer = TagIndexer;

})();
