package com.pingpang.redis.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.data.redis.core.query.SortQuery;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.pingpang.redis.RedisPre;
import com.pingpang.redis.service.RedisService;
import com.pingpang.websocketchat.Message;


@Service
@DubboService
public class RedisServiceImpl implements RedisService{
	
	// 日志操作
    protected Logger logger = LoggerFactory.getLogger(RedisServiceImpl.class);
	
    @Resource
    private RedisTemplate<String, Object> redisTemplateString;
    
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    
    @Resource
    private RedisTemplate<String, Object>redisTemplateGroup;
    
    /**
     * 添加数据
     * @param key
     * @param value
     */
    public void set(String key, Object value) {
    	//delete(key);
        ValueOperations<String, Object> vo =  redisTemplate.opsForValue();
        vo.set(key, value);
    }

    /**
     * 获取数据
     * @param key
     * @return
     */
    public Object get(String key) {
        ValueOperations<String, Object> vo =  redisTemplate.opsForValue();
        return vo.get(key);
    }
    
    /**
     * 删除数据
     * @param key
     * @return
     */
    public boolean delete(String key) {
    	return redisTemplate.delete(key);
    }
    
    
    /**
     * 删除数据匹配前缀
     * @param prex
     * @return
     */
    public void deletePrex(String prex) {
    	Set<String> keys = redisTemplate.keys(prex);
        if (null!=keys && !keys.isEmpty()) {
            redisTemplate.delete(keys);
        }
    }
    
    /**
     * 获取key值
     * @param prex
     * @return
     */
    public Set<String> getSetPrex(String prex) {
    	return redisTemplate.keys(prex);
    }
    
    /**
     * 判断key是否存在
     * @param key
     * @return
     */
    public boolean isExitKey(String key) {
    	return redisTemplate.hasKey(key);
    }
    
    
    /**
     * 统计数量
     * @param prex
     * @return
     */
    public int getCountPrex(String prex) {
    	return redisTemplate.keys(prex).size();
    }

//--------------------set开始-----------------------------------------------------------------------------    
    /**
              * 获取set数据
     * @param key
     * @return
     */
    public Set<Object> getSet(String key){
    	return redisTemplateGroup.opsForSet().members(key);
    }
    
    /**
          * 获取set集合的个数
     * @param key
     * @return
     */
    public Long getSetCount(String key) {
    	return redisTemplateGroup.opsForSet().size(key);
    }
    /**
     * 单条set添加
     * @param key
     * @param ojbSet
     */
    public void addSet(String key,Object objSet) {
    	redisTemplateGroup.opsForSet().add(key,objSet);
    }
    
    /**
     *   添加set数据
     * @param key
     * @param ojbSet
     */
    public void addSet(String key,Set<Object> objSet) {
    	redisTemplateGroup.opsForSet().add(key, objSet);
    }
    
    /**
     * 判断是否存在
     * @param key
     * @param value
     * @return
     */
    public boolean contains(String key,Object value) {
    	return redisTemplateGroup.opsForSet().isMember(key, value);
    }
    
    
    /**
     * 判断是否包含某个元素
     * @param key
     * @param value
     */
    public boolean contains(String key,String name, Object value) {
    	  logger.info("判断是否包含key:{},name:{},value:{}",key,name,value);
    	  String lua="--接收的key\r\n" + 
    	  		"local setKey=KEYS[1]\r\n" + 
    	  		"--判断接收的字段名称\r\n" + 
    	  		"local setName = ARGV[1]\r\n" + 
    	  		"--判断接收的数据\r\n" + 
    	  		"local setValue= ARGV[2]\r\n" + 
    	  		"print(setKey..' '..setName..' '..setValue)\r\n" + 
    	  		"local userGroup=redis.call('SMEMBERS',setKey);\r\n" + 
    	  		"if next(userGroup) ~=nil then\r\n" + 
    	  		"   for i=1,#userGroup\r\n" + 
    	  		"    do\r\n" + 
    	  		"      print('for:'..userGroup[i]);\r\n" + 
    	  		"	  local userTable=cjson.decode(userGroup[i])\r\n" + 
    	  		"	  print(userTable[2].userName)\r\n" + 
    	  		"	  --pairs先按顺序输出值，然后再按键值对的hash顺序输出键值对\r\n" + 
    	  		"      --ipairs只会按照顺序输出值，若下标是nil值(也可以理解为下标不连续)则中断。\r\n" + 
    	  		"	  for key, value in pairs(userTable[2])\r\n" + 
    	  		"	    do\r\n" + 
    	  		"		     print(tostring(key)..':'..tostring(value))\r\n" + 
    	  		"		 if string.gsub(setName, '\"', '')==key and string.gsub(setValue, '\"', '')==value then\r\n" + 
    	  		"			 return 1\r\n" + 
    	  		"		 end\r\n" + 
    	  		"		end\r\n" + 
    	  		"		\r\n" + 
    	  		"    end\r\n" + 
    	  		"else\r\n" + 
    	  		" print('取数为空') \r\n" + 
    	  		" return 0 \r\n" + 
    	  		"end\r\n" + 
    	  		"return 0";
    	// 指定 lua 脚本，并且指定返回值类型
          DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(lua,Long.class);
          // 参数一：redisScript，参数二：key列表，参数三：arg（可多个）
          return new Long(1).equals(redisTemplate.execute(redisScript, Collections.singletonList(key),name.toString(),value.toString()));
    }
    
