/*
 * This file is part of Nuts Framework.
 * Copyright(C) 2009-2012 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 * 
 * Nuts Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */
package nuts.core.lang;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import nuts.core.beans.PropertyUtils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * Utility class for Text.
 */
public abstract class TextUtils {
	private static Log log = LogFactory.getLog(TextUtils.class);

	/**
	 * transform "${a}-${b}" with Map { "a": 1, "b": 2 } -> "1-2".
	 * 
	 * @param expression expression 
	 * @param wrapper object wrapper
	 * @return translated string
	 */
	public static String transform(String expression, Object wrapper) {
		return transform(expression, wrapper, '$');
	}
	

	/**
	 * transform "${a}-${b}" with Map { "a": 1, "b": 2 } -> "1-2".
	 * 
	 * @param expression expression 
	 * @param wrapper object wrapper
	 * @param prefix prefix char 
	 * @return translated string
	 */
	public static String transform(String expression, Object wrapper, char prefix) {
		return transform(expression, wrapper, prefix, '{', '}');
	}
	/**
	 * transform "${a}-${b}" with Map { "a": 1, "b": 2 } -> "1-2".
	 * 
	 * @param prefix prefix char $ or %
	 * @param open open char ( or {
	 * @param close close char ) or } 
	 * @param expression expression string
	 * @param wrapper object wrapper
	 * @return translated string
	 */
	public static String transform(String expression, Object wrapper, char prefix, char open, char close) {
		if (StringUtils.isEmpty(expression)) {
			return expression;
		}
		
		StringBuilder sb = new StringBuilder();
		
		for (int i = 0; i < expression.length(); i++) {
			char c = expression.charAt(i);
			if (c == prefix && i < expression.length() - 1 && expression.charAt(i + 1) == open) {
				String n = null;
				int j = i + 2;
				for (; j < expression.length(); j++) {
					if (expression.charAt(j) == close) {
						n = expression.substring(i + 2, j);
						break;
					}
				}
				if (n == null) {
					throw new IllegalArgumentException("Illegal statement (" + i + "): unexpected end of tag reached.");
				}
				else if (n.length() < 1) {
					throw new IllegalArgumentException("Illegal statement (" + i + "): the paramenter can not be empty.");
				}
				
				Object v = null;
				if (wrapper instanceof Map) {
					v = ((Map<?, ?>)wrapper).get(n);
				}
				else {
					try {
						v = PropertyUtils.getProperty(wrapper, n);
					}
					catch (Exception e) {
						log.warn("Failed to get property: " + wrapper.getClass() + " - " + n);
					}
				}
				if (v == null) {
					sb.append(prefix);
					sb.append(open);
					sb.append(n);
					sb.append(close);
				}
				else {
					sb.append(v);
				}
				i = j;
			}
			else {
				sb.append(c);
			}
		}
		
		return sb.toString();
	}

	/**
	 * 
	 * @param text text
	 * @return keyword set
	 */
	public static Set<String> parseKeywords(String text) {
		return parseKeywords(text, 1, 20);
	}
	
	/**
	 * 
	 * @param text text
	 * @param minLength min length of keyword
	 * @param maxLength max length of keyword 
	 * @return keyword set
	 */
	public static Set<String> parseKeywords(String text, int minLength, int maxLength) {
		Set<String> kws = new HashSet<String>();

		if (StringUtils.isBlank(text)) {
			return kws;
		}

		int start = 0;
		int i = 0;
		int len = text.length();
		for (; i < len; i++) {
			char ch = text.charAt(i);
			if (!Character.isLetterOrDigit(ch)) {
				int cl = i - start;
				if (cl >= minLength && i <= maxLength) {
					kws.add(text.substring(start, i));
				}
				start = i + 1;
			}
		}
		int cl = i - start;
		if (cl >= minLength && i <= maxLength) {
			kws.add(text.substring(start, i));
		}

		return kws;
	}
}
