package org.bench4q.agent.plugin.basic.HBasePlugin;

import java.io.IOException;
import java.util.UUID;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.log4j.Logger;
import org.bench4q.agent.plugin.Constructor;
import org.bench4q.agent.plugin.Parameter;
import org.bench4q.agent.plugin.Plugin;
import org.bench4q.agent.plugin.behavior.Behavior;
import org.bench4q.agent.plugin.behavior.BehaviorType;
import org.bench4q.agent.utils.Type.SupportTypes;
import org.bench4q.share.exception.Bench4QRunTimeException;

@Plugin("HBase")
public class HBasePlugin {
	private final Configuration conf;
	private final HTable tableUnderTest;

	@Constructor
	public HBasePlugin(
			@Parameter(value = "dnsServer", type = SupportTypes.Field) String dnsServer,
			@Parameter(value = "zookeeperQuorum", type = SupportTypes.Field) String zookeeperQuorum,
			@Parameter(value = "zookeeperDataDir", type = SupportTypes.Field) String zookeeperDataDir,
			@Parameter(value = "masterAdrress", type = SupportTypes.Field) String masterAdrress,
			@Parameter(value = "tableName", type = SupportTypes.Field) String tableName) {
		conf = HBaseConfiguration.create();
		try {
			Configuration config = new Configuration();
			config.set("hbase.master.dns.nameserver", dnsServer);
			config.setBoolean("hbase.cluster.distributed", true);
			config.set("hbase.zookeeper.quorum", zookeeperQuorum);
			config.set("hbase.zookeeper.property.dataDir", zookeeperDataDir);
			config.set("hbase.master.info.bindAddress", masterAdrress);
			@SuppressWarnings({ "unused", "resource" })
			HBaseAdmin admin = new HBaseAdmin(config);
			tableUnderTest = new HTable(conf, tableName);
		} catch (Exception e) {
			Logger.getLogger(HBasePlugin.class).error(e, e);
			throw new Bench4QRunTimeException("Construct HBasePlugin fails!", e);
		}
	}

	@Behavior(value = "Insert", type = BehaviorType.USER_BEHAVIOR)
	public HBaseReturn insert(
			@Parameter(value = "key", type = SupportTypes.Field) String key,
			@Parameter(value = "value", type = SupportTypes.Field) String value) {
		try {
			Put put = new Put(UUID.randomUUID().toString().getBytes());
			put.add("key1".getBytes(), "key1".getBytes(), key.getBytes());
			put.add("value1".getBytes(), "value1".getBytes(), value.getBytes());
			this.tableUnderTest.put(put);
			return new HBaseReturn(true);
		} catch (Exception ex) {
			Logger.getLogger(HBasePlugin.class).info(ex, ex);
			return new HBaseReturn(false);
		}
	}

	@Behavior(value = "Query", type = BehaviorType.USER_BEHAVIOR)
	public HBaseReturn query(
			@Parameter(value = "key", type = SupportTypes.Field) String key) {
		try {
			Filter filter = new SingleColumnValueFilter(Bytes.toBytes("key1"),
					Bytes.toBytes("key1"), CompareOp.EQUAL, Bytes.toBytes(key));
			Scan s = new Scan();
			s.setFilter(filter);
			ResultScanner resultScanner = this.tableUnderTest.getScanner(s);
			for (Result r : resultScanner) {
				System.out.println("get the row key:" + new String(r.getRow()));
			}
			return new HBaseReturn(true);
		} catch (Exception ex) {
			Logger.getLogger(HBasePlugin.class).info(ex, ex);
			return new HBaseReturn(false);
		}
	}

	/**
	 * get style, read according to rowKey
	 * 
	 * @param rowkey
	 * @throws IOException
	 * @return
	 */
	@SuppressWarnings("deprecation")
	@Behavior(value = "Get", type = BehaviorType.USER_BEHAVIOR)
	public HBaseReturn get(
			@Parameter(value = "rowkey", type = SupportTypes.Field) String rowkey) {
		try {
			Get g = new Get(Bytes.toBytes(rowkey));
			Result r = tableUnderTest.get(g);
			for (KeyValue kv : r.raw()) {
				System.out.println("column: " + new String(kv.getRow()));
				System.out.println("value: " + new String(kv.getValue()));
			}
			return new HBaseReturn(true);
		} catch (IOException ex) {
			Logger.getLogger(HBasePlugin.class).info(ex, ex);
			return new HBaseReturn(false);
		}
	}

	/**
	 * Perform a range scan for a set of records in the database.
	 * 
	 * @param startkey
	 *            The record key of the first record to read.
	 * @param recordcount
	 *            The number of records to read
	 * @return
	 */

	@SuppressWarnings("deprecation")
	@Behavior(value = "Scan", type = BehaviorType.USER_BEHAVIOR)
	public HBaseReturn scan(
			@Parameter(value = "startkey", type = SupportTypes.Field) String startkey,
			@Parameter(value = "recordcount", type = SupportTypes.Field) String recordcount) {
		Scan s = new Scan(Bytes.toBytes(startkey));
		Integer count = Integer.getInteger(recordcount);
		s.setCaching(count);
		ResultScanner scanner = null;
		try {
			scanner = tableUnderTest.getScanner(s);
			int numResults = 0;
			for (Result rr = scanner.next(); rr != null; rr = scanner.next()) {

				for (KeyValue kv : rr.raw()) {
					System.out.println("result: key =" + kv.getQualifier()
							+ " value = " + kv.getValue());
				}
				numResults++;
				if (numResults >= count) {
					break;
				}
			}

		} catch (IOException e) {
			Logger.getLogger(HBasePlugin.class).info(e, e);
			return new HBaseReturn(false);
		} finally {
			scanner.close();
		}

		return new HBaseReturn(true);
	}

}