/*
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.io.uri;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Set;
import net.ranides.assira.collection.sets.MaskFactory;
import net.ranides.assira.collection.sets.MaskSet;

/**
 * This type defines all operations which can be supported by {@link URIHandle}.
 *
 * @see URIHandle#flags()
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public enum URIFlags {

    /**
     * URI can be used for reading.
     * It should support method like "istream", "reader" and "content".
     * Please note, that "istream(offset)" is supported only if handler reports SEEK
     */
    READABLE    (0x0000_0001),
    /**
     * URI can be used for writing.
     * It should support method like "ostream", "writer".
     */
    WRITABLE    (0x0000_0002),
    /**
     * URI points to file with "executable" attribute.
     * At this moment there is no support for execution by URI.
     */
    EXECUTE     (0x0000_0004),
    /**
     * URI points to existing resource (local file, FTP file, HTTP resource).
     */
    EXISTS      (0x0000_0008),
    /**
     * URI points to directory
     */
    DIR         (0x0000_0010),
    /**
     * URI points to ordinary file
     */
    FILE        (0x0000_0020),
    /**
     * URI points to text file (most probably with defined charset)
     */
    TEXT        (0x0000_0040),
    /**
     * URI points to binary file (or text file with undefined charset)
     */
    BINARY      (0x0000_0080),
    /**
     * URI resource has well defined size in bytes
     */
    SIZE        (0x0000_0100),
    /**
     * URI resource supports opening input stream at specified offset
     */
    SEEK        (0x0000_0200),
    ;
    
    private static final MaskFactory<URIFlags> MAP = new MaskFactory<>(URIFlags.values(), a -> a.mask);
    
    private final int mask;

    URIFlags(int mask) {
        this.mask = mask;
    }

    /**
     * Returns true, if provided handle supports feature described by this enum.
     *
     * @param handle handle
     * @return boolean
     * @throws IOException on error
     */
    public boolean matches(URIHandle handle) throws IOException {
        return handle.flags().contains(this);
    }

    /**
     * Returns immutable MaskSet with no features at all
     *
     * @return mask
     */
    public static MaskSet<URIFlags> empty() {
        return MAP.empty();
    }

    /**
     * Returns mutable set with specified features.
     *
     * @param flags flags
     * @return mask
     */
    public static MaskSet<URIFlags> collect(URIFlags... flags) {
        return MAP.collect(flags);
    }

    /**
     * Returns immutable set with specified features.
     *
     * @param flags flags
     * @return mask
     */
    public static MaskSet<URIFlags> constant(URIFlags... flags) {
        return MAP.constant(flags);
    }

    /**
     * Returns new mutable set with the same features as in provided set.
     *
     * @param flags flags
     * @return mask
     */
    public static MaskSet<URIFlags> clone(Set<URIFlags> flags) {
        return MAP.clone(flags);
    }
    
}
