/******************************************************************************* 
 * Copyright (c) 2007 Red Hat, Inc. 
 * Distributed under license by Red Hat, Inc. All rights reserved. 
 * This program is made available under the terms of the 
 * Eclipse Public License v1.0 which accompanies this distribution, 
 * and is available at http://www.eclipse.org/legal/epl-v10.html 
 * 
 * Contributors: 
 * Red Hat, Inc. - initial API and implementation 
 ******************************************************************************/ 
package org.jboss.tools.common.el.core.parser;

import java.util.List;
import java.util.Stack;

import org.jboss.tools.common.el.core.model.ELModel;
import org.jboss.tools.common.el.internal.core.model.ELModelImpl;
import org.jboss.tools.common.el.internal.core.parser.ELParserImpl;

/**
 * 
 * @author V. Kabanovich
 *
 */
public class ELParserUtil {

	private static ELParserFactory DEFAULT_FACTORY = new DefaultFactory() {
		public ELParser newParser() {
			return new DefaultParser() {
				protected Tokenizer createTokenizer() {
					return TokenizerFactory.createDefaultTokenizer();
				}
				public void dispose() {
					super.dispose();
					release(this);
				}
			};
		}
	};

	public static ELParserFactory getDefaultFactory() {
		return DEFAULT_FACTORY;
	}

	private static ELParserFactory COLLECTION_FACTORY = new DefaultFactory() {
		public ELParser newParser() {
			return new DefaultParser() {
				protected Tokenizer createTokenizer() {
					return TokenizerFactory.createCollectionTokenizer();
				}
				public void dispose() {
					super.dispose();
					release(this);
				}
			};
		}
	};

	/**
	 * Extends default factory by ability to parse method invocation without parameters
	 * to support access to collection and map elements by .iterator().next()
	 * @return
	 */
	public static ELParserFactory getCollectionFactory() {
		return COLLECTION_FACTORY;
	}

	private static ELParserFactory JBOSS_FACTORY = new DefaultFactory() {
		public ELParser newParser() {
			return new DefaultParser() {
				protected Tokenizer createTokenizer() {
					return TokenizerFactory.createJbossTokenizer();
				}
				public void dispose() {
					super.dispose();
					release(this);
				}
			};
		}
	};

	public static ELParserFactory getJbossFactory() {
		return JBOSS_FACTORY;
	}

	private static abstract class DefaultFactory implements ELParserFactory {
		protected Stack<ELParser> inUse = new Stack<ELParser>();
		protected Stack<ELParser> free = new Stack<ELParser>();

		public ELParser createParser() {
			synchronized(this) {
				if(!free.isEmpty()) {
					//reuse
					ELParser parser = free.pop();
					inUse.push(parser);
					return parser;
				}
			}
			ELParser parser = newParser();
			synchronized(this) {
				//new
				inUse.push(parser);
			}			
			return parser;
		}

		protected abstract ELParser newParser();

		public void release(ELParser parser) {
			synchronized(this) {
				//release
				boolean b = inUse.remove(parser);
				if(!b) return;
				free.push(parser);
			}
		}
	}

	private static abstract class DefaultParser implements ELParser {
		ELParserImpl impl = new ELParserImpl();
		List<SyntaxError> errors = null;
		Tokenizer t = createTokenizer();

		public ELModel parse(String source) {
			return parse(source, 0, source.length());
		}

		public ELModel parse(String source, int start, int length) {
			try {
				LexicalToken token = t.parse(source, start, length);
				errors = t.getErrors();
				ELModelImpl model = impl.parse(token);
				model.setSource(source);
				model.setErrors(errors);
				return model;
			} finally {
				t.dispose();
				dispose();
			}
		}

		protected abstract Tokenizer createTokenizer();

		public void dispose() {
			errors = null;
		}

	}

}