    /**
     * 移除set数据
     * @param key
     * @param value
     */
    public void removeSet(String key,Object value) {
    	redisTemplateGroup.opsForSet().remove(key, value);
    }
    
    /**
          * 下线删除群组里面的用户信息
     * @param key
     * @param value
     */
    public void delGroupUser(String key,Object name,Object value) {
    	  logger.info("删除无序集合key:{},name:{},value:{}",key,name,value);
      
    	String lua="--接收的key\r\n" + 
    			"local setKey=KEYS[1]\r\n" + 
    			"--判断接收的字段名称\r\n" + 
    			"local setName = ARGV[1]\r\n" + 
    			"--判断接收的数据\r\n" + 
    			"local setValue= ARGV[2]\r\n" + 
    			//"print(setKey..' '..string.gsub(setName, '\"', '')..' '..string.gsub(setValue, '\"', ''))\r\n"+
    			//"print(setKey..' '..tostring(setName)..' '..tostring(setValue))\r\n"+
    			"local userGroup=redis.call('SMEMBERS',setKey);\r\n" + 
    			"if next(userGroup) ~=nil then\r\n" + 
    			"   for i=1,#userGroup\r\n" + 
    			"    do\r\n" + 
    			"      print('for:'..userGroup[i]);\r\n" + 
    			"	  local userTable=cjson.decode(userGroup[i])\r\n" + 
    			"	  print(userTable[2].userName)\r\n" + 
    			"	  \r\n" + 
    			"	  --pairs先按顺序输出值，然后再按键值对的hash顺序输出键值对\r\n" + 
    			"      --ipairs只会按照顺序输出值，若下标是nil值(也可以理解为下标不连续)则中断。\r\n" + 
    			"	  for key, value in pairs(userTable[2])\r\n" + 
    			"	    do\r\n" + 
    			"		    print(tostring(key)..':'..tostring(value))\r\n" + 
    			"		 if string.gsub(setName, '\"', '')==tostring(key) and string.gsub(setValue, '\"', '')==tostring(value) then\r\n" + 
    			"			 redis.call('SREM',setKey,userGroup[i]);\r\n" + 
    			"		 end\r\n" + 
    			"		end\r\n" + 
    			"    end\r\n" + 
    			"	\r\n" + 
//    			"   local i=1\r\n" + 
//    			"   while(i<=#userGroup)\r\n" + 
//    			"	do\r\n" + 
//    			"	 print('while:'..userGroup[i]);\r\n" + 
//    			"     i=i+1\r\n" + 
//    			"    end\r\n" + 
    			"else\r\n" + 
    			" print('取数为空')  \r\n" + 
    			"end\r\n" + 
    			"return 1";
    	// 指定 lua 脚本，并且指定返回值类型
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(lua,Long.class);
        // 参数一：redisScript，参数二：key列表，参数三：arg（可多个）
        Long result = redisTemplate.execute(redisScript, Collections.singletonList(key),name.toString(),value.toString());
    }
    
//--------------------set结束-----------------------------------------------------------------------------    
//--------------------zset开始----------------------------------------------------------------------------
    public void addZset(String key,String value,double score) {
    	redisTemplateGroup.opsForZSet().add(key, value, score);
    }
    
    public void delZset(String key,String... values) {
    	redisTemplateGroup.opsForZSet().remove(key, values);
    }
    
