content: /**
   *  Copyright (c) 2013-2016 Angelo ZERR.
   *  All rights reserved. This program and the accompanying materials
   *  are 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:
   *  Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
   */
  package tern.server.protocol.completions;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import tern.utils.StringUtils;
  
  /**
   * Helper for tern type.
   *
   */
  public class TernTypeHelper {
  
  	public static final String STRING_TYPE = "string";
  	public static final String NUMBER_TYPE = "number";
  	public static final String BOOL_TYPE = "bool";
  
  	private static final String FUNCTION_REF = "fn";
  	private static final String FUNCTION_START = "fn(";
  	private static final String FUNCTION_ARRAY_START = "[fn(";
  
  	private TernTypeHelper() {
  	}
  
  	/**
  	 * Returns true if the given type is fn() and false otherwise.
  	 * 
  	 * @param type
  	 *            the tern type
  	 * @return true if the given type is fn() and false otherwise.
  	 */
  	public static boolean isFunction(String type) {
  		return !StringUtils.isEmpty(type)
  				&& (type.startsWith(FUNCTION_START) || type
  						.startsWith(FUNCTION_ARRAY_START));
  	}
  
  	/**
  	 * Return the function information of the given function name and type.
  	 * 
  	 * @param name
  	 *            function name
  	 * @param type
  	 *            function type
  	 * @return the function information of the given function name and type.
  	 */
  	public static FunctionInfo parseFunction(String name, String type) {
  		type = type.startsWith("[") ? type.substring(1, type.length()) : type;
  		StringBuilder signature = name != null ? new StringBuilder(name) : null;
  		List<Parameter> parameters = null;
  		StringBuilder currentParamName = null;
  		boolean currentParamRequired = true;
  		StringBuilder currentParamType = null;
  
  		if (signature != null) {
  			signature.append("(");
  		}
  		int bracket = 0;
  		String afterStartFn = type.substring(2, type.length());
  		int i = 0;
  		for (i = 0; i < afterStartFn.length(); i++) {
  			char c = afterStartFn.charAt(i);
  			switch (c) {
  			case '(':
  				bracket++;
  				if (currentParamType != null)
  					currentParamType.append(c);
  				break;
  			case ')':
  				bracket--;
  				if (bracket >= 1 && currentParamType != null)
  					currentParamType.append(c);
  				break;
  			default:
  				if (bracket >= 1) {
  					if (currentParamType != null) {
  						if (c == ',') {
  							if (bracket < 2) {
  								parameters
  										.add(new Parameter(
  												currentParamName.toString(),
  												currentParamRequired,
  												currentParamType != null ? currentParamType
  														.toString() : null));
  								currentParamName = null;
  								currentParamRequired = true;
  								currentParamType = null;
  							} else {
  								currentParamType.append(c);
  							}
  						} else if (c != ' ') {
  							currentParamType.append(c);
  						}
  					} else {
  						if (currentParamName == null) {
  							if (c != ' ' && c != '?') {
  								currentParamName = new StringBuilder();
  								currentParamName.append(c);
  							}
  						} else {
  							if (c == ':') {
  								if (parameters == null) {
  									parameters = new ArrayList<Parameter>();
  								} else {
  									if (signature != null) {
  										signature.append(", ");
  									}
  								}
  								if (signature != null) {
  									signature.append(currentParamName
  											.toString());
  								}
  								currentParamType = new StringBuilder();
  							} else {
  								if (c == '?') {
  									currentParamRequired = false;
  								} else if (c != ' ') {
  									currentParamName.append(c);
  								}
  							}
  						}
  					}
  				}
  			}
  			if (bracket == 0)
  				break;
  		}
  		if (currentParamName != null) {
  			if (parameters == null) {
  				parameters = new ArrayList<Parameter>();
  			}
  			parameters.add(new Parameter(currentParamName.toString(),
  					currentParamRequired,
  					currentParamType != null ? currentParamType.toString()
  							: null));
  			currentParamName = null;
  			currentParamRequired = true;
  			currentParamType = null;
  		}
  		if (signature != null) {
  			signature.append(")");
  		}
  		StringBuilder s = null;
  		for (int j = i + 1; j < afterStartFn.length(); j++) {
  			char c = afterStartFn.charAt(j);
  			if (s != null) {
  				s.append(c);
  			} else {
  				if (c == '>') {
  					s = new StringBuilder();
  				}
  			}
  		}
  		String returnType = s != null ? s.toString().trim() : null;
  		return new FunctionInfo(parameters,
  				signature != null ? signature.toString() : null, returnType);
  	}
  
  	/**
  	 * Returns true if the given type is "string" type and false otherwise.
  	 * 
  	 * @param type
  	 * @return true if the given type is "string" type and false otherwise.
  	 */
  	public static boolean isStringType(String type) {
  		return STRING_TYPE.equals(type);
  	}
  
  	/**
  	 * Returns true if the given type is "number" type and false otherwise.
  	 * 
  	 * @param type
  	 * @return true if the given type is "number" type and false otherwise.
  	 */
  	public static boolean isNumberType(String type) {
  		return NUMBER_TYPE.equals(type);
  	}
  
  	/**
  	 * Returns true if the given type is "bool" type and false otherwise.
  	 * 
  	 * @param type
  	 * @return true if the given type is "bool" type and false otherwise.
  	 */
  	public static boolean isBoolType(String type) {
  		return BOOL_TYPE.equals(type);
  	}
  
  	/**
  	 * Returns true if the given type is "fn" type and false otherwise.
  	 * 
  	 * @param type
  	 * @return true if the given type is "fn" type and false otherwise.
  	 */
  	public static boolean isFunctionRefType(String type) {
  		return FUNCTION_REF.equals(type);
  	}
  }
  