/*\
title: $:/plugins/tiddlywiki/dynannotate/selection-tracker.js
type: application/javascript
module-type: startup

Dyannotate background daemon to track the selection

\*/
(function(){

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

// Export name and synchronous status
exports.name = "dyannotate-startup";
exports.platforms = ["browser"];
exports.after = ["render"];
exports.synchronous = true;

var TextMap = require("$:/plugins/tiddlywiki/dynannotate/textmap.js").TextMap;

exports.startup = function() {
	$tw.dynannotate = {
		selectionTracker: new SelectionTracker($tw.wiki,{
			allowBlankSelectionPopup: true
		})
	};
};

function SelectionTracker(wiki,options) {
	options = options || {};
	var self = this;
	this.wiki = wiki;
	this.allowBlankSelectionPopup = options.allowBlankSelectionPopup;
	this.selectionPopupTitle = null;
	document.addEventListener("selectionchange",function(event) {
		var selection = document.getSelection();
		if(selection && (selection.type === "Range" || (self.allowBlankSelectionPopup && !self.selectionPopupTitle))) {
			// Look for the selection containers for each of the two ends of the selection
			var anchorContainer = self.findSelectionContainer(selection.anchorNode),
				focusContainer = self.findSelectionContainer(selection.focusNode);
			// If either end of the selection then we ignore it
			if(!!anchorContainer || !!focusContainer) {
				var selectionRange = selection.getRangeAt(0);
				// Check for the selection spilling outside the starting container
				if((anchorContainer !== focusContainer) || (selectionRange.startContainer.nodeType !== Node.TEXT_NODE && selectionRange.endContainer.nodeType !== Node.TEXT_NODE)) {
					if(self.selectionPopupTitle) {
						self.wiki.deleteTiddler(self.selectionPopupTitle);
						self.selectionPopupTitle = null;
					}
				} else {
					self.selectionSaveTitle = anchorContainer.getAttribute("data-annotation-selection-save");
					self.selectionPrefixSaveTitle = anchorContainer.getAttribute("data-annotation-selection-prefix-save");
					self.selectionSuffixSaveTitle = anchorContainer.getAttribute("data-annotation-selection-suffix-save");
					self.selectionPopupTitle = anchorContainer.getAttribute("data-annotation-selection-popup");
					// The selection is a range so we trigger the popup
					if(self.selectionPopupTitle) {
						var selectionRectangle = selectionRange.getBoundingClientRect(),
							trackingRectangle = anchorContainer.getBoundingClientRect();
						$tw.popup.triggerPopup({
							domNode: null,
							domNodeRect: {
								left: selectionRectangle.left - trackingRectangle.left,
								top: selectionRectangle.top - trackingRectangle.top,
								width: selectionRectangle.width,
								height: selectionRectangle.height
							},
							force: true,
							floating: true,
							title: self.selectionPopupTitle,
							wiki: self.wiki
						});						
					}
					// Write the selection text to the specified tiddler
					if(self.selectionSaveTitle) {
						// Note that selection.toString() normalizes whitespace but selection.getRangeAt(0).toString() does not
						var text = selectionRange.toString();
						self.wiki.addTiddler(new $tw.Tiddler({title: self.selectionSaveTitle, text: text}));
						// Build a textmap of the container so that we can find the prefix and suffix
						var textMap = new TextMap(anchorContainer);
						// Find the selection start in the text map and hence extract the prefix and suffix
						var context = textMap.extractContext(selectionRange.startContainer,selectionRange.startOffset,text);
						// Save the prefix and suffix
						if(context) {
							if(self.selectionPrefixSaveTitle) {
								self.wiki.addTiddler(new $tw.Tiddler({title: self.selectionPrefixSaveTitle, text: context.prefix}));
							}
							if(self.selectionSuffixSaveTitle) {
								self.wiki.addTiddler(new $tw.Tiddler({title: self.selectionSuffixSaveTitle, text: context.suffix}));
							}
						}
					}
				}
			}
		} else {
			// If the selection is a caret we clear any active popup
			if(self.selectionPopupTitle) {
				self.wiki.deleteTiddler(self.selectionPopupTitle);
				self.selectionPopupTitle = null;
			}
		}
	});
}

SelectionTracker.prototype.findSelectionContainer = function findSelectionContainer(domNode) {
	if(domNode && domNode.nodeType === Node.ELEMENT_NODE && domNode.classList.contains("tc-dynannotation-selection-container")) {
		return domNode;
	}
	if(domNode && domNode.parentNode) {
		return findSelectionContainer(domNode.parentNode);
	}
	return null;
};

})();
