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

import com.infoteria.asteria.flowengine2.compile.AbstractCompiler;
import com.infoteria.asteria.flowengine2.execute.ExecuteContext;
import com.infoteria.asteria.flowengine2.resource.ExecuteInfo;
import com.infoteria.asteria.flowlibrary2.mapper.MultiOutputFunction;
import com.infoteria.asteria.flowlibrary2.mapper.MapperException;
import com.infoteria.asteria.value.Value;
import java.util.ArrayList;

public class Split extends MultiOutputFunction {
	
	private static final String FUNCTION_NAME = "Split";
	private static final String PROPERTY_SEPARATOR = "Separator";
	private static final String PROPERTY_SEARCH_DIR = "SearchDir";
	private static final String PROPERTY_SEP_MODE = "SeparatorMode";
	private static final String PROPERTY_COUNT = "Count";
	
	private static final String VALUE_LEFT  = "Left";
	private static final String VALUE_RIGHT = "Right";
	private static final String VALUE_NONE  = "None";
	
	public String getFunctionName() { return FUNCTION_NAME;}
	
	public Split() {
		super(true);
	}
	
	protected void internalInit() {
		registProperty(PROPERTY_SEPARATOR, Value.TYPE_STRING, false);
		registProperty(PROPERTY_SEARCH_DIR, Value.TYPE_STRING, true);
		registProperty(PROPERTY_SEP_MODE, Value.TYPE_STRING, true);
		registProperty(PROPERTY_COUNT, Value.TYPE_INTEGER, true, new Value(2));
	}
	
	protected void postCompile(AbstractCompiler compiler) {
		int count = (int)getPropertyInteger(PROPERTY_COUNT) - 1;
		if (count > 0)
			setSubValueCount(count);
	}
	
	public int getMinInputCount() { return 1;}
	public int getMaxInputCount() { return 2;}
	
	public void execute(ExecuteContext context, Value[] in, Value out) throws MapperException {
		String s = in[0].toString();
		String searchStr = CONST.replaceMetaCharacter(getPropertyString(PROPERTY_SEPARATOR, in, 1));
		if (searchStr == null || searchStr.length() == 0)
			throw new MapperException(ExecuteInfo.INVALID_PROPERTY_VALUE, PROPERTY_SEPARATOR, searchStr);
		String searchDirStr = getPropertyString(PROPERTY_SEARCH_DIR);
		int searchDir = 0;
		if (searchDirStr.equals(VALUE_RIGHT))
			searchDir = 1;
		
		String sepModeStr = getPropertyString(PROPERTY_SEP_MODE);
		int sepMode = 0;
		if (VALUE_LEFT.equals(sepModeStr))
			sepMode = 1;
		else if (VALUE_RIGHT.equals(sepModeStr))
			sepMode = 2;
		
		int count = (int)getPropertyInteger(PROPERTY_COUNT);
		String[] ret = split(s, searchStr, searchDir, sepMode, count);
		out.setValue(ret[0]);
		int idx = 1;
		for (int i=0; i<getSubValueCount(); i++)
			getSubValue(i).setValue(ret[i+1]);
	}
	
	private String[] split(String s, String sep, int dir, int sepMode, int count) {
		String[] ret = new String[count];
		int idx = 0;
		if (dir == 0) {
			int spos = 0;
			int n = s.indexOf(sep, 0);
			while(n >= 0 && idx < count-1) {
				String s1 = null;
				String s2 = null;
				switch (sepMode) {
					case 0://None
						s1 = s.substring(0, n);
						s2 = s.substring(n + sep.length());
						break;
					case 1://Left
						n += sep.length();
						s1 = s.substring(0, n);
						s2 = s.substring(n);
						break;
					case 2://Right
						s1 = s.substring(0, n);
						s2 = s.substring(n);
						spos = sep.length();
						break;
				}
				ret[idx++] = s1;
				s = s2;
				if (idx == count-1)
					break;
				n = s.indexOf(sep, spos);
			}
			ret[idx++] = s;
		} else {
			ArrayList<String> list = new ArrayList(count);
			int epos = s.length();
			int n = s.lastIndexOf(sep, epos);
			while(n >= 0 && list.size() < count-1) {
				String s1 = null;
				String s2 = null;
				switch (sepMode) {
					case 0:
						epos = n;
						s1 = s.substring(0, n);
						s2 = s.substring(n + sep.length());
						break;
					case 1:
						epos = n-1;
						n += sep.length();
						s1 = s.substring(0, n);
						s2 = s.substring(n);
						break;
					case 2:
						epos = n;
						s1 = s.substring(0, n);
						s2 = s.substring(n);
						break;
				}
				list.add(s2);
				s = s1;
				if (list.size() == count-1)
					break;
				n = s.lastIndexOf(sep, epos);
			}
			list.add(s);
			for (int i=list.size()-1; i>=0; i--)
				ret[idx++] = list.get(i);
		}
		while (idx < count)
			ret[idx++] = "";
		return ret;
	}
	
}
