// 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 com.cloud.storage;

import org.apache.commons.lang.NotImplementedException;

import java.util.ArrayList;
import java.util.List;

public class Storage {
    public static enum ImageFormat {
        QCOW2(true, true, false, "qcow2"),
        RAW(false, false, false, "raw"),
        VHD(true, true, true, "vhd"),
        ISO(false, false, false, "iso"),
        OVA(true, true, true, "ova"),
        VHDX(true, true, true, "vhdx"),
        BAREMETAL(false, false, false, "BAREMETAL"),
        VMDK(true, true, false, "vmdk"),
        VDI(true, true, false, "vdi"),
        TAR(false, false, false, "tar"),
        ZIP(false, false, false, "zip"),
        DIR(false, false, false, "dir");

        private final boolean supportThinProvisioning;
        private final boolean supportSparse;
        private final boolean supportSnapshot;
        private final String fileExtension;

        private ImageFormat(boolean supportThinProvisioning, boolean supportSparse, boolean supportSnapshot) {
            this.supportThinProvisioning = supportThinProvisioning;
            this.supportSparse = supportSparse;
            this.supportSnapshot = supportSnapshot;
            fileExtension = null;
        }

        private ImageFormat(boolean supportThinProvisioning, boolean supportSparse, boolean supportSnapshot, String fileExtension) {
            this.supportThinProvisioning = supportThinProvisioning;
            this.supportSparse = supportSparse;
            this.supportSnapshot = supportSnapshot;
            this.fileExtension = fileExtension;
        }

        public boolean supportThinProvisioning() {
            return supportThinProvisioning;
        }

        public boolean supportsSparse() {
            return supportSparse;
        }

        public boolean supportSnapshot() {
            return supportSnapshot;
        }

        public String getFileExtension() {
            if (fileExtension == null)
                return toString().toLowerCase();

            return fileExtension;
        }

    }

    public static enum Capability {
        HARDWARE_ACCELERATION("HARDWARE_ACCELERATION"),
        ALLOW_MIGRATE_OTHER_POOLS("ALLOW_MIGRATE_OTHER_POOLS");

        private final String capability;

        private Capability(String capability) {
            this.capability = capability;
        }

        public String toString() {
            return this.capability;
        }
    }

    public static enum ProvisioningType {
        THIN("thin"),
        SPARSE("sparse"),
        FAT("fat");

        private final String provisionType;

        private ProvisioningType(String provisionType){
            this.provisionType = provisionType;
        }

        public String toString(){
            return this.provisionType;
        }

        public static ProvisioningType getProvisioningType(String provisioningType){

            if(provisioningType.equals(THIN.provisionType)){
                return ProvisioningType.THIN;
            } else if(provisioningType.equals(SPARSE.provisionType)){
                return ProvisioningType.SPARSE;
            } else if (provisioningType.equals(FAT.provisionType)){
                return ProvisioningType.FAT;
            } else{
                    throw new NotImplementedException();
            }
        }
    }

    public static enum FileSystem {
        Unknown, ext3, ntfs, fat, fat32, ext2, ext4, cdfs, hpfs, ufs, hfs, hfsp
    }

    public static enum TemplateType {
        ROUTING, // Router template
        SYSTEM, /* routing, system vm template */
        BUILTIN, /* buildin template */
        PERHOST, /* every host has this template, don't need to install it in secondary storage */
        USER, /* User supplied template/iso */
        VNF,    /* VNFs (virtual network functions) template */
        DATADISK, /* Template corresponding to a datadisk(non root disk) present in an OVA */
        ISODISK /* Template corresponding to a iso (non root disk) present in an OVA */
    }

    public enum EncryptionSupport {
        /**
         * Encryption not supported.
         */
        Unsupported,
        /**
         * Will use hypervisor encryption driver (qemu -> luks)
         */
        Hypervisor,
        /**
         * Storage pool handles encryption and just provides an encrypted volume
         */
        Storage
    }

    /**
     * StoragePoolTypes carry some details about the format and capabilities of a storage pool. While not necessarily a
     * 1:1 with PrimaryDataStoreDriver (and for KVM agent, KVMStoragePool and StorageAdaptor) implementations, it is
     * often used to decide which storage plugin or storage command to call, so it may be necessary for new storage
     * plugins to add a StoragePoolType.  This can be done by adding it below, or by creating a new public static final
     * instance of StoragePoolType in the plugin itself, which registers it with the map.
     *
     * Note that if the StoragePoolType is for KVM and defined in plugin code rather than below, care must be taken to
     * ensure this is available on the agent side as well. This is best done by defining the StoragePoolType in a common
     * package available on both management server and agent plugin jars.
     */
    public static enum StoragePoolType {
        Filesystem(false, true, EncryptionSupport.Hypervisor), // local directory
        NetworkFilesystem(true, true, EncryptionSupport.Hypervisor), // NFS
        IscsiLUN(true, false, EncryptionSupport.Unsupported), // shared LUN, with a clusterfs overlay
        Iscsi(true, false, EncryptionSupport.Unsupported), // for e.g., ZFS Comstar
        ISO(false, false, EncryptionSupport.Unsupported), // for iso image
        LVM(false, false, EncryptionSupport.Unsupported), // XenServer local LVM SR
        CLVM(true, false, EncryptionSupport.Unsupported),
        RBD(true, true, EncryptionSupport.Unsupported), // http://libvirt.org/storage.html#StorageBackendRBD
        SharedMountPoint(true, true, EncryptionSupport.Hypervisor),
        VMFS(true, true, EncryptionSupport.Unsupported), // VMware VMFS storage
        PreSetup(true, true, EncryptionSupport.Unsupported), // for XenServer, Storage Pool is set up by customers.
        EXT(false, true, EncryptionSupport.Unsupported), // XenServer local EXT SR
        OCFS2(true, false, EncryptionSupport.Unsupported),
        SMB(true, false, EncryptionSupport.Unsupported),
        Gluster(true, false, EncryptionSupport.Unsupported),
        PowerFlex(true, true, EncryptionSupport.Hypervisor), // Dell EMC PowerFlex/ScaleIO (formerly VxFlexOS)
        ManagedNFS(true, false, EncryptionSupport.Unsupported),
        Linstor(true, true, EncryptionSupport.Storage),
        DatastoreCluster(true, true, EncryptionSupport.Unsupported), // for VMware, to abstract pool of clusters
        StorPool(true, true, EncryptionSupport.Hypervisor),
        FiberChannel(true, true, EncryptionSupport.Unsupported); // Fiber Channel Pool for KVM hypervisors is used to find the volume by WWN value (/dev/disk/by-id/wwn-<wwnvalue>)

        private final boolean shared;
        private final boolean overProvisioning;
        private final EncryptionSupport encryption;

        StoragePoolType(boolean shared, boolean overProvisioning, EncryptionSupport encryption) {
            this.shared = shared;
            this.overProvisioning = overProvisioning;
            this.encryption = encryption;
        }

        public boolean isShared() {
            return shared;
        }

        public boolean supportsOverProvisioning() {
            return overProvisioning;
        }

        public boolean supportsEncryption() {
            return encryption == EncryptionSupport.Hypervisor || encryption == EncryptionSupport.Storage;
        }

        public EncryptionSupport encryptionSupportMode() {
            return encryption;
        }
    }

    public static List<StoragePoolType> getNonSharedStoragePoolTypes() {
        List<StoragePoolType> nonSharedStoragePoolTypes = new ArrayList<>();
        for (StoragePoolType storagePoolType : StoragePoolType.values()) {
            if (!storagePoolType.isShared()) {
                nonSharedStoragePoolTypes.add(storagePoolType);
            }
        }
        return nonSharedStoragePoolTypes;

    }

    public static enum StorageResourceType {
        STORAGE_POOL, STORAGE_HOST, SECONDARY_STORAGE, LOCAL_SECONDARY_STORAGE
    }
}
