/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.shardingsphere.core.strategy.encrypt;

import com.google.common.base.Optional;
import org.apache.shardingsphere.api.config.encryptor.EncryptRuleConfiguration;
import org.apache.shardingsphere.api.config.encryptor.EncryptorRuleConfiguration;
import org.apache.shardingsphere.spi.encrypt.ShardingEncryptor;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Set;

/**
 * Sharding encryptor engine.
 *
 * @author panjuan
 */
public final class ShardingEncryptorEngine {
    
    private final Collection<ShardingEncryptorStrategy> shardingEncryptorStrategies = new LinkedList<>();
    
    public ShardingEncryptorEngine(final EncryptRuleConfiguration encryptRuleConfiguration) {
        for (EncryptorRuleConfiguration each : encryptRuleConfiguration.getEncryptorRuleConfigs()) {
            shardingEncryptorStrategies.add(new ShardingEncryptorStrategy(each));
        }
    }
    
    /**
     * Get sharding encryptor.
     * 
     * @param logicTableName logic table name
     * @param columnName column name
     * @return optional of sharding encryptor
     */
    public Optional<ShardingEncryptor> getShardingEncryptor(final String logicTableName, final String columnName) {
        for (ShardingEncryptorStrategy each : shardingEncryptorStrategies) {
            Optional<ShardingEncryptor> result = each.getShardingEncryptor(logicTableName, columnName);
            if (result.isPresent()) {
                return result;
            }
        }
        return Optional.absent();
    }
    
    /**
     * Is has sharding query assisted encryptor or not.
     * 
     * @param logicTableName logic table name
     * @return has sharding query assisted encryptor or not
     */
    public boolean isHasShardingQueryAssistedEncryptor(final String logicTableName) {
        for (ShardingEncryptorStrategy each : shardingEncryptorStrategies) {
            if (each.isHasShardingQueryAssistedEncryptor(logicTableName)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * Get assisted query column.
     * 
     * @param logicTableName logic table name
     * @param columnName column name
     * @return assisted query column
     */
    public Optional<String> getAssistedQueryColumn(final String logicTableName, final String columnName) {
        for (ShardingEncryptorStrategy each : shardingEncryptorStrategies) {
            Optional<String> result = each.getAssistedQueryColumn(logicTableName, columnName);
            if (result.isPresent()) {
                return result;
            }
        }
        return Optional.absent();
    }
    
    /**
     * Get assisted query column count.
     * 
     * @param logicTableName logic table name
     * @return assisted query column count
     */
    public Optional<Integer> getAssistedQueryColumnCount(final String logicTableName) {
        for (ShardingEncryptorStrategy each : shardingEncryptorStrategies) {
            Optional<Integer> result = each.getAssistedQueryColumnCount(logicTableName);
            if (result.isPresent()) {
                return result;
            }
        }
        return Optional.absent();
    }
    
    /**
     * Get encrypt table names.
     *
     * @return encrypt table names
     */
    public Collection<String> getEncryptTableNames() {
        Set<String> result = new LinkedHashSet<>();
        for (ShardingEncryptorStrategy each : shardingEncryptorStrategies) {
            result.addAll(each.getEncryptTableNames());
        }
        return result;
    }
}

@@ -1177,19 +1177,19 @@
 nkedHash
-Set
+Map
 ;%0Aimport
@@ -1205,20 +1205,73 @@
 l.Linked
-List
+HashSet;%0Aimport java.util.Map;%0Aimport java.util.Map.Entry
 ;%0Aimport
@@ -1415,27 +1415,28 @@
 e final 
-Collection%3C
+Map%3CString, 
 Sharding
@@ -1498,12 +1498,15 @@
 nked
-List
+HashMap
 %3C%3E()
@@ -1619,16 +1619,30 @@
    for (
+Entry%3CString, 
 Encrypto
@@ -1659,16 +1659,17 @@
 guration
+%3E
  each : 
@@ -1718,16 +1718,27 @@
 onfigs()
+.entrySet()
 ) %7B%0A    
@@ -1777,12 +1777,27 @@
 ies.
-add(
+put(each.getKey(), 
 new 
@@ -1826,16 +1826,27 @@
 egy(each
+.getValue()
 ));%0A    
@@ -2227,32 +2227,41 @@
 ryptorStrategies
+.values()
 ) %7B%0A            
@@ -2827,32 +2827,41 @@
 ryptorStrategies
+.values()
 ) %7B%0A            
@@ -3360,32 +3360,41 @@
 ryptorStrategies
+.values()
 ) %7B%0A            
@@ -3920,32 +3920,41 @@
 ryptorStrategies
+.values()
 ) %7B%0A            
@@ -4438,16 +4438,25 @@
 rategies
+.values()
 ) %7B%0A    

use Map<String, ShardingEncryptorStrategy>