/**
 * WordGetter.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

define("tinymce.wordcount.text.WordGetter", [
	"tinymce.wordcount.text.UnicodeData",
	"tinymce.wordcount.text.StringMapper",
	"tinymce.wordcount.text.WordBoundary"
], function(UnicodeData, StringMapper, WordBoundary) {
	var EMPTY_STRING = UnicodeData.EMPTY_STRING;
	var WHITESPACE = UnicodeData.WHITESPACE;
	var PUNCTUATION = UnicodeData.PUNCTUATION;

	var isProtocol = function (word) {
		return word === 'http' || word === 'https';
	};

	var findWordEnd = function (string, index) {
		var i;
		for (i = index; i < string.length; ++i) {
			var chr = string.charAt(i);

			if (WHITESPACE.test(chr)) {
				break;
			}
		}
		return i;
	};

	var extractUrl = function (word, string, index) {
		var endIndex = findWordEnd(string, index + 1);
		var peakedWord = string.substring(index + 1, endIndex);
		if (peakedWord.substr(0, 3) === '://') {
			return {
				word: word + peakedWord,
				index: endIndex
			};
		}

		return {
			word: word,
			index: index
		};
	};

	var getWords = function (string, options) {
		var i = 0;
		var map = StringMapper.classify(string);
		var len = map.length;
		var word = [];
		var words = [];
		var chr;
		var includePunctuation;
		var includeWhitespace;

		if (!options) {
			options = {};
		}

		if (options.ignoreCase) {
			string = string.toLowerCase();
		}

		includePunctuation = options.includePunctuation;
		includeWhitespace = options.includeWhitespace;

		// Loop through each character in the classification map and determine
		// whether it precedes a word boundary, building an array of distinct
		// words as we go.
		for (; i < len; ++i) {
			chr = string.charAt(i);

			// Append this character to the current word.
			word.push(chr);

			// If there's a word boundary between the current character and the
			// next character, append the current word to the words array and
			// start building a new word.
			if (WordBoundary.isWordBoundary(map, i)) {
				word = word.join(EMPTY_STRING);

				if (word &&
								(includeWhitespace || !WHITESPACE.test(word)) &&
								(includePunctuation || !PUNCTUATION.test(word))) {
					if (isProtocol(word)) {
						var obj = extractUrl(word, string, i);
						words.push(obj.word);
						i = obj.index;
					} else {
						words.push(word);
					}
				}

				word = [];
			}
		}

		return words;
	};

	return {
		getWords: getWords
	};
});