/*\
title: $:/core/modules/parsers/wikiparser/rules/image.js
type: application/javascript
module-type: wikirule

Wiki text inline rule for embedding images. For example:

```
[img[https://tiddlywiki.com/fractalveg.jpg]]
[img width=23 height=24 [https://tiddlywiki.com/fractalveg.jpg]]
[img width={{!!width}} height={{!!height}} [https://tiddlywiki.com/fractalveg.jpg]]
[img[Description of image|https://tiddlywiki.com/fractalveg.jpg]]
[img[TiddlerTitle]]
[img[Description of image|TiddlerTitle]]
```

Generates the `<$image>` widget.

\*/
(function(){

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

exports.name = "image";
exports.types = {inline: true};

exports.init = function(parser) {
	this.parser = parser;
};

exports.findNextMatch = function(startPos) {
	// Find the next tag
	this.nextImage = this.findNextImage(this.parser.source,startPos);
	return this.nextImage ? this.nextImage.start : undefined;
};

exports.parse = function() {
	// Move past the match
	this.parser.pos = this.nextImage.end;
	var node = {
		type: "image",
		attributes: this.nextImage.attributes
	};
	return [node];
};

/*
Find the next image from the current position
*/
exports.findNextImage = function(source,pos) {
	// A regexp for finding candidate HTML tags
	var reLookahead = /(\[img)/g;
	// Find the next candidate
	reLookahead.lastIndex = pos;
	var match = reLookahead.exec(source);
	while(match) {
		// Try to parse the candidate as a tag
		var tag = this.parseImage(source,match.index);
		// Return success
		if(tag) {
			return tag;
		}
		// Look for the next match
		reLookahead.lastIndex = match.index + 1;
		match = reLookahead.exec(source);
	}
	// Failed
	return null;
};

/*
Look for an image at the specified position. Returns null if not found, otherwise returns {type: "image", attributes: [], isSelfClosing:, start:, end:,}
*/
exports.parseImage = function(source,pos) {
	var token,
		node = {
			type: "image",
			start: pos,
			attributes: {}
		};
	// Skip whitespace
	pos = $tw.utils.skipWhiteSpace(source,pos);
	// Look for the `[img`
	token = $tw.utils.parseTokenString(source,pos,"[img");
	if(!token) {
		return null;
	}
	pos = token.end;
	// Skip whitespace
	pos = $tw.utils.skipWhiteSpace(source,pos);
	// Process attributes
	if(source.charAt(pos) !== "[") {
		var attribute = $tw.utils.parseAttribute(source,pos);
		while(attribute) {
			node.attributes[attribute.name] = attribute;
			pos = attribute.end;
			pos = $tw.utils.skipWhiteSpace(source,pos);
			if(source.charAt(pos) !== "[") {
				// Get the next attribute
				attribute = $tw.utils.parseAttribute(source,pos);
			} else {
				attribute = null;
			}
		}
	}
	// Skip whitespace
	pos = $tw.utils.skipWhiteSpace(source,pos);
	// Look for the `[` after the attributes
	token = $tw.utils.parseTokenString(source,pos,"[");
	if(!token) {
		return null;
	}
	pos = token.end;
	// Skip whitespace
	pos = $tw.utils.skipWhiteSpace(source,pos);
	// Get the source up to the terminating `]]`
	token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/g);
	if(!token) {
		return null;
	}
	pos = token.end;
	if(token.match[1]) {
		node.attributes.tooltip = {type: "string", value: token.match[1].trim()};
	}
	node.attributes.source = {type: "string", value: (token.match[2] || "").trim()};
	// Update the end position
	node.end = pos;
	return node;
};

})();
