package com.ctrip.framework.dal.cluster.client.sharding.strategy;

import com.ctrip.framework.dal.cluster.client.exception.ClusterRuntimeException;

import java.util.HashSet;
import java.util.Set;

/**
 * @author c7ch23en
 */
public class ModShardStrategy extends ColumnShardStrategy implements ShardStrategy {

    protected static final String DB_SHARD_MOD = "dbShardMod";
    protected static final String TABLE_SHARD_MOD = "tableShardMod";

    public ModShardStrategy() {}

    @Override
    protected Integer calcDbShard(String tableName, Object shardValue) {
        Integer mod = getDbShardMod(tableName);
        if (mod == null)
            throw new ClusterRuntimeException(String.format("db shard mod undefined for table '%s'", tableName));
        return getModResult(mod, shardValue);
    }

    @Override
    protected String calcTableShard(String tableName, Object shardValue) {
        Integer mod = getTableShardMod(tableName);
        if (mod == null)
            throw new ClusterRuntimeException(String.format("table shard mod undefined for table '%s'", tableName));
        return String.valueOf(getModResult(mod, shardValue));
    }

    @Override
    protected Set<String> calcAllTableShards(String tableName) {
        Integer mod = getTableShardMod(tableName);
        if (mod == null)
            throw new ClusterRuntimeException(String.format("table shard mod undefined for table '%s'", tableName));
        Set<String> allShards = new HashSet<>();
        for (int i = 0; i < mod; i++)
            allShards.add(String.valueOf(i));
        return allShards;
    }

    protected Integer getDbShardMod(String tableName) {
        return getTableIntProperty(tableName, DB_SHARD_MOD);
    }

    protected Integer getTableShardMod(String tableName) {
        return getTableIntProperty(tableName, TABLE_SHARD_MOD);
    }

    protected int getModResult(int mod, Object shardValue) {
        long longValue = getLongValue(shardValue);
        return (int) (longValue % mod);
    }

    protected Long getLongValue(Object value) {
        if (value instanceof Long)
            return (Long) value;
        if (value instanceof Number)
            return ((Number) value).longValue();
        if (value instanceof String)
            return Long.parseLong((String) value);
        throw new ClusterRuntimeException(String.format("value [%s] cannot be parsed as a valid number", value.toString()));
    }

}

@@ -142,16 +142,57 @@
 ption;%0A%0A
+import java.lang.annotation.ElementType;%0A
 import j
@@ -479,16 +479,163 @@
 dMod%22;%0A%0A
+    protected static final String STRING_TYPE_HANDLER = %22stringTypeHandler%22;%0A    protected static final String STRING_TYPE_HANDLER_HASH = %22hash%22;%0A%0A
     publ
@@ -2427,16 +2427,18 @@
  String)
+ %7B
 %0A       
@@ -2453,13 +2453,8 @@
 urn 
-Long.
 pars
@@ -2472,24 +2472,34 @@
 ng) value);%0A
+        %7D%0A
         thro
@@ -2618,10 +2618,392 @@
 %0A    %7D%0A%0A
+    protected long parseLong(String value) %7B%0A        String stringTypeHandler = getProperty(STRING_TYPE_HANDLER);%0A        if (STRING_TYPE_HANDLER_HASH.equalsIgnoreCase(stringTypeHandler))%0A            return hash(value);%0A        else%0A            return Long.parseLong(value);%0A    %7D%0A%0A    protected long hash(String value) %7B%0A        return value.hashCode() & Integer.MAX_VALUE;%0A    %7D%0A%0A
 %7D%0A

support hash mod strategy for varchar column