import java.util.*;

public class MappingNameFinder
{
	private static final int NORMAL        = 0,
							 LEADER        = NORMAL + 1,
							 LEADER_NORMAL = LEADER + 1,
							 LEADER_IN_DQ  = LEADER_NORMAL + 1,
							 IN_DQ         = LEADER_IN_DQ + 1,
							 IN_SQ         = IN_DQ + 1,
							 IN_APSQ       = IN_SQ  + 1;

	public static final char LEADER_0 = '@',
							 LEADER_1 = ':',
							 DOUBLE_QUOTA = '\"',
							 SINGLE_QUOTA = '\'',
							 APOSTROPHE_QUOTA = '`',
							 SPACE = ' ';
	
	/**
	 *	This method finds all mapping names who have a leader char in 
	 *	front of it, and returns a vector of Position, indicating where 
	 *	these sub strings are located.
	 *	@param		s the string to find mapping names.
	 *	@return		Vector of Position info.  If no such mapping name
	 *				found, return a zero length Vector. 
	 */
	public static Vector find(String s)
	{
		Vector v = new Vector();

		if (s == null || s.trim().length() == 0)
		{
			return v;
		}

		char c;
		int st = NORMAL;
		Position p = new Position();
		StringBuffer mapn = new StringBuffer();

		int iLength = s.length();
		for (int i = 0; i < iLength; i++)
		{
			c = s.charAt(i);
			switch (st)
			{
				case NORMAL:
				{
					switch (c)
					{
					case LEADER_0:
					case LEADER_1:
						st = LEADER;
						mapn.setLength(0);
						p = new Position();
						p.leader = c;
						p.begin = i;
						v.addElement(p);
						break;
					case DOUBLE_QUOTA:
						st = IN_DQ;
						break;
					case SINGLE_QUOTA:
						st = IN_SQ;
						break;
					case APOSTROPHE_QUOTA:
						st = IN_APSQ;
						break;
					}
					break;
				}
				case LEADER:
				{
					if (c == DOUBLE_QUOTA)
					{
						st = LEADER_IN_DQ;
					}
					else if (c != SPACE)
					{
						st = LEADER_NORMAL;
						mapn.append(c);
					}
					break;
				}
				case LEADER_NORMAL:
				{
					if (c == SPACE || c == ')' || c == ',')
					{
						st = NORMAL;
						p.end = i;
						p.name = mapn.toString();
					}
					else
					{
						mapn.append(c);
					}
					break;
				}
				case LEADER_IN_DQ:
				{
					if (c == DOUBLE_QUOTA)
					{
						st = NORMAL;
						p.end = i + 1;
						p.name = mapn.toString();
					}
					else 
					{
						mapn.append(c);
					}
					break;
				}
				case IN_DQ:
				{
					if (c == DOUBLE_QUOTA && (i == iLength - 1 || s.charAt(i + 1) != DOUBLE_QUOTA))
					{
						st = NORMAL;
					}
					break;
				}
				case IN_SQ:
				{
					if (c == SINGLE_QUOTA && (i == iLength - 1 || s.charAt(i + 1) != SINGLE_QUOTA))
					{
						st = NORMAL;
					}
					break;
				}
				case IN_APSQ:
				{
					if (c == APOSTROPHE_QUOTA)
					{
						st = NORMAL;
					}
					break;
				}
			}
		}
		if (st != NORMAL)
		{
			p.end = s.length();
			p.name = mapn.toString();
		}
		return v;
	}


	
	public static void main(String[] args)
	{
		String sql = "Select Customer.ID "  
					 + "From Customers "
					 + "Where Customer.\"cus ID\" <> @\"cus id\" "
					 + "and Cutomer.city in (:cities) "
					 + "and Customer.ID in @ SubQuery "
					 + "or Customer.mail = \'someone@jinfonet.com\'";
		System.out.println( "SQL = " + sql);
		System.out.println(find(sql));
		System.out.println(sql.substring(0, 61));
		System.out.println(sql.substring(70, 92));
		System.out.println(sql.substring(99, 120));
		System.out.println(sql.substring(130));
		System.out.println();
	}

	public static class Position
	{
		/**
		 *	begin and end indicate that the name (including leader char 
		 *	and quotation marks) begins at the leader char <code>begin</code> and extends 
		 *	to the character at index <code>end - 1</code>.
		 *	<p>
		 *	For example:
		 *		a Position stands for <code>where @ "customer id"</code> would have 
		 *		<code>begin = 5</code> and <code>end = 21<code>.
		 *	</p>
		 */
		public int begin = -1;		// leader char position
		public int end = -1;		// end position (including double quotation mark if has)
		
		/**
		 *	The prefix char before a mapping name.  It is defined as
		 *	LEADER_0 and/or LEADER_1.
		 */
		public char leader;

		/**
		 *	The mapping name, not including leader char and quotation marks.
		 */
		public String name;

		public Position()
		{
		}

		public String toString()
		{
			return "[" + leader + ", " + name + ", " + begin + " - " + end + "] ";
		}
	}
}


