package io.mycat.route.sequence;

import io.mycat.route.sequence.handler.*;
import org.slf4j.Logger; import org.slf4j.LoggerFactory;

import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;

import io.mycat.MycatServer;
import io.mycat.cache.LayerCachePool;
import io.mycat.catlets.Catlet;
import io.mycat.config.model.SchemaConfig;
import io.mycat.config.model.SystemConfig;
import io.mycat.config.model.TableConfig;
import io.mycat.route.RouteResultset;
import io.mycat.route.factory.RouteStrategyFactory;
import io.mycat.server.ServerConnection;
import io.mycat.server.parser.ServerParse;
import io.mycat.sqlengine.EngineCtx;
import io.mycat.util.StringUtil;

/**
 * 执行批量插入sequence Id
 * @author 兵临城下
 * @date 2015/03/20
 */
public class BatchInsertSequence implements Catlet {
	private static final Logger LOGGER = LoggerFactory.getLogger(BatchInsertSequence.class);
	
	private RouteResultset rrs;//路由结果集
	private String executeSql;//接收执行处理任务的sql
	private SequenceHandler sequenceHandler;//sequence处理对象
	
	//重新路由使用
	private SystemConfig sysConfig;
	private SchemaConfig schema;
	private int sqltype; 
	private String charset; 
	private ServerConnection sc;
	private LayerCachePool cachePool;

	@Override
	public void processSQL(String sql, EngineCtx ctx) {
		throw new UnsupportedOperationException("batch insert is not supported because the mycat 1.6 does not support multi statements.");
//		try {
//
//			getRoute(executeSql);
//			RouteResultsetNode[] nodes = rrs.getNodes();
//			if (nodes == null || nodes.length == 0 || nodes[0].getName() == null
//					|| nodes[0].getName().equals("")) {
//				ctx.getSession().getSource().writeErrMessage(ErrorCode.ER_NO_DB_ERROR,
//						"No dataNode found ,please check tables defined in schema:"
//								+ ctx.getSession().getSource().getSchema());
//				return;
//			}
//
//			sc.getSession2().execute(rrs, sqltype);//将路由好的数据执行入库
//
//		} catch (Exception e) {
//			LOGGER.error("BatchInsertSequence.processSQL(String sql, EngineCtx ctx)",e);
//		}
	}

	@Override
	public void route(SystemConfig sysConfig, SchemaConfig schema, int sqlType,
			String realSQL, String charset, ServerConnection sc,
			LayerCachePool cachePool) {
		int rs = ServerParse.parse(realSQL);
		this.sqltype = rs & 0xff;
		this.sysConfig=sysConfig; 
		this.schema=schema;
		this.charset=charset; 
		this.sc=sc;	
		this.cachePool=cachePool;	
		
		try {
			MySqlStatementParser parser = new MySqlStatementParser(realSQL);	 
			SQLStatement statement = parser.parseStatement();
			MySqlInsertStatement insert = (MySqlInsertStatement)statement;
			if(insert.getValuesList()!=null){
				String tableName = StringUtil.getTableName(realSQL).toUpperCase();
				TableConfig tableConfig = schema.getTables().get(tableName);
				String primaryKey = tableConfig.getPrimaryKey();//获得表的主键字段
				
				SQLIdentifierExpr sqlIdentifierExpr = new SQLIdentifierExpr();
				sqlIdentifierExpr.setName(primaryKey);
				insert.getColumns().add(sqlIdentifierExpr);
				
				if(sequenceHandler == null){
					int seqHandlerType = MycatServer.getInstance().getConfig().getSystem().getSequenceHandlerType();
					switch(seqHandlerType){
						case SystemConfig.SEQUENCEHANDLER_MYSQLDB:
							sequenceHandler = IncrSequenceMySQLHandler.getInstance();
							break;
						case SystemConfig.SEQUENCEHANDLER_LOCALFILE:
							sequenceHandler = IncrSequencePropHandler.getInstance();
							break;
						case SystemConfig.SEQUENCEHANDLER_LOCAL_TIME:
							sequenceHandler = IncrSequenceTimeHandler.getInstance();
							break;
						case SystemConfig.SEQUENCEHANDLER_ZK_DISTRIBUTED:
							sequenceHandler = DistributedSequenceHandler.getInstance(MycatServer.getInstance().getConfig().getSystem());
							break;
						case SystemConfig.SEQUENCEHANDLER_ZK_GLOBAL_INCREMENT:
							sequenceHandler = IncrSequenceZKHandler.getInstance();
							break;
						default:
							throw new java.lang.IllegalArgumentException("Invalid sequnce handler type "+seqHandlerType);
					}
				}
				
				for(ValuesClause vc : insert.getValuesList()){
					SQLIntegerExpr sqlIntegerExpr = new SQLIntegerExpr();
					long value = sequenceHandler.nextId(tableName.toUpperCase());
					sqlIntegerExpr.setNumber(value);//插入生成的sequence值
					vc.addValue(sqlIntegerExpr);
				}
				
				String insertSql = insert.toString();
				this.executeSql = insertSql;
			}
			
		} catch (Exception e) {
			LOGGER.error("BatchInsertSequence.route(......)",e);
		}
	}
	
	/**
	 * 根据sql获得路由执行结果
	 * @param sql
	 */
	private void getRoute(String sql){
		try {
			rrs =RouteStrategyFactory.getRouteStrategy().route(sysConfig, schema, sqltype,sql,charset, sc, cachePool);
		} catch (Exception e) {
			LOGGER.error("BatchInsertSequence.getRoute(String sql)",e);
		}
	}

}