package org.nutz.dao.impl;
import static java.lang.String.format;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.nutz.dao.SqlManager;
import org.nutz.dao.SqlNotFoundException;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.lang.Lang;
import org.nutz.lang.Streams;
import org.nutz.lang.Strings;
import org.nutz.lang.util.LinkedCharArray;
/**
*
* @author zozoh(zozohtnt@gmail.com)
* @author wendal(wendal1985@gmail.com)
* @author mawenming at 2010-4-10 上午10:04:17
*
*/
public abstract class AbstractSqlManager implements SqlManager {
protected Map<String, String> _sql_map;
private List<String> _sql_keys;
private Map<String, String> map() {
if (null == _sql_map)
this.refresh();
return _sql_map;
}
private List<String> keylist() {
if (null == _sql_keys)
this.refresh();
return _sql_keys;
}
public boolean contains(String key) {
return map().containsKey(key);
}
public void saveAs(File f) throws IOException {
Writer w = Streams.fileOutw(f);
for (String key : keylist()) {
w.append("/*").append(Strings.dup('-', 60)).append("*/\n");
String sql = map().get(key);
w.append(format("/*%s*/\n", key));
w.append(sql).append('\n');
}
w.flush();
w.close();
}
public String get(String key) {
String sql = map().get(key);
if (null == sql)
throw new SqlNotFoundException(key);
return sql;
}
public Sql create(String key) throws SqlNotFoundException {
return Sqls.create(get(key));
}
public List<Sql> createCombo(String... keys) {
if (null == keys || keys.length == 0)
keys = this.keys();
List<Sql> list = new ArrayList<Sql>(keys.length);
for (String key : keys) {
Sql sql = create(key);
list.add(sql);
}
return list;
}
public int count() {
return map().size();
}
public String[] keys() {
return keylist().toArray(new String[keylist().size()]);
}
public void addSql(String key, String value) {
if (map().containsKey(key)) {
throw Lang.makeThrow("duplicate key '%s'", key);
}
key = Strings.trim(key);
map().put(key, value);
keylist().add(key);
}
static final Pattern ptn = Pattern.compile("(?<=^\n/[*])(.*)(?=[*]/)");
static class InnerStack {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
LinkedCharArray list = new LinkedCharArray();
LinkedCharArray cmts = new LinkedCharArray();
String key = null;
boolean inNormalComment;
void eat(int c) {
if (inNormalComment) {
if (cmts.push(c).endsWith("*/")) {
cmts.clear();
inNormalComment = false;
}
} else if (key != null) {
if (list.push(c).endsWith("\n/*")) {
list.popLast(3);
addOne();
list.push("\n/*");
} else if (list.endsWith("/*")) {
list.popLast(2);
inNormalComment = true;
}
} else {
if (list.size() < 3) {
if (!"\n/*".startsWith(list.push(c).toString())) {
list.clear();
}
} else {
if (list.push(c).endsWith("*/")) {
Matcher matcher = ptn.matcher(list.popAll());
if (matcher.find()) {
key = Strings.trim(matcher.group());
}
}
}
}
}
void addOne() {
String value = Strings.trim(list.popAll());
if (!Strings.isBlank(value))
map.put(key, value);
key = null;
}
}
static class SqlFileBuilder {
LinkedHashMap<String, String> map;
SqlFileBuilder(BufferedReader reader) throws IOException {
InnerStack stack = new InnerStack();
int c;
stack.eat('\n');
while (-1 != (c = reader.read())) {
stack.eat(c);
}
if (stack.key != null)
stack.addOne();
map = stack.map;
Streams.safeClose(reader);
}
Set<String> keys() {
return map.keySet();
}
String get(String key) {
return map.get(key);
}
}
public void remove(String key) {
this.keylist().remove(key);
this.map().remove(key);
}
/**
* 执行根据字符流来加载sql内容的操作
*
* @param reader
* @throws IOException
*/
protected void loadSQL(Reader reader) throws IOException {
BufferedReader bufferedReader = null;
try {
if(reader instanceof BufferedReader)
bufferedReader = (BufferedReader)reader;
else
bufferedReader = new BufferedReader(reader);
SqlFileBuilder p = new SqlFileBuilder(bufferedReader);
Iterator<String> it = p.keys().iterator();
_sql_keys = new ArrayList<String>(p.map.size());
while (it.hasNext()) {
String key = it.next();
String value = Strings.trim(p.get(key));
addSql(key, value);
}
}
finally {
Streams.safeClose(bufferedReader);
}
}
}