/*
 * 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.bc;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 
 *
 *
 * @author MORIGUCHI, Yuichiro 2013/07/14
 */
public class BcRootNamespace implements BcNamespace {

	static final char MAX = (char)0xa000;
	static final char MAX_LOCAL = (char)0xd800;
	static final char MAX_FUNCTION = (char)0x2000;
	static final char MAX_LOOP = (char)0xff00;
	static final char TMP_ARRAY1 = (char)0xff01;
	static final char TMP_ARRAY2 = (char)0xff02;
	static final char SCALE = (char)0xff03;
	static final char IBASE = (char)0xff04;

	private Map<String, Character> allocated;
	private Map<String, Integer> arities;
	private Map<String, Character> locals;
	private Map<String, Character> functions;
	private int varch = 0x4e00;
	private int functionch = 0x00c0;
	private int localch = 0xac00;
	private int loopch = MAX_LOCAL;

	/**
	 * 
	 */
	public BcRootNamespace() {
		allocated = new HashMap<String, Character>();
		arities   = new HashMap<String, Integer>();
		locals    = new HashMap<String, Character>();
		functions = new HashMap<String, Character>();
	}

	/* (non-Javadoc)
	 * @see net.morilib.bc.BcNamespace#getCharacter(java.lang.String)
	 */
	public char getCharacter(String name) {
		if(name.equals("scale")) {
			return SCALE;
		} else if(name.equals("pi") || name.equals("π")) {
			return 'π';
		} else if(locals.containsKey(name)) {
			return locals.get(name);
		} else if(allocated.containsKey(name)) {
			return allocated.get(name);
		} else {
			return allocCharacter(name);
		}
	}

	/* (non-Javadoc)
	 * @see net.morilib.bc.BcNamespace#getFunction(java.lang.String)
	 */
	public char getFunction(String name) {
		if(functions.containsKey(name)) {
			return functions.get(name);
		} else {
			throw new BcSyntaxException();
		}
	}

	/* (non-Javadoc)
	 * @see net.morilib.bc.BcNamespace#allocCharacter(java.lang.String)
	 */
	public char allocCharacter(String name) {
		if(varch < MAX) {
			allocated.put(name, (char)varch);
			return (char)varch++;
		} else {
			throw new BcSyntaxException();
		}
	}

	/* (non-Javadoc)
	 * @see net.morilib.bc.BcNamespace#allocCharacter(java.lang.String)
	 */
	public char allocLocalCharacter(String name) {
		if(localch < MAX_LOCAL) {
			locals.put(name, (char)localch);
			return (char)localch++;
		} else {
			throw new BcSyntaxException();
		}
	}

	/* (non-Javadoc)
	 * @see net.morilib.bc.BcNamespace#clearLocalCharacter()
	 */
	public void clearLocalCharacter() {
		locals.clear();
	}

	/* (non-Javadoc)
	 * @see net.morilib.bc.BcNamespace#defineFunction(java.lang.String, java.util.List)
	 */
	public char defineFunction(String name, List<String> args) {
		arities.put(name, args.size());
		if(functionch < MAX_FUNCTION) {
			functions.put(name, (char)functionch);
			return (char)functionch++;
		} else {
			throw new BcSyntaxException();
		}
	}

	/* (non-Javadoc)
	 * @see net.morilib.bc.BcNamespace#getArity(java.lang.String)
	 */
	public int getArity(String name) {
		if(arities.containsKey(name)) {
			return arities.get(name);
		} else {
			return -1;
		}
	}

	/* (non-Javadoc)
	 * @see net.morilib.bc.BcNamespace#getLocalStart()
	 */
	public int getLocalStart() {
		return MAX;
	}

	/* (non-Javadoc)
	 * @see net.morilib.bc.BcNamespace#popLoop()
	 */
	public void popLoop() {
		loopch--;
	}

	/* (non-Javadoc)
	 * @see net.morilib.bc.BcNamespace#pushLoop()
	 */
	public char pushLoop() {
		return (char)loopch++;
	}

}
