/*
 * Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software;Designed and Developed mainly by many Chinese 
 * opensource volunteers. you can redistribute it and/or modify it under the 
 * terms of the GNU General Public License version 2 only, as published by the
 * Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * Any questions about this component can be directed to it's project Web address 
 * https://code.google.com/p/opencloudb/.
 *
 */
package com.talent.mysql.packet.request;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

import java.nio.ByteOrder;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.talent.balance.conf.BackendConf;
import com.talent.balance.conf.BackendServerConf;
import com.talent.mysql.packet.MysqlRequestPacket;
import com.talent.mysql.packet.factory.MysqlHeaderFactory;
import com.talent.mysql.packet.factory.MysqlHeaderFactory.MysqlHeader;
import com.talent.mysql.packet.response.HandshakePacket;
import com.talent.mysql.utils.Capabilities;
import com.talent.mysql.utils.SecurityUtil;
import com.talent.nio.communicate.intf.DecoderIntf.DecodeException;

/**
 * 
	40 00 00                    //数据长度,3字节,0x40=64字节<br>
	01                          //序号,1字节,同一个动作的所有请求与响应会递增此值<br>
	
	8D A6 03 00                 //客户端支持的属性,4字节,枚举参见网站<br>
	FF FF FF 00                 //最大数据包长度,4字节,0xffffff=16777215=约16MB<br>
	21                          //字符集,1字节,0x21=33=utf8<br>
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   //固定填充0,23字节<br>
	74 65 73 74 00              //用户名,\0结尾的字符串,内容为test<br>
	14                          //密码串长度,1字节,0x14=20字节<br>
	B4 2F BB 65 7A D4 55 BA 9E E4 4B 34 A3 2C F6 58 92 7A A7 A2   //密码的加密串,20字节(算法见后)<br>
	76 6D 6E 70 6E 00           //初始数据库,\0结尾的字符串,内容为vmnpn<br>
 * 
 * @see  http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse
 * @filename:	 com.talent.mysql.packet.request.AuthPacket
 * @copyright:   Copyright (c)2010
 * @company:     talent
 * @author:      谭耀武
 * @version:     1.0
 * @create time: 2013年12月26日 下午5:19:13
 * @record
 * <table cellPadding="3" cellSpacing="0" style="width:600px">
 * <thead style="font-weight:bold;background-color:#e3e197">
 * 	<tr>   <td>date</td>	<td>author</td>		<td>version</td>	<td>description</td></tr>
 * </thead>
 * <tbody style="background-color:#ffffeb">
 * 	<tr><td>2013年12月26日</td>	<td>谭耀武</td>	<td>1.0</td>	<td>create</td></tr>
 * </tbody>
 * </table>
 */
public class AuthPacket extends MysqlRequestPacket
{
	/**
	 * 
	 */
	private static final long serialVersionUID = -474477733084620969L;

	private static final long CLIENT_FLAGS = initClientFlags();

	private static Logger log = LoggerFactory.getLogger(AuthPacket.class);

	public long clientFlags = CLIENT_FLAGS; //172939;//
	public long maxPacketSize = 15 * 1024 * 1024;  //1073741824;//
	public byte charsetIndex;
	public byte[] extra = new byte[23]; //固定填充0,23字节<br>
	public byte[] user;
	public byte passwordLen;
	public byte[] password;
	public byte[] database;

	private static long initClientFlags()
	{
		long flag = 0;
		flag |= Capabilities.CLIENT_LONG_PASSWORD;
		flag |= Capabilities.CLIENT_FOUND_ROWS;
		flag |= Capabilities.CLIENT_LONG_FLAG;
		flag |= Capabilities.CLIENT_CONNECT_WITH_DB;
		// flag |= Capabilities.CLIENT_NO_SCHEMA;
		// flag |= Capabilities.CLIENT_COMPRESS;
		flag |= Capabilities.CLIENT_ODBC;
		// flag |= Capabilities.CLIENT_LOCAL_FILES;
		flag |= Capabilities.CLIENT_IGNORE_SPACE;
		flag |= Capabilities.CLIENT_PROTOCOL_41;
		flag |= Capabilities.CLIENT_INTERACTIVE;
		// flag |= Capabilities.CLIENT_SSL;
		flag |= Capabilities.CLIENT_IGNORE_SIGPIPE;
		flag |= Capabilities.CLIENT_TRANSACTIONS;
		// flag |= Capabilities.CLIENT_RESERVED;
		flag |= Capabilities.CLIENT_SECURE_CONNECTION;
		// client extension
		// flag |= Capabilities.CLIENT_MULTI_STATEMENTS;
		// flag |= Capabilities.CLIENT_MULTI_RESULTS;
		return flag;
	}

	public int bodyLenth()
	{
		//		return 4 + 4 + 1 + 23 + user.length + 1 + 1 + 20 + database.length + 1;
		return 55 + user.length + database.length;
	}

	/**
	 * 
	 */
	public AuthPacket()
	{

	}

	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		AuthPacket authPacket1 = new AuthPacket();
		authPacket1.decodeBody(null);

		byte[] bs = new byte[] { 82, 0, 0, 0, 10, 49, 48, 46, 48, 46, 49, 45, 77, 97, 114, 105, 97, 68, 66, 0, -98, 1,
				0, 0, 110, 104, 61, 56, 64, 122, 101, 107, 0, -1, -9, 8, 2, 0, 15, -96, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0,
				0, 105, 78, 41, 35, 111, 43, 39, 124, 98, 82, 87, 60, 0, 109, 121, 115, 113, 108, 95, 110, 97, 116,
				105, 118, 101, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0 };
		ByteBuf byteBuf = Unpooled.buffer(bs.length);
		byteBuf = byteBuf.order(ByteOrder.LITTLE_ENDIAN);

		byteBuf.setBytes(0, bs);

		HandshakePacket handshakePacket = new HandshakePacket();
		try
		{
			handshakePacket.decode(byteBuf);
			byteBuf.readerIndex(0);
		} catch (DecodeException e)
		{
			e.printStackTrace();
		}

		BackendConf backendConf = BackendConf.getInstance();
		BackendServerConf backendServerConf = backendConf.getServers()[0];

		AuthPacket authPacket = new AuthPacket();
		authPacket.charsetIndex = (byte) (handshakePacket.charset & 0xff);
		authPacket.user = backendServerConf.getProps().get("user").getBytes();
		try
		{
			authPacket.password = getPass(backendServerConf.getProps().get("pwd"), handshakePacket);
		} catch (NoSuchAlgorithmException e)
		{
			e.printStackTrace();
		}
		authPacket.passwordLen = (byte) authPacket.password.length;
		authPacket.database = backendServerConf.getProps().get("db").getBytes();
		ByteBuf byteBuf1 = authPacket.encode();
		System.out.println(Arrays.toString(byteBuf1.array()));

	}

	public static final byte[] getPass(String pass, HandshakePacket hs) throws NoSuchAlgorithmException
	{
		if (pass == null || pass.length() == 0)
		{
			return null;
		}
		byte[] passwd = pass.getBytes();
		int sl1 = hs.encrypt1.length;
		int sl2 = hs.encrypt2.length;
		byte[] seed = new byte[sl1 + sl2];
		System.arraycopy(hs.encrypt1, 0, seed, 0, sl1);
		System.arraycopy(hs.encrypt2, 0, seed, sl1, sl2);
		return SecurityUtil.scramble411(passwd, seed);

		//		if (src == null || src.length() == 0)
		//		{
		//			return null;
		//		}
		//		byte[] passwd = src.getBytes();
		//		int sl1 = handshakePacket.encrypt1.length;
		//		int sl2 = handshakePacket.authPluginName.length;
		//		byte[] seed = new byte[sl1 + sl2];
		//		System.arraycopy(handshakePacket.encrypt1, 0, seed, 0, sl1);
		//		System.arraycopy(handshakePacket.authPluginName, 0, seed, sl1, sl2);
		//		return SecurityUtil.scramble411(passwd, seed);
	}

	@Override
	public void encodeBody(ByteBuf byteBuf)
	{
		int index = byteBuf.readerIndex();
		String xx = Long.toBinaryString(clientFlags);
		byteBuf.setLong(index, clientFlags);
		index += 4;

		byteBuf.setLong(index, maxPacketSize);
		index += 4;

		byteBuf.setByte(index, charsetIndex);
		index++;

		byteBuf.setBytes(index, extra);
		index += extra.length;

		byteBuf.setBytes(index, user);
		index += user.length;

		byteBuf.setByte(index, 0);
		index++;

		byteBuf.setByte(index, passwordLen);
		index++;

		byteBuf.setBytes(index, password);
		index += password.length;

		byteBuf.setBytes(index, database);
		index += database.length;

		byteBuf.setByte(index, 0);
		index++;
	}

	public void decodeBody(ByteBuf _byteBuf)
	{
		byte[] bs = new byte[] { -117, -93, 2, 0, 0, 0, 0, 64, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
				0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 111, 111, 116, 0, 20, -19, -111, -3, 39, -46, -116, -128, -44, -112,
				-26, -48, 42, 70, -85, 8, 83, 83, 100, 103, 68, 116, 97, 108, 101, 110, 116, 95, 98, 97, 115, 101, 119,
				101, 98, 50, 48, 49, 0 };
		ByteBuf byteBuf = Unpooled.buffer(bs.length);
		byteBuf = byteBuf.order(ByteOrder.LITTLE_ENDIAN);
		byteBuf.setBytes(0, bs, 0, bs.length);
		
		int _index = byteBuf.readerIndex();
		int index = _index;

		clientFlags = byteBuf.getInt(index);  //172939
		index += 4;
		
		maxPacketSize = byteBuf.getInt(index);  //1073741824
		index += 4;
		
		charsetIndex = byteBuf.getByte(index);  //33
		index += 1;
		
		index += extra.length;
		
		
		int len = 0;
		while (byteBuf.getByte(index+len) != 0)
		{
			len++;
		}
		user = new byte[len];
		byteBuf.getBytes(index, user, 0, len);
		index += len;
		index++;
		
		passwordLen = byteBuf.getByte(index);
		index += 1;
		
		password = new byte[passwordLen];
		byteBuf.getBytes(index, password, 0, passwordLen);
		
		
		len = 0;
		while (byteBuf.getByte(index+len) != 0)
		{
			len++;
		}
		database = new byte[len];
		byteBuf.getBytes(index, database, 0, len);
		index += len;
		index++;
		
	}

	@Override
	public MysqlHeader createHeader()
	{
		MysqlHeader mysqlHeader = MysqlHeaderFactory.borrow(bodyLenth(), (byte) 1);
		return mysqlHeader;
	}

}