/*
 * Licensed 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 com.facebook.presto.hive;

import com.facebook.presto.spi.PrestoException;
import com.facebook.presto.spi.StandardErrorCode;
import com.facebook.presto.spi.session.PropertyMetadata;
import com.facebook.presto.spi.type.TypeManager;
import com.google.common.collect.ImmutableList;

import javax.inject.Inject;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.facebook.presto.spi.session.PropertyMetadata.integerSessionProperty;
import static com.facebook.presto.spi.type.StandardTypes.ARRAY;
import static com.facebook.presto.spi.type.VarcharType.createUnboundedVarcharType;
import static java.util.Locale.ENGLISH;

public class HiveTableProperties
{
    public static final String STORAGE_FORMAT_PROPERTY = "format";
    public static final String PARTITIONED_BY_PROPERTY = "partitioned_by";
    public static final String CLUSTERED_BY_PROPERTY = "clustered_by";
    public static final String BUCKET_COUNT_PROPERTY = "bucket_count";

    private final List<PropertyMetadata<?>> tableProperties;

    @Inject
    public HiveTableProperties(TypeManager typeManager, HiveClientConfig config)
    {
        tableProperties = ImmutableList.of(
                new PropertyMetadata<>(
                        STORAGE_FORMAT_PROPERTY,
                        "Hive storage format for the table",
                        createUnboundedVarcharType(),
                        HiveStorageFormat.class,
                        config.getHiveStorageFormat(),
                        false,
                        value -> HiveStorageFormat.valueOf(((String) value).toUpperCase(ENGLISH)),
                        HiveStorageFormat::toString),
                new PropertyMetadata<>(
                        PARTITIONED_BY_PROPERTY,
                        "Partition columns",
                        typeManager.getParameterizedType(ARRAY, ImmutableList.of(createUnboundedVarcharType().getTypeSignature()), ImmutableList.of()),
                        List.class,
                        ImmutableList.of(),
                        false,
                        value -> ImmutableList.copyOf(((Collection<?>) value).stream()
                                .map(name -> ((String) name).toLowerCase(ENGLISH))
                                .collect(Collectors.toList())),
                        value -> value),
                new PropertyMetadata<>(
                        CLUSTERED_BY_PROPERTY,
                        "Bucketing columns",
                        typeManager.getParameterizedType(ARRAY, ImmutableList.of(createUnboundedVarcharType().getTypeSignature()), ImmutableList.of()),
                        List.class,
                        ImmutableList.of(),
                        false,
                        value -> ImmutableList.copyOf(((Collection<?>) value).stream()
                                .map(name -> ((String) name).toLowerCase(ENGLISH))
                                .collect(Collectors.toList())),
                        value -> value),
                integerSessionProperty(BUCKET_COUNT_PROPERTY, "Number of buckets", 0, false));
    }

    public List<PropertyMetadata<?>> getTableProperties()
    {
        return tableProperties;
    }

    public static HiveStorageFormat getHiveStorageFormat(Map<String, Object> tableProperties)
    {
        return (HiveStorageFormat) tableProperties.get(STORAGE_FORMAT_PROPERTY);
    }

    public static List<String> getPartitionedBy(Map<String, Object> tableProperties)
    {
        return (List<String>) tableProperties.get(PARTITIONED_BY_PROPERTY);
    }

    public static Optional<HiveBucketProperty> getBucketProperty(Map<String, Object> tableProperties)
    {
        List<String> clusteredBy = (List<String>) tableProperties.get(CLUSTERED_BY_PROPERTY);
        int bucketCount = (Integer) tableProperties.get(BUCKET_COUNT_PROPERTY);
        if ((clusteredBy.isEmpty()) && (bucketCount == 0)) {
            return Optional.empty();
        }
        if (bucketCount < 0) {
            throw new PrestoException(StandardErrorCode.INVALID_TABLE_PROPERTY, BUCKET_COUNT_PROPERTY + " must be greater than zero");
        }
        if (clusteredBy.isEmpty() || bucketCount == 0) {
            throw new PrestoException(StandardErrorCode.INVALID_TABLE_PROPERTY, CLUSTERED_BY_PROPERTY + " and " + BUCKET_COUNT_PROPERTY + " must appear at the same time");
        }
        return Optional.of(new HiveBucketProperty(clusteredBy, bucketCount));
    }
}

@@ -642,58 +642,8 @@
 on;%0A
-import com.facebook.presto.spi.StandardErrorCode;%0A
 impo
@@ -960,16 +960,96 @@
 ctors;%0A%0A
+import static com.facebook.presto.spi.StandardErrorCode.INVALID_TABLE_PROPERTY;%0A
 import s
@@ -1174,27 +1174,40 @@
 ype.
-StandardTypes.ARRAY
+TypeSignature.parseTypeSignature
 ;%0Aim
@@ -1287,16 +1287,55 @@
 arType;%0A
+import static java.lang.String.format;%0A
 import s
@@ -2561,117 +2561,48 @@
 .get
-ParameterizedType(ARRAY, ImmutableList.of(createUnboundedVarcharType().getTypeSignature()), ImmutableList.of(
+Type(parseTypeSignature(%22array(varchar)%22
 )),%0A
@@ -3162,117 +3162,48 @@
 .get
-ParameterizedType(ARRAY, ImmutableList.of(createUnboundedVarcharType().getTypeSignature()), ImmutableList.of(
+Type(parseTypeSignature(%22array(varchar)%22
 )),%0A
@@ -3973,32 +3973,67 @@
 OPERTY);%0A    %7D%0A%0A
+    @SuppressWarnings(%22unchecked%22)%0A
     public stati
@@ -4337,64 +4337,38 @@
 y = 
-(List%3CString%3E) tableProperties.get(CLUSTERED_BY_PROPERTY
+getClusteredBy(tableProperties
 );%0A 
@@ -4623,34 +4623,16 @@
 ception(
-StandardErrorCode.
 INVALID_
@@ -4651,33 +4651,18 @@
 TY, 
-BUCKET_COUNT_PROPERTY + %22
+format(%22%25s
  mus
@@ -4684,16 +4684,40 @@
 an zero%22
+, BUCKET_COUNT_PROPERTY)
 );%0A     
@@ -4816,34 +4816,16 @@
 ception(
-StandardErrorCode.
 INVALID_
@@ -4839,16 +4839,63 @@
 ROPERTY,
+ format(%22%25s and %25s must be specified together%22,
  CLUSTER
@@ -4912,20 +4912,9 @@
 ERTY
- + %22 and %22 +
+,
  BUC
@@ -4935,42 +4935,9 @@
 ERTY
- + %22 must appear at the same time%22
+)
 );%0A 
@@ -5028,11 +5028,217 @@
 );%0A    %7D
+%0A%0A    @SuppressWarnings(%22unchecked%22)%0A    private static List%3CString%3E getClusteredBy(Map%3CString, Object%3E tableProperties)%0A    %7B%0A        return (List%3CString%3E) tableProperties.get(CLUSTERED_BY_PROPERTY);%0A    %7D
 %0A%7D%0A

Fix warnings in HiveTableProperties