package com.zzsn.cache;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.whalin.MemCached.MemCachedClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * memcached
 *
 * @Author Sugar
 * @Version 2018/3/15 16:44
 */
public class MemcachedUtils {
    public final static int DEFAULT_EXPIRES = 3600*24*10; //默认过期时间（秒）
    private final static Logger logger = LoggerFactory.getLogger(MemcachedUtils.class);

    /**
     * 缓存数据(默认缓存1小时)
     *
     * @param key
     * @param data
     */
    public static void put(String key, Object data) {
        put(key, data, DEFAULT_EXPIRES);
    }

    /**
     * 缓存数据
     *
     * @param key
     * @param data
     * @param seconds 过期时间（秒）
     */
    public static void put(String key, Object data, int seconds) {
        try {
            Memcached.getClient().setWithNoReply(key, seconds, data);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 缓存对象（默认缓存1小时）
     *
     * @param key
     * @param value <T>
     */
    public static <T> void putObject(String key, T value) {
        putObject(key, value, DEFAULT_EXPIRES);
    }

    /**
     * 缓存对象
     *
     * @param key
     * @param value
     * @param seconds 缓存时间（秒）
     */
    public static <T> void putObject(String key, T value, int seconds) {
        try {
            byte[] data = null;
            if (value instanceof Map) {
                data = JSONObject.toJSONBytes(value, SerializerFeature.DisableCircularReferenceDetect);
            } else if(value instanceof Iterable) {
                data = JSONArray.toJSONBytes(value, SerializerFeature.DisableCircularReferenceDetect);
            } else {
                data = ProtostuffUtil.serializer(value);
            }
            put(key, data, seconds);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 缓存对象（默认缓存1小时）
     *
     * @param key
     * @param value
     * @return
     */
    public static void putList(String key, List value) {
        setList(key, value, DEFAULT_EXPIRES);
    }

    /**
     * 缓存对象
     *
     * @param key
     * @param value
     * @param seconds 缓存时间（秒）
     * @return
     */
    public static <T> void putList(String key, List<T> value, int seconds) {
        try {
            T obj = value.get(0);
            if (obj instanceof Map) {
                put(key, JSONArray.toJSONBytes(value), seconds);
            } else {
                Class<?> type = obj.getClass();
                if (type.isArray() || type.getTypeName().startsWith("java.lang")) {
                    put(key, value, seconds);
                } else {
                    put(key, ProtostuffUtil.serializeList(value), seconds);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 缓存数据
     *
     * @param key
     * @param data
     * @param seconds 过期时间（秒）
     * @return
     */
    public static boolean set(String key, Object data, int seconds) {
        try {
            return Memcached.getClient().set(key, seconds, data);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return false;
        }
    }

    /**
     * 缓存对象（默认缓存1小时）
     *
     * @param key
     * @param value <T>
     * @return
     */
    public static <T> boolean setObject(String key, T value) {
        return setObject(key, value, DEFAULT_EXPIRES);
    }

    /**
     * 缓存对象
     *
     * @param key
     * @param value
     * @param seconds 缓存时间（秒）
     * @return
     */
    public static <T> boolean setObject(String key, T value, int seconds) {
        try {
            byte[] data = null;
            if (value instanceof Map) {
                data = JSONObject.toJSONBytes(value, SerializerFeature.DisableCircularReferenceDetect);
            } else if(value instanceof Iterable) {
                data = JSONArray.toJSONBytes(value, SerializerFeature.DisableCircularReferenceDetect);
            } else {
                data = ProtostuffUtil.serializer(value);
            }
            return set(key, data, seconds);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return false;
    }

    /**
     * 缓存对象（默认缓存1小时）
     *
     * @param key
     * @param value
     * @return
     */
    public static boolean setList(String key, List value) {
        return setList(key, value, DEFAULT_EXPIRES);
    }

    /**
     * 缓存对象
     *
     * @param key
     * @param value
     * @param seconds 缓存时间（秒）
     * @return
     */
    public static <T> boolean setList(String key, List<T> value, int seconds) {
        try {
            T obj = value.get(0);
            if (obj instanceof Map) {
                return set(key, JSONArray.toJSONBytes(value), seconds);
            } else {
                Class<?> type = obj.getClass();
                if (type.isArray() || type.getTypeName().startsWith("java.lang")) {
                    return set(key, value, seconds);
                } else {
                    return set(key, ProtostuffUtil.serializeList(value), seconds);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return false;
    }

    /**
     * 读取缓存数据
     *
     * @param key
     * @return
     */
    public static <T> T get(String key) {
        try {
            return Memcached.getClient().get(key);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取对象值
     *
     * @param key
     * @param clazz <T>
     * @return
     */
    public static <T> T getObject(String key, Class<T> clazz) {
        byte[] bytes = get(key);
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        try {
            //如果数据是json格式{}
            if (clazz.isAssignableFrom(Map.class) || (bytes.length > 0 && bytes[0] == 123 && bytes[bytes.length - 1] == 125)) {
                return JSONObject.parseObject(bytes, clazz);
            }
            return ProtostuffUtil.deserializer(bytes, clazz);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取列表
     *
     * @param key
     * @return
     */
    public static <T> List<T> getList(String key, Class<T> clazz) {
        try {
            if (clazz.isAssignableFrom(Map.class)) {
                byte[] data = get(key);
                if (data == null || data.length == 0) {
                    return null;
                }
                return JSONArray.parseObject(data, List.class);
            } else if (clazz.isArray() || clazz.getTypeName().startsWith("java.lang")) {
                return get(key);
            } else {
                byte[] data = get(key);
                if (data == null || data.length == 0) {
                    return null;
                }
                return ProtostuffUtil.deserializeList(data, clazz);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取String值
     *
     * @param key
     * @return 不存在返回空字符串
     */
    public static String getString(String key) {
        String val = get(key);
        return val == null ? "" : val;
    }

    /**
     * 读取int值
     *
     * @param key
     * @return 不存在返回0
     */
    public static int getInt(String key) {
        Integer val = get(key);
        return val == null ? 0 : val.intValue();
    }

    /**
     * 读取long值
     *
     * @param key
     * @return 不存在返回0
     */
    public static long getLong(String key) {
        Long val = get(key);
        return val == null ? 0 : val.longValue();
    }

    /**
     * 读取float值
     *
     * @param key
     * @return 不存在返回0
     */
    public static float getFloat(String key) {
        Float val = get(key);
        return val == null ? 0 : val.floatValue();
    }

    /**
     * 读取double值
     *
     * @param key
     * @return 不存在返回0
     */
    public static double getDouble(String key) {
        Double val = get(key);
        return val == null ? 0 : val.doubleValue();
    }

    /**
     * 读取boolean值
     *
     * @param key
     * @return 不存在返回false
     */
    public static boolean getBoolean(String key) {
        Boolean val = get(key);
        return val == null ? false : val.booleanValue();
    }

    /**
     * 将存储在键上的数字+1
     *
     * @param key
     * @return 成功返回新的结果, 失败返回null
     */
    public static Long incrAndGet(String key) {
        return incrAndGet(key, 1);
    }

    /**
     * 将存储在键上的数字按指定的值增加
     *
     * @param key
     * @param value 增加的值
     * @return 成功返回新的结果, 失败返回null
     */
    public static Long incrAndGet(String key, long value) {
        try {
            return Memcached.getClient().incr(key, value);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 将存储在键上的数字+1
     *
     * @param key
     */
    public static void incr(String key) {
        incr(key, 1);
    }

    /**
     * 将存储在键上的数字按指定的值增加
     *
     * @param key
     * @param value 增加的值
     */
    public static void incr(String key, long value) {
        try {
            Memcached.getClient().incrWithNoReply(key, value);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 将存储在键上的数字-1
     *
     * @param key
     * @return 成功返回新的结果, 失败返回null
     */
    public static Long decrAngGet(String key) {
        return decrAngGet(key, 1);
    }

    /**
     * 将存储在键上的数字按指定的值减少
     *
     * @param key
     * @param value 减少的值
     * @return 成功返回新的结果, 失败返回null
     */
    public static Long decrAngGet(String key, long value) {
        try {
            return Memcached.getClient().decr(key, value);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 将存储在键上的数字-1
     *
     * @param key
     */
    public static void decr(String key) {
        decr(key, 1);
    }

    /**
     * 将存储在键上的数字按指定的值减少
     *
     * @param key
     * @param value 减少的值
     */
    public static void decr(String key, long value) {
        try {
            Memcached.getClient().decrWithNoReply(key, value);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param seconds
     * @return
     */
    public static boolean expire(String key, int seconds) {
        try {
            return Memcached.getClient().touch(key, seconds);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return false;
        }
    }

    /**
     * 清空所有key
     *
     * @return
     */
    public static void flushAll() {
        try {
            Memcached.getClient().flushAll();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }
    /**
     * 删除指定key
     *
     * @return
     */
    public static void del(String key) {
        try {
            Memcached.getClient().delete(key);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }
    /**
     * 删除指定多个key
     *
     * @return
     */
    public static void del(String... keys) {
        try {
            for (String key : keys) {
                Memcached.getClient().delete(key);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 判断key是否存在
     *
     * @param key
     * @return boolean
     */
    public static boolean exists(String key) {
        try {
            return Memcached.getClient().get(key) != null;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return false;
        }
    }

    public static List<String> getAllKeys(MemCachedClient mcc) {
        List<String> list = new ArrayList<String>();
        Map<String, Map<String, String>> items = mcc.statsItems();
        for (Iterator<String> itemIt = items.keySet().iterator(); itemIt.hasNext();) {
            String itemKey = itemIt.next();
            Map<String, String> maps = items.get(itemKey);
            for (Iterator<String> mapsIt = maps.keySet().iterator(); mapsIt.hasNext();) {
                String mapsKey = mapsIt.next();
                String mapsValue = maps.get(mapsKey);
                if (mapsKey.endsWith("number")) { // memcached key 类型
                    // item_str:integer:number_str
                    String[] arr = mapsKey.split(":");
                    int slabNumber = Integer.valueOf(arr[1].trim());
                    int limit = Integer.valueOf(mapsValue.trim());
                    Map<String, Map<String, String>> dumpMaps = mcc.statsCacheDump(slabNumber,
                            limit);
                    for (Iterator<String> dumpIt = dumpMaps.keySet().iterator(); dumpIt
                            .hasNext();) {
                        String dumpKey = dumpIt.next();
                        Map<String, String> allMap = dumpMaps.get(dumpKey);
                        for (Iterator<String> allIt = allMap.keySet().iterator(); allIt
                                .hasNext();) {
                            String allKey = allIt.next();
                            list.add(allKey.trim());
                        }
                    }
                }
            }
        }
        return list;
    }

    public static void main(String[] args) {
        MemcachedUtils.put("lwg","liuweigang1",30);
        MemcachedUtils.put("lwg","liuweigang2",30);
        Object lwg = MemcachedUtils.get("lwg1");
        System.out.println(lwg.toString());



    }
}
