/*
 * Copyright 2006 Takahiro Nakamura.
 *
 * Licensed 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 woolpack.sql.convert;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import woolpack.sql.fn.PreparedStatementInfo;

/**
 * バインド変数コメント付きのSQLを解析するためのユーティリティです。
 * @author nakamura
 */
public final class SqlCommentUtils {
	private static final Pattern BIND_COMMENT_SQL_PATTERN = Pattern.compile(
			"[^@s,@(@)]*/@*([^@*@s]+)@s*@*/[^@s,@(@)]*".replaceAll("@", "\\\\"));
	private static final String BIND_COMMENT_SQL_PATTERN_REPLACEMENT = "?";
	private static final Pattern COMMENT_SQL_PATTERN = Pattern.compile(
			"/@*@s+[^@*]*@*/".replaceAll("@", "\\\\"));
	private static final String COMMENT_SQL_PATTERN_REPLACEMENT = "";
	
	
	private SqlCommentUtils() {}
	
	/**
	 * バインド変数コメント付きのSQLを解析してコンパイル済ステートメント情報を生成します。
	 * 例えば、
	 * 「select * from table where /<span/>* conditions *<span/>/ col0 = 11/<span/>*col0*<span/>/ and col1 = /<span/>*col1*<span/>/'hona'」は
	 * 「select * from table where  col0 = ? and col1 = ?」に変換され、
	 * バインド変数は「"col0", "col1"」に変換されます。
	 * このロジックは、正規表現「[^\s,\(\)]*<span/>/\*([^\*\s]+)\s*\*<span/>/[^\s,\(\)]*」
	 * で検索して$1を属性名として取得し、マッチ箇所全体を「?」に置き換えます。
	 * そのあと正規表現「/\*\s[^\*]*\*<span/>/」のマッチ箇所を通常コメントとして削除します。
	 * @param s 解析対象のSQL。
	 * @return バインド変数コメント付きのSQLを解析した結果。
	 */
	public static PreparedStatementInfo toPreparedStatementInfo(final String s) {
		final PreparedStatementInfo info = new PreparedStatementInfo();
		final List<String> list = new ArrayList<String>();
		info.setList(list);
		final StringBuffer sb = new StringBuffer(s.length());
		{
			final Matcher m = BIND_COMMENT_SQL_PATTERN.matcher(s);
			while (m.find()) {
				list.add(m.group(1));
				m.appendReplacement(sb, BIND_COMMENT_SQL_PATTERN_REPLACEMENT);
			}
			m.appendTail(sb);
		}
		info.setQuery(COMMENT_SQL_PATTERN.matcher(sb.toString())
				.replaceAll(COMMENT_SQL_PATTERN_REPLACEMENT));
		return info;
	}
}
