/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 flash.tools.debugger.expression;

import java.io.IOException;
import java.io.Reader;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.tree.as.IASNode;

import flash.localization.LocalizationManager;
import flash.tools.debugger.DebuggerLocalizer;

/**
 * ASTBuilder.java
 * 
 *    This class creates an abstract syntax tree representation
 *    of an expression given a sequence of tokens.
 * 
 *    The tree is built by calling the ActionScript compiler and
 *    having it parse the expression, then converting the result
 *    to a form we prefer.
 *
 *    No compression is performed on the tree, thus expressions
 *    such as (3*4) will result in 3 nodes.
 * 
 */
public class ASTBuilder implements IASTBuilder
{
	private static LocalizationManager s_localizationManager;

	/**
	 * whether the fdb indirection operators are allowed, e.g. asterisk (*x) or
	 * trailing dot (x.)
	 */
	private boolean m_isIndirectionOperatorAllowed = true;

	static
	{
        // set up for localizing messages
        s_localizationManager = new LocalizationManager();
        s_localizationManager.addLocalizer( new DebuggerLocalizer("flash.tools.debugger.expression.expression.") ); //$NON-NLS-1$
	}

	/**
	 * @param isIndirectionOperatorAllowed
	 *            whether the fdb indirection operators are allowed, e.g.
	 *            asterisk (*x) or trailing dot (x.)
	 */
	public ASTBuilder(boolean isIndirectionOperatorAllowed)
	{
		m_isIndirectionOperatorAllowed = isIndirectionOperatorAllowed;
	}

	/**
	 * @return whether the fdb indirection operators are allowed, e.g. asterisk
	 *         (*x) or trailing dot (x.)
	 */
	public boolean isIndirectionOperatorAllowed()
	{
		return m_isIndirectionOperatorAllowed;
	}


	/*
	 * @see flash.tools.debugger.expression.IASTBuilder#parse(java.io.Reader)
	 */
	public ValueExp parse(Reader in) throws IOException, ParseException
	{
		DebuggerExpression retval = new DebuggerExpression();

		StringBuilder sb = new StringBuilder();
		int ch;
		while ( (ch=in.read()) != -1 )
			sb.append((char)ch);

		String s = sb.toString();

		// FB-16879: If expression begins with "#N" where N is a number,
		// replace that with "$obj(N)".  For example, "#3" would become
		// "$obj(3)".  Later, in PlayerSession.callFunction(), we will
		// detect the $obj() function and handle it.
		s = s.replaceFirst("^#([0-9]+)", "\\$obj($1)"); //$NON-NLS-1$ //$NON-NLS-2$

		if (isIndirectionOperatorAllowed()) {
			if (s.endsWith(".")) { //$NON-NLS-1$
				retval.setLookupMembers(true);
				s = s.substring(0, s.length() - 1);
			} else if (s.startsWith("*")) { //$NON-NLS-1$
				retval.setLookupMembers(true);
				s = s.substring(1);
			}
		}

		// Enclose the expression in parentheses, in order to ensure that the
		// parser considers it to be an expression.  For example, "{x:3}" would
		// be considered to be a block with label "x" and value "3", but,
		// "({x:3})" is considered to be an inline object with field "x" that
		// has value 3.
		s = "(" + s + ")"; //$NON-NLS-1$ //$NON-NLS-2$

		final List<ICompilerProblem> errors = new ArrayList<ICompilerProblem>();
//		CompilerHandler newHandler = new CompilerHandler() {
//			@Override
//			public void error(final String filename, int ln, int col, String msg, String source) {
//				ErrorInfo ei = new ErrorInfo();
//				ei.filename = filename;
//				ei.ln = ln;
//				ei.col = col;
//				ei.msg = msg;
//				ei.source = source;
//				errors.add(ei);
//			}
//		};
//		cx.setHandler(newHandler);
//		cx.scriptAssistParsing = true;
	//	Parser parser = new Parser(cx, s, "Expression"); //$NON-NLS-1$
		IASNode programNode = DebuggerUtil.parseExpression(s, errors);
		//ProgramNode programNode = parser.parseProgram();

		if (errors.size() > 0) {
			 ICompilerProblem firstError = errors.get(0);
			throw new ParseException(firstError.toString(), firstError.getColumn());
		}

		retval.setProgramNode(programNode);
		return retval;
	}

	 
	static LocalizationManager getLocalizationManager()
	{
		return s_localizationManager;
	}
}
