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

import com.infoteria.asteria.flowengine2.execute.ExecuteContext;
import com.infoteria.asteria.flowengine2.resource.ExecuteInfo;
import com.infoteria.asteria.flowlibrary2.mapper.Function;
import com.infoteria.asteria.flowlibrary2.mapper.MapperException;
import com.infoteria.asteria.util.text.SurrogateUtil;
import com.infoteria.asteria.value.Value;
import java.io.UnsupportedEncodingException;

public class LEFT extends Function {
	
	private static final String FUNCTION_NAME   = "LEFT";
	private static final String PROPERTY_COUNT  = "Count";
	private static final String PROPERTY_MODE           = "Mode";
	private static final String PROPERTY_ENCODING       = "Encoding";
	private static final String PROPERTY_PADDING        = "Padding";
	
	public String getFunctionName() { return FUNCTION_NAME;}
	
	protected void internalInit() {
		registProperty(PROPERTY_COUNT, Value.TYPE_INTEGER, false);
		registProperty(PROPERTY_MODE, Value.TYPE_STRING, true);
		registProperty(PROPERTY_ENCODING, Value.TYPE_STRING, true);
		registProperty(PROPERTY_PADDING, Value.TYPE_BOOLEAN, false);
	}
	
	public int getMinInputCount() { return 1;}
	public int getMaxInputCount() { return 2;}
	
	public void execute(ExecuteContext context, Value[] in, Value out) throws MapperException {
		int len = (int)getPropertyInteger(PROPERTY_COUNT, in, 1);
		if (len < 0)
			throw new MapperException(ExecuteInfo.INVALID_PROPERTY_VALUE, PROPERTY_COUNT, Integer.toString(len));
		String str = in[0].strValue();
		boolean bPad = getPropertyBoolean(PROPERTY_PADDING);
		String strChar = " ";
		
		if (len == 0)
			str = "";
		else if ("Binary".equals(getPropertyString(PROPERTY_MODE))) {
			String enc = getPropertyString(PROPERTY_ENCODING);
			try {
				byte[] data = str.getBytes(enc);
				if (data.length > len) {
					byte[] ret = new byte[len];
					System.arraycopy(data, 0, ret, 0, ret.length);
					String str2 = new String(ret, enc);
					while (!str.startsWith(str2) && str2.length() > 0)
						str2 = str2.substring(0, str2.length()-1);
					str = str2;
				} else if (data.length < len && bPad) {
					byte[] ret = new byte[len];
					System.arraycopy(data, 0, ret, 0, data.length);
					
					byte[] pad = strChar.getBytes(enc);
					if (pad.length == 1) {
						for (int i=data.length; i<len; i++)
							ret[i] = pad[0];
					} else {
						int idx = data.length;
						while (idx + pad.length <= len) {
							System.arraycopy(pad, 0, ret, idx, pad.length);
							idx += pad.length;
						}
					}
					str = new String(ret, enc);
				}
			} catch (UnsupportedEncodingException e) {
				throw new MapperException(e);
			}
		} else if (Setting.SURROGATE_SUPPORT) {
			str = SurrogateUtil.left(str, len, bPad);
		} else {
			if (str.length() > len)
				str = str.substring(0, len);
			else if (str.length() < len && bPad) {
				StringBuilder buf = new StringBuilder(str);
				int clen = strChar.length();
				while (buf.length() + clen <= len)
					buf.append(strChar);
				str = buf.toString();
			}
		}
		out.setValue(str);
	}
	
}
