package com.infoteria.asteria.flowlibrary2.mapper.string;

import com.infoteria.asteria.flowengine2.execute.ExecuteContext;
import com.infoteria.asteria.flowlibrary2.mapper.Function;
import com.infoteria.asteria.flowlibrary2.mapper.MapperException;
import com.infoteria.asteria.value.Value;
import com.infoteria.asteria.value.ValueConvertException;

public class CONST extends Function {
	
	private static final String INVALID_METACHARACTER = "1";
	
	private static final String FUNCTION_NAME = "CONST";
	private static final String PROPERTY_DATA = "Data";
	private static final String PROPERTY_ENABLE_METACHARACTER = "EnableMetaCharacter";
	private static final String PROPERTY_DATATYPE = "DataType";
	
	private static final String VALUE_NULL = "(null)";
	
	public String getFunctionName() { return FUNCTION_NAME;}
	
	protected void internalInit() {
		registProperty(PROPERTY_DATA, Value.TYPE_STRING, false);
		registProperty(PROPERTY_ENABLE_METACHARACTER, Value.TYPE_BOOLEAN, false);
		registProperty(PROPERTY_DATATYPE, Value.TYPE_STRING, false);
	}
	
	public boolean checkInputCount() {
		return getInputList().size() == 0;
	}
	
	public void execute(ExecuteContext context, Value[] in, Value out) throws MapperException {
		String type = getPropertyString(PROPERTY_DATATYPE);
		if (VALUE_NULL.equals(type))
			out.setValue((String)null);
		else {
			Value.Type vt = Value.strToType(type);
			if (vt == null)
				vt = Value.TYPE_STRING;
			String s = getPropertyString(PROPERTY_DATA);
			try {
				out.setValue(vt, s);
			} catch (ValueConvertException e) {
				throw new MapperException(e);
			}
		}
	}
	
	protected void postCompile() throws MapperException {
		if (getPropertyBoolean(PROPERTY_ENABLE_METACHARACTER)) {
			Value v = getProperty(PROPERTY_DATA);
			if (v == null)
				return;
			
			v.setValue(replaceMetaCharacter(v.strValue()));
		}
	}
	
	public static String replaceMetaCharacter(String s) throws MapperException {
		int len = s.length();
		int idx = s.indexOf('\\');
		if (idx == -1)
			return s;
		
		int spos = 0;
		StringBuilder buf = new StringBuilder(len);
		while (idx != -1) {
			buf.append(s.substring(spos, idx));
			if (idx+1 >= len)
				throw new MapperException(getMessageStatic(FUNCTION_NAME, INVALID_METACHARACTER, "\\"));
			char c2 = s.charAt(idx+1);
			if (c2 == 'u') {
				if (idx+5 < len) {
					String num = s.substring(idx+2, idx+6);
					try {
						buf.append((char)Integer.parseInt(num, 16));
						spos = idx + 6;
					} catch (NumberFormatException e) {
						throw new MapperException(getMessageStatic(FUNCTION_NAME, INVALID_METACHARACTER, "\\u" + num));
					}
				} else
					throw new MapperException(getMessageStatic(FUNCTION_NAME, INVALID_METACHARACTER, "\\" + c2));
			} else {
				switch (c2) {
					case 'n': buf.append('\n'); break;
					case 't': buf.append('\t'); break;
					case 'r': buf.append('\r'); break;
					case '\\': buf.append('\\'); break;
					default:
						throw new MapperException(getMessageStatic(FUNCTION_NAME, INVALID_METACHARACTER, "\\" + c2));
				}
				spos = idx+2;
			}
			idx = s.indexOf('\\', spos);
		}
		buf.append(s.substring(spos));
		return buf.toString();
	}
}
