vector<string> CodisClient::mget(vector<string>& keys, int tt)
{
    vector<string> values;

    Command comm("MGET");
    for (size_t i=0; i<keys.size(); i++)
    {
        comm(keys[i]);
    }


    Reply rep = RedisCommand(comm, tt);

    if (rep.error())
    {
        return values;
    }
    else
    {
        for (size_t i=0; i<rep.elements().size(); i++)
        {
            values.push_back(rep.elements()[i].str());
        }
    }

    return values;
}
vector<string> CodisClient::hvals(string key, int tt)
{
    vector<string> values;
    Reply rep = RedisCommand(Command("HVALS")(key), tt);

    for (size_t i=0; i<rep.elements().size(); i++)
    {
        values.push_back(rep.elements()[i].str());
    }

    return values;
}
vector<string> CodisClient::hkeys(string key, int tt)
{
    vector<string> keys;
    Reply rep = RedisCommand(Command("HKEYS")(key), tt);

    for (size_t i=0; i<rep.elements().size(); i++)
    {
        keys.push_back(rep.elements()[i].str());
    }

    return keys;
}
vector<string> CodisClient::lrange(string key, int start, int end, int tt)
{
    vector<string> values;
    Reply rep = RedisCommand(Command("LRANGE")(key)(int2string(start))(int2string(end)), tt);

    for (size_t i=0; i<rep.elements().size(); i++)
    {
        values.push_back(rep.elements()[i].str());
    }

    return values;
}
bool CodisClient::hgetall(string key, vector<string>& fields, vector<string>& values, int tt)
{
    Reply rep = RedisCommand(Command("HGETALL")(key), tt);

    if (rep.error()) return false;

    for (size_t i=1; i<rep.elements().size(); i+=2)
    {
        fields.push_back(rep.elements()[i-1].str());
        values.push_back(rep.elements()[i].str());
    }

    return true;
}
/*
 * Class:     com_redis_sentinel_client_RedisClient
 * Method:    cRedisCommand
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_redis_sentinel_client_RedisClient_cRedisCommand__Ljava_lang_String_2
  (JNIEnv *env, jclass, jstring jCommand)
{
	const char* ccommand = env->GetStringUTFChars(jCommand, NULL);
	std::string comm(ccommand);
	env->ReleaseStringUTFChars(jCommand, ccommand);

	std::vector<std::string> command;
	split(comm, std::string(" "), command);

	Reply ret = client->RedisCommand(command);

	stringstream stream;
	stream << ret.type() << ";"
			<< ret.str() << ";"
			<< ret.error() << ";"
			<< ret.integer() << ";";

	std::vector<Reply> elements = ret.elements();

	for (size_t i=0; i<elements.size(); i++)
	{
		stream << elements[i].type() << ";"
				<< elements[i].str() << ";"
				<< elements[i].error() << ";"
				<< elements[i].integer() << ";";
	}

	jstring reply = env->NewStringUTF(stream.str().c_str());

	return reply;
}
vector<string> CodisClient::hmget(string key, vector<string>& fields, int tt)
{
    vector<string> values;
    Command command("HMGET");
    command(key);
    for (size_t i=0; i<fields.size(); i++)
    {
        command(fields[i]);
    }

    Reply rep = RedisCommand(command, tt);

    for (size_t i=0; i<rep.elements().size(); i++)
    {
        values.push_back(rep.elements()[i].str());
    }

    return values;
}
vector<string> CodisClient::zrevrangebyscore(string key, string min, string max, string withscores, int tt)
{
    vector<string> values;
    Reply rep;
    if (withscores=="True")
    {
        rep = RedisCommand(Command("ZREVRANGEBYSCORE")(key)(min)(max)("withscores"), tt);
    }
    else
    {
        rep = RedisCommand(Command("ZREVRANGEBYSCORE")(key)(min)(max), tt);
    }

    for (size_t i=0; i<rep.elements().size(); i++)
    {
        values.push_back(rep.elements()[i].str());
    }

    return values;
}
vector<string> CodisClient::zrevrange(string key, int start, int end, string withscores, int tt)
{
    vector<string> values;
    Reply rep;
    if (withscores=="True")
    {
        rep = RedisCommand(Command("ZREVRANGE")(key)(int2string(start))(int2string(end))("withscores"), tt);
    }
    else
    {
        rep = RedisCommand(Command("ZREVRANGE")(key)(int2string(start))(int2string(end)), tt);
    }

    for (size_t i=0; i<rep.elements().size(); i++)
    {
        values.push_back(rep.elements()[i].str());
    }

    return values;
}
vector<string> ReplyToVec(Reply rep)
{
	vector<string> ret;
	vector<Reply> reps= rep.elements();
	for(size_t i=0; i<reps.size(); i++)
	{
		ret.push_back(reps[i].str());
	}

	return ret;
}
void ReplyToString(Reply& reply, std::string &rep)
{
	stringstream stream;
	stream << reply.type() << ";"
			<< reply.str() << ";"
			<< reply.error() << ";"
			<< reply.integer() << ";";

	std::vector<Reply> elements = reply.elements();

	for (size_t i=0; i<elements.size(); i++)
	{
		stream << elements[i].type() << ";"
				<< elements[i].str() << ";"
				<< elements[i].error() << ";"
				<< elements[i].integer() << ";";
	}

	rep = stream.str();
}
std::string ReplyToString(const Reply& rep)
{
	stringstream retstream;

	vector<Reply> reps;
	if (rep.elements().size()>0)
	{
		reps = rep.elements();
	}

	switch (rep.type()) {
		case Reply::ERROR:
			retstream << rep.str();
			break;
		case Reply::STRING:
			retstream << rep.str();
			break;
		case Reply::STATUS:
			retstream << rep.str();
			break;
		case Reply::INTEGER:
		  	retstream << rep.integer();
		  	break;
		case Reply::NIL:
			retstream << "nil";
			break;
		case Reply::ARRAY:
			retstream << "*";
			retstream << rep.elements().size();
			retstream << endl;


			for (size_t idx=0; idx<reps.size(); ++idx) {
		    	switch (reps[idx].type()) {
					case Reply::ERROR:
						retstream << reps[idx].str();
						retstream << endl;
						break;
					case Reply::STRING:
						retstream << reps[idx].str();
						retstream << endl;
						break;
					case Reply::STATUS:
						retstream << reps[idx].str();
						retstream << endl;
						break;
					case Reply::INTEGER:
					  	retstream << reps[idx].integer();
					  	retstream << endl;
					  	break;
					case Reply::NIL:
						retstream << "nil";
						break;
					default:
						retstream << "+OK";
					    break;
		    	}
			}
		    break;
		default:
			retstream << "OK";
			break;
	}

	return retstream.str();
}
vector<string> RedisDB::keys(string prefix)
{
	vector<string> keys;

	if (!m_ConnPool)
	{
		fprintf(stderr, "client pool is null!!!");
		Reply reply;
		reply.SetErrorMessage("Can not fetch client from pool!!!");
		LOG(ERROR, "client pool is null!!!");
		return keys;
	}

	vector<string> command;
	command.push_back("KEYS");
	if (prefix != "")
	{
		command.push_back(prefix + "*");
	}
	else
	{
		command.push_back("*");
	}

	vector<const char*> argv;
	vector<size_t> arglen;
	for (size_t i = 0; i < command.size(); ++i)
	{
		argv.push_back(command[i].c_str());
		arglen.push_back(command[i].size());
	}

	redisContext* redis = m_ConnPool->borrowItem();
#ifdef DEBUG
	fprintf(stdout, "real key: %s, host:%s \n", inner_key.c_str(), p->getId().c_str());
#endif

	if (!redis)
	{
		fprintf(stderr, "contetx is NULL!!");
		Reply reply;
		reply.SetErrorMessage("context is NULL !!");
		LOG(ERROR, "contetx is null!!!");
		return keys;
	}
	redisReply *reply = NULL;

	string selectCommand = string("select ") + m_RedisDBNo;

	int ret = redisAppendCommand(redis, selectCommand.c_str());
	if (ret != REDIS_OK)
	{
		if (redis != NULL)
		{
			redisFree(redis);
			redis = NULL;
		}
		redis = m_ConnPool->create();
		if (redis == NULL)
		{
			LOG(ERROR, "reconnect faild!");
			Reply reply;
			reply.SetErrorMessage("reconnect faild!");
			LOG(ERROR, "reconnect faild!");
			return keys;
		}
		ret = redisAppendCommand(redis, selectCommand.c_str());
	}

	if (ret != REDIS_OK)
	{
		if (redis != NULL)
		{
			redisFree(redis);
			redis = NULL;
		}
		Reply reply;
		reply.SetErrorMessage("Do Select Command faild.");
		LOG(ERROR, "Do Select Command faild.");
		return keys;
	}

	ret = redisAppendCommandArgv(redis, argv.size(), &argv[0], &arglen[0]);

	if (ret != REDIS_OK)
	{
		if (redis != NULL)
		{
			redisFree(redis);
			redis = NULL;
		}
		Reply reply;
		reply.SetErrorMessage("Do Command faild.");
		LOG(ERROR, "Do Command faild.");
		return keys;
	}

	if (REDIS_OK != redisGetReply(redis, (void**) &reply))
	{
		if (redis != NULL)
		{
			redisFree(redis);
			redis = NULL;
		}
		Reply reply;
		reply.SetErrorMessage("Do Select Command faild.");
		LOG(ERROR, "Do Select Command faild.");
		return keys;
	}

	if (string(reply->str) != string("OK"))
	{
		if (redis != NULL)
		{
			redisFree(redis);
			redis = NULL;
		}
		Reply reply;
		reply.SetErrorMessage(
				"Do Select Command faild, please check redis config parameter databases, it must >= 1024!");
		LOG(ERROR, "Do Select Command faild, please check redis config parameter databases, it must >= 1024!");
		return keys;
	}

	if (REDIS_OK != redisGetReply(redis, (void**) &reply))
	{
		if (redis != NULL)
		{
			redisFree(redis);
			redis = NULL;
		}
		Reply reply;
		reply.SetErrorMessage("Do Command faild.");
		LOG(ERROR, "Do Command faild.");
		return keys;
	}

	m_ConnPool->returnItem(redis);
	Reply retrep = Reply(reply);
	freeReplyObject(reply);

	for (size_t i=0; i<retrep.elements().size(); i++)
	{
		keys.push_back(retrep.elements()[i].str());
	}

	return keys;
}