/*
 * 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.metastore;

import com.facebook.presto.spi.security.Privilege;
import com.facebook.presto.spi.security.PrivilegeInfo;
import com.google.common.collect.ImmutableSet;
import org.apache.hadoop.hive.metastore.api.PrivilegeGrantInfo;

import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.facebook.presto.hive.metastore.HivePrivilegeInfo.HivePrivilege.DELETE;
import static com.facebook.presto.hive.metastore.HivePrivilegeInfo.HivePrivilege.INSERT;
import static com.facebook.presto.hive.metastore.HivePrivilegeInfo.HivePrivilege.OWNERSHIP;
import static com.facebook.presto.hive.metastore.HivePrivilegeInfo.HivePrivilege.SELECT;
import static com.facebook.presto.hive.metastore.HivePrivilegeInfo.HivePrivilege.UPDATE;
import static com.google.common.base.MoreObjects.toStringHelper;
import static java.util.Locale.ENGLISH;
import static java.util.Objects.requireNonNull;

public class HivePrivilegeInfo
{
    public enum HivePrivilege
    {
        SELECT, INSERT, UPDATE, DELETE, OWNERSHIP
    }

    private final HivePrivilege hivePrivilege;
    private final boolean grantOption;

    public HivePrivilegeInfo(HivePrivilege hivePrivilege, boolean grantOption)
    {
        this.hivePrivilege = requireNonNull(hivePrivilege, "hivePrivilege is null");
        this.grantOption = grantOption;
    }

    public HivePrivilege getHivePrivilege()
    {
        return hivePrivilege;
    }

    public boolean isGrantOption()
    {
        return grantOption;
    }

    public static Set<HivePrivilegeInfo> parsePrivilege(PrivilegeGrantInfo userGrant)
    {
        boolean withGrantOption = userGrant.isGrantOption();
        String name = userGrant.getPrivilege().toUpperCase(ENGLISH);
        switch (name) {
            case "ALL":
                return ImmutableSet.copyOf(Arrays.stream(HivePrivilege.values())
                        .map(hivePrivilege -> new HivePrivilegeInfo(hivePrivilege, withGrantOption))
                        .collect(Collectors.toSet()));
            case "SELECT":
                return ImmutableSet.of(new HivePrivilegeInfo(SELECT, withGrantOption));
            case "INSERT":
                return ImmutableSet.of(new HivePrivilegeInfo(INSERT, withGrantOption));
            case "UPDATE":
                return ImmutableSet.of(new HivePrivilegeInfo(UPDATE, withGrantOption));
            case "DELETE":
                return ImmutableSet.of(new HivePrivilegeInfo(DELETE, withGrantOption));
            case "OWNERSHIP":
                return ImmutableSet.of(new HivePrivilegeInfo(OWNERSHIP, withGrantOption));
            default:
                throw new IllegalArgumentException("Unsupported privilege name: " + name);
        }
    }

    public static HivePrivilege toHivePrivilege(Privilege privilege)
    {
        switch (privilege) {
            case SELECT:
                return SELECT;
            case INSERT:
                return INSERT;
            case DELETE:
                return DELETE;
            case UPDATE:
                return UPDATE;
            default:
                throw new IllegalArgumentException("Unexpected privilege: " + privilege);
        }
    }

    public boolean isContainedIn(HivePrivilegeInfo hivePrivilegeInfo)
    {
        return (getHivePrivilege().equals(hivePrivilegeInfo.getHivePrivilege()) &&
                (isGrantOption() == hivePrivilegeInfo.isGrantOption() ||
                        (!isGrantOption() && hivePrivilegeInfo.isGrantOption())));
    }

    public Set<PrivilegeInfo> toPrivilegeInfo()
    {
        switch (hivePrivilege) {
            case SELECT:
                return ImmutableSet.of(new PrivilegeInfo(Privilege.SELECT, isGrantOption()));
            case INSERT:
                return ImmutableSet.of(new PrivilegeInfo(Privilege.INSERT, isGrantOption()));
            case DELETE:
                return ImmutableSet.of(new PrivilegeInfo(Privilege.DELETE, isGrantOption()));
            case UPDATE:
                return ImmutableSet.of(new PrivilegeInfo(Privilege.UPDATE, isGrantOption()));
            case OWNERSHIP:
                return ImmutableSet.copyOf(Arrays.stream(Privilege.values())
                        .map(privilege -> new PrivilegeInfo(privilege, Boolean.TRUE))
                        .collect(Collectors.toSet()));
            default:
                throw new IllegalArgumentException("Unsupported hivePrivilege: " + hivePrivilege);
        }
    }

    @Override
    public int hashCode()
    {
        return Objects.hash(hivePrivilege, grantOption);
    }

    @Override
    public boolean equals(Object o)
    {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        HivePrivilegeInfo hivePrivilegeInfo = (HivePrivilegeInfo) o;
        return Objects.equals(hivePrivilege, hivePrivilegeInfo.hivePrivilege) &&
                Objects.equals(grantOption, hivePrivilegeInfo.grantOption);
    }

    @Override
    public String toString()
    {
        return toStringHelper(this)
                .add("privilege", hivePrivilege)
                .add("grantOption", grantOption)
                .toString();
    }
}

@@ -1747,388 +1747,8 @@
 n;%0A%0A
-    public HivePrivilegeInfo(HivePrivilege hivePrivilege, boolean grantOption)%0A    %7B%0A        this.hivePrivilege = requireNonNull(hivePrivilege, %22hivePrivilege is null%22);%0A        this.grantOption = grantOption;%0A    %7D%0A%0A    public HivePrivilege getHivePrivilege()%0A    %7B%0A        return hivePrivilege;%0A    %7D%0A%0A    public boolean isGrantOption()%0A    %7B%0A        return grantOption;%0A    %7D%0A%0A
     
@@ -3408,32 +3408,412 @@
        %7D%0A    %7D%0A%0A
+    public HivePrivilegeInfo(HivePrivilege hivePrivilege, boolean grantOption)%0A    %7B%0A        this.hivePrivilege = requireNonNull(hivePrivilege, %22hivePrivilege is null%22);%0A        this.grantOption = grantOption;%0A    %7D%0A%0A    public HivePrivilege getHivePrivilege()%0A    %7B%0A        return hivePrivilege;%0A    %7D%0A%0A    public boolean isGrantOption()%0A    %7B%0A        return grantOption;%0A    %7D%0A%0A
     public boole

Reorder methods in HivePrivilegeInfo