/*
 * Copyright 2013-2014 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.nina;

import java.io.IOException;
import java.io.Reader;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import net.morilib.automata.lr.ContextFreeGrammar;
import net.morilib.automata.lr.ContextFreeRule;
import net.morilib.automata.lr.LALR1Table;
import net.morilib.automata.lr.LR1Table;
import net.morilib.automata.lr.LRConflict;
import net.morilib.deculture.misc.ConstantNonterminal;
import net.morilib.deculture.parser.DecultureAction;
import net.morilib.deculture.parser.DecultureDefinition;
import net.morilib.deculture.parser.DecultureReader;

/**
 * 
 * 
 * @author MORIGUCHI, Yuichiro 2014/03/23
 */
public class LRObject {

	//
	private DecultureDefinition def;
	private DecultureAction act;
	private ContextFreeGrammar grammar;
	private LR1Table table;
	private Map<ContextFreeRule, Object> actionMap =
			new HashMap<ContextFreeRule, Object>();
	private Map<Object, Integer> nonterminalMap =
			new HashMap<Object, Integer>();
	private Map<String, String> subautomata =
			new HashMap<String, String>();
	private int nonterminalNumber = 0;

	/**
	 * 
	 * @return
	 */
	public DecultureDefinition getDefinition() {
		return def;
	}

	/**
	 * 
	 * @return
	 */
	public ContextFreeGrammar getGrammar() {
		return grammar;
	}

	/**
	 * 
	 * @return
	 */
	public LR1Table getTable() {
		return table;
	}

	/**
	 * 
	 * @return
	 */
	public Collection<LRConflict> getConflicts() {
		return table.getConflicts();
	}

	/**
	 * 
	 * @param rule
	 * @return
	 */
	public Object getAction(ContextFreeRule rule) {
		return actionMap.get(rule);
	}

	/**
	 * 
	 * @param rule
	 * @param action
	 */
	public void setAction(ContextFreeRule rule, Object action) {
		actionMap.put(rule, action);
	}

	/**
	 * 
	 * @param rule
	 */
	public void removeAction(ContextFreeRule rule) {
		actionMap.remove(rule);
	}

	/**
	 * 
	 * @return
	 */
	public int howManyShiftReduceConflicts() {
		int r = 0;

		for(LRConflict t : table.getConflicts()) {
			r += t.isShiftReduce() ? 1 : 0;
		}
		return r;
	}

	/**
	 * 
	 * @return
	 */
	public int howManyReduceReduceConflicts() {
		int r = 0;

		for(LRConflict t : table.getConflicts()) {
			r += t.isReduceReduce() ? 1 : 0;
		}
		return r;
	}

	/**
	 * 
	 * @param o
	 * @return
	 */
	public int getNonterminalNumber(Object o) {
		if(nonterminalMap.containsKey(o)) {
			return nonterminalMap.get(o);
		} else {
			nonterminalMap.put(o, nonterminalNumber);
			return nonterminalNumber++;
		}
	}

	/**
	 * 
	 * @return
	 */
	public int getStartNumber() {
		return table.getInitialStateID();
	}

	/**
	 * 
	 * @return
	 */
	public Map<ContextFreeRule, Object> getActionMap() {
		return Collections.unmodifiableMap(actionMap);
	}

	/**
	 * 
	 * @return
	 */
	public Map<String, String> getSubautomata() {
		return Collections.unmodifiableMap(subautomata);
	}

	private void _put(ContextFreeGrammar g) {
//		System.out.println(act.getActions());
//		System.out.println(g.getStartSymbol());
//		for(ContextFreeRule r : g.getRules()) {
//			System.out.println(r);
//		}
	}

	/**
	 * 
	 * @param in
	 * @return
	 * @throws IOException
	 */
	public static LRObject parse(Reader rd) throws IOException {
		LRObject p = new LRObject();

		p.def = new DecultureDefinition();
		p.def.parse(new DecultureReader(rd));
		p.act = new DecultureAction(p.def);
		p.act.parse(new DecultureReader(rd));
		p.actionMap = p.act.getActions();
		p.subautomata = p.act.getSubautomata();

		p.grammar = ContextFreeGrammar.newInstance(
				p.act.getActions().keySet(),
				new ConstantNonterminal(p.def.getStartSymbolName()));
		p._put(p.getGrammar());

		p.table = LALR1Table.create(p.grammar, p.def.getPriority(),
				p.def.getAssociativity());
		return p;
	}

}