    public Set<String> getAllServer(String key) {
    	Set<TypedTuple<Object>>serverSet=redisTemplateGroup.opsForZSet().rangeWithScores(key, 0, -1);
    	Set<String> serverIP=new HashSet<String>();
    	for(TypedTuple<Object> t:serverSet) {
    		serverIP.add(t.getValue().toString());
    	}
    	return serverIP;
    }
    
    public void increZset(String key,String value,double score) {
    	redisTemplateGroup.opsForZSet().incrementScore(key, value, score);
    }
    
    /**
          *获取最小的值
     * @param key
     * @return
     */
    public String getServer(String key,int incryBY) {
    	Set<TypedTuple<Object>> serverMinSet= redisTemplateGroup.opsForZSet().rangeWithScores(key, 0, -1);
    	if(null!=serverMinSet) {
    		Iterator<TypedTuple<Object>> iterator = serverMinSet.iterator();
    		if(iterator.hasNext()) {
    			TypedTuple<Object> min=iterator.next();
    			redisTemplateGroup.opsForZSet().incrementScore(key,min.getValue() ,incryBY);
    			return (String) min.getValue();
    		}
    	}
    	return "";
    }

	/**
	 * 随机值
	 * @param key
	 * @return
	 */
	public String getRandomServer(String key, int incryBY) {
        String serverIP=redisTemplateGroup.opsForSet().randomMember(key).toString();
        redisTemplateGroup.opsForZSet().incrementScore(key, serverIP, incryBY);
		return serverIP;
	}
    
    
	/**
	 * 排序操作
	 * @param query
	 * @return
	 */
	public List<Object> sort(SortQuery query) {
		return redisTemplate.sort(query);
	}
//--------------------zset结束----------------------------------------------------------------------------    
    /**
     * map类型数据
     * @param key
     * @param value
     */
    public void addHashMap(String key,Map<String,Object> value) {
    	redisTemplateString.opsForHash().putAll(key, value);
    }
    
    /**
     * map类型数据添加
     * @param key
     * @param value
     */
    public void addHashMap(String key,String mapKey,Object value) {
    	if(redisTemplateString.opsForHash().hasKey(key, mapKey)) {
     	   redisTemplateString.opsForHash().put(key, mapKey,value);
    	}
    }
    
    
    /**
     * map数据值自增长1
     * @param mapKey
     * @param key
     */
    public void addHashMapVlaue(String mapKey,String key) {
    	redisTemplateString.opsForHash().increment(mapKey, key, 1);
    }
    
    /**
             * 判断Map是否存在
     * @param key
     * @param keyMap
     * @return
     */
    public boolean isHashMap(String key,String keyMap) {
    	return redisTemplateString.opsForHash().hasKey(key, keyMap);
    }
    
    /**
             * 删除map的key
     * @param key
     * @param keyMap
     * @return
     */
    public long removeMap(String key,String keyMap) {
    	return redisTemplateString.opsForHash().delete(key, keyMap);
    }
    
    /**
             * 获取map数据
     * @param key
     * @return
     */
    public Map<Object,Object> getHashMapKeys(String key){
    	return redisTemplateString.opsForHash().entries(key);
    }
    
    /**
     * 获取hashMap内容
     * @param key
     * @param mapKey
     * @return
     */
    public Object getHshMapValue(String key,String mapKey) {
       return redisTemplateString.opsForHash().get(key, mapKey);
    }
    
    /**
             * 发布消息
     * @param msg
     */
    public void SendMsg(Message msg) {
    	redisTemplate.convertAndSend(RedisPre.SEND_MSG,msg);
    }
    
    /**
     * 为json串
     * @return
     */
    public List<String> getAllUpUser(){
    	String lua="local userList={}\r\n" + 
                "local index=1\r\n"+
    			//"local red = redis:new()\r\n"+
    			"local userGroup=redis.call('KEYS','"+RedisPre.DB_USER+"*');\r\n" + 
    			"if next(userGroup) ~=nil then\r\n" + 
    			"   for i=1,#userGroup\r\n" + 
    			"    do\r\n" + 
    			"      print('for:'..userGroup[i]);\r\n" + 
    			"	  local currentStatu=string.gsub(redis.call(\"HGET\",userGroup[i],\"userStatus\"), '\"', '');\r\n" + 
    			"	  print(currentStatu)\r\n" + 
    			"	  if ('1'==currentStatu or '2'==currentStatu) then\r\n" + 
    			//"	     print('for2:'..redis.call(\"HGETALL\",userGroup[i]));\r\n" + 
    			"		 print(type(redis.call(\"HGETALL\",userGroup[i])))\r\n" + 
    			"        local flat_map = redis.call(\"HGETALL\",userGroup[i])\r\n" + 
    			"		 print(#flat_map)\r\n" + 
    			"        local result = {}\r\n" + 
    			"        	for j = 1, #flat_map, 2 do\r\n" + 
    			"              result[flat_map[j]] = flat_map[j + 1]\r\n" + 
    			"           end\r\n"+
    			//"		 print(result)\r\n" + 
    			//"	     table.insert(userList,result);\r\n" + 
    			"        userList[index]=cjson.encode(result)\r\n"+
    			"        index=index+1\r\n"+
    			"      end\r\n" + 
    			"	end  \r\n" + 
    			"end\r\n" + 
    			"return userList";
    	// 指定 lua 脚本，并且指定返回值类型
        DefaultRedisScript<List> redisScript = new DefaultRedisScript<>(lua,List.class);
        // 参数一：redisScript，参数二：key列表，参数三：arg（可多个）
        List<String> result = redisTemplateString.execute(redisScript,new ArrayList());
        return result;
    }
    
    /**
             * 监听发送消息
     * @param str
     * @throws IOException 
     */
	/*
	 * public void chatMsg(String str) throws IOException {
	 * 
	 * if(!StringUtil.isNUll(str)) { logger.info("获取数据:"+str); ObjectMapper mapper =
	 * new ObjectMapper(); mapper.setSerializationInclusion(Include.NON_NULL);
	 * //设置输入时忽略JSON字符串中存在而Java对象实际没有的属性
	 * mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
	 * Message message = mapper.readValue(str, Message.class);
	 * if(ChannelManager.isExitChannel(message.getAccept())) {
	 * ChatSendUtil.getChatSend(message); } }
	 * 
	 * }
	 */
    /**
     * 添加存活时间
     * @param key
     * @param secordTime
     */
    public void expireKey(String key,int timeout) {
    	redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
    }
    
    public static void main(String[] args) throws JsonMappingException, JsonProcessingException {
		//String str="{\"@class\":\"com.pingpang.websocketchat.Message\",\"cmd\":\"3\",\"from\":{\"@class\":\"com.pingpang.websocketchat.ChartUser\",\"id\":null,\"userCode\":\"fhx\",\"userName\":null,\"userEmail\":null,\"userPhone\":null,\"userImagePath\":null,\"userPassword\":null,\"userSex\":null,\"userStatus\":null,\"userCreateDate\":null,\"ip\":null},\"accept\":{\"@class\":\"com.pingpang.websocketchat.ChartUser\",\"id\":null,\"userCode\":\"jz\",\"userName\":null,\"userEmail\":null,\"userPhone\":null,\"userImagePath\":null,\"userPassword\":null,\"userSex\":null,\"userStatus\":null,\"userCreateDate\":null,\"ip\":null},\"group\":null,\"msg\":\"ddd\",\"status\":null,\"id\":null,\"createDate\":\"2020-05-26 14:57:06\",\"chatSet\":null,\"groupSet\":null}";
		
		String str="{\"cmd\":\"3\",\"from\":{\"id\":null,\"userCode\":\"fhx\",\"userName\":null,\"userEmail\":null,\"userPhone\":null,\"userImagePath\":null,\"userPassword\":null,\"userSex\":null,\"userStatus\":null,\"userCreateDate\":null,\"ip\":null},\"accept\":{\"id\":null,\"userCode\":\"jz\",\"userName\":null,\"userEmail\":null,\"userPhone\":null,\"userImagePath\":null,\"userPassword\":null,\"userSex\":null,\"userStatus\":null,\"userCreateDate\":null,\"ip\":null},\"group\":null,\"msg\":\"ddd\",\"status\":null,\"id\":null,\"createDate\":\"2020-05-26 14:57:06\",\"chatSet\":null,\"groupSet\":null}";

		ObjectMapper mapper = new ObjectMapper();
   		//将类名称序列化到json串中，去掉会导致得出来的的是LinkedHashMap对象，直接转换实体对象会失败
   		mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL); 	    //设置输入时忽略JSON字符串中存在而Java对象实际没有的属性
   		//mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		Message message = mapper.readValue(str, Message.class);
		System.out.println(message);
		}
}
