package parsenodes;

import java.util.ArrayList;
import java.util.List;
import parse.Function;
import parse.NodeInformation;
import parse.ParserException;
import parse.StringParser;
import parserInformation.ParserInformation;

public class NodeMakeUserInstruction extends NodeStructure{
    
    public static final String DEFAULT_RESOURCE_PACKAGE = "resources/";
    public static final String ERRORS_RESOURCE_NAME = "Errors";
    public static final String WRONG_SYNTAX = "IncorrectSyntax";
	
	private List<String> functionParameters;
	private String functionBody;
	private String functionTitle;
	
	private Function userFunction;
	
	private boolean evaluable;

	public NodeMakeUserInstruction(NodeInformation nodeInformation, ParserInformation parserInformation)
			throws Exception {
		super(nodeInformation, parserInformation);
	}
	
	private List<String> getFunctionParameters() throws Exception{
		String nextWord = myStringParser.getNextWord();
		if(!nextWord.matches(mySyntaxProperties.getProperty(LIST_START))) throw new ParserException(myResources.getString(WRONG_SYNTAX));
		nextWord = myStringParser.getNextWord();
		List<String> parameters = new ArrayList<String>();
		while(!nextWord.matches(mySyntaxProperties.getProperty(LIST_END))){
			if(!nextWord.matches(mySyntaxProperties.getProperty(VARIABLE))) throw new ParserException(myResources.getString(WRONG_SYNTAX));
			parameters.add(nextWord);
			nextWord = myStringParser.getNextWord();
		}
		return parameters;
	}
	
	/**
	 * Returns the function body
	 * The format is "wordA wordB wordC ", with one space appending each word
	 * This is useful for the Function.java class when it has to replace words
	 * with the correct values
	 * @return
	 * @throws Exception
	 */
	
	private String getFunctionBody() throws Exception{
		String nextWord = myStringParser.getNextWord();
		if(!nextWord.matches(mySyntaxProperties.getProperty(LIST_START))) throw new ParserException(myResources.getString(WRONG_SYNTAX));
		StringBuilder body = new StringBuilder();
		nextWord = myStringParser.getNextWord();
		int numBrackets = 1;
		while(numBrackets > 0){
			if(nextWord.matches(mySyntaxProperties.getProperty(LIST_START))) numBrackets++;
			if(nextWord.matches(mySyntaxProperties.getProperty(LIST_END))) numBrackets--;
			if(numBrackets == 0) break;
			body.append(nextWord);
			body.append(" ");
			nextWord = myStringParser.getNextWord();
		}
		return body.toString();
	}
	
	private void checkEvaluability(){
		StringParser functionStringParser = new StringParser(functionBody);
		myFunctions.put(functionTitle.toLowerCase(), new Function(functionTitle, "", functionParameters));
		evaluable = true;
		while(!functionStringParser.isComplete()){
			try {
				myNodeFactory.getNode(new NodeInformation(functionStringParser,
						myVariables, myFunctions, mySyntaxProperties,
						myNodeInformation.getLanguageProperties()), myParserInformation);
			} catch (Exception e) {
				evaluable = false;
				myFunctions.remove(functionTitle.toLowerCase());
				break;
			}
		}
		if(evaluable) myFunctions.put(functionTitle.toLowerCase(), userFunction);
	}
	
	@Override
	protected void createStructure() throws Exception {
		functionTitle = myStringParser.getNextWord();
		functionParameters = getFunctionParameters();
		functionBody = getFunctionBody();
		userFunction = new Function(functionTitle, functionBody, functionParameters);
		checkEvaluability();	
	}


	@Override
	public double evaluate() {
		return evaluable ? 1 : 0;
	}

}
