/*
 * Copyright 2013 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.awk.namespace;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import net.morilib.awk.value.AwkInteger;
import net.morilib.awk.value.AwkString;
import net.morilib.awk.value.AwkUndefined;
import net.morilib.awk.value.AwkValue;

public class AwkRootNamespace extends AwkSimpleNamespace {

	private String line;
	private List<String> fields;

	/**
	 * 
	 */
	public AwkRootNamespace() {
		super();
	}

	@Override
	public AwkValue find(String s) {
		if(s.equals("NF")) {
			return AwkInteger.valueOf(fields.size());
		} else {
			return super.find(s);
		}
	}

	@Override
	public void assign(String s, AwkValue v) {
		if(!s.equals("NF")) {
			super.assign(s, v);
		}
	}

	public AwkValue referField(int n) {
		if(n < 0) {
			return AwkUndefined.UNDEF;
		} else if(n == 0) {
			return AwkString.valueOf(line);
		} else if(n <= fields.size()) {
			return AwkString.valueOf(fields.get(n - 1));
		} else {
			return AwkUndefined.UNDEF;
		}
	}

	private void _joinField() {
		StringBuffer b = new StringBuffer();
		String ofs = getOFS(), d = "";

		for(String s : fields) {
			b.append(d).append(s);
			d = ofs;
		}
		line = b.toString();
	}

	public void setField(int n, String v) {
		if(n < 0) {
			// do nothing
		} else if(n == 0) {
			setField(v);
		} else if(n <= fields.size()) {
			fields.set(n - 1, v);
			_joinField();
		} else {
			for(int i = sizeOfField(); i < n - 1; i++) {
				fields.add("");
			}
			fields.add(v);
			_joinField();
		}
	}

	public int sizeOfField() {
		return fields.size();
	}

	void setField(String s, String fs, boolean seq) {
		StringBuffer b = null;
		boolean ws = seq;
		int c;

		line = s;
		fields = new ArrayList<String>();
		for(int i = 0; i < s.length(); i += c > 0xffff ? 2 : 1) {
			c = s.codePointAt(i);
			if(ws && fs.indexOf(c) < 0) {
				b = new StringBuffer().appendCodePoint(c);
				ws = false;
			} else if(!ws && fs.indexOf(c) >= 0) {
				fields.add(b == null ? "" : b.toString());
				b = null;
				ws = seq;
			} else if(!ws) {
				if(b == null)  b = new StringBuffer();
				b.appendCodePoint(c);
			}
		}
		if(b != null)  fields.add(b.toString());
	}

	void setFieldRegex(String s, String re) {
		fields = Arrays.asList(s.split(re));

		if(fields.size() > 0 && fields.get(0).equals("")) {
			fields = new ArrayList<String>(fields);
			fields.remove(0);
		}

		if(fields.size() > 0 &&
				fields.get(fields.size() - 1).equals("")) {
			fields = new ArrayList<String>(fields);
			fields.remove(fields.size() - 1);
		}
	}

	public void setField(String s) {
		String rs = getFS();

		if(rs.equals("")) {
			fields = new ArrayList<String>();
			fields.add(s);
		} else if(rs.equals(" ")) {
			setField(s, " \t", true);
		} else if(rs.length() == 1) {
			setField(s, rs, false);
		} else {
			setFieldRegex(s, rs);
		}
	}

	public String getFS() {
		return find("FS").toString();
	}

	public String getRS() {
		return find("RS").toString();
	}

	public String getOFS() {
		return find("OFS").toString();
	}

	public String getORS() {
		return find("ORS").toString();
	}

	public AwkNamespace getRoot() {
		return this;
	}

	public boolean isRoot() {
		return true;
	}

}
