/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.reflection.impl;

import java.util.AbstractSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import net.ranides.assira.generic.HashUtils;
import net.ranides.assira.reflection.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class AHints implements IHints {

    public static final AHints EMPTY = new NULLHints();

    private Set<IAttribute> require;
    
    private Set<IAttribute> discard;

    AHints(Set<IAttribute> require, Set<IAttribute> discard) {
        this.require = require;
        this.discard = discard;
    }
    
    @Override
    public Set<IAttribute> require() {
        return require;
    }
    
    @Override
    public IHints require(IAttribute attr) {
        require.add(attr);
        return this;
    }
    
    @Override
    public IHints require(Set<IAttribute> attrs) {
        require.addAll(attrs);
        return this;
    }

    @Override
    public Set<IAttribute> discard() {
        return discard;
    }
    
    @Override
    public IHints discard(IAttribute attr) {
        discard.add(attr);
        return this;
    }
    
    @Override
    public IHints discard(Set<IAttribute> attrs) {
        discard.addAll(attrs);
        return this;
    }

    @Override
    public IHints replace(IHints value) {
        require = value.require();
        discard = value.discard();
        return this;
    }
    
    public boolean hintAny() {
        return 
            require.contains(IAttribute.ANY) ||
            require.contains(IAttribute.PRIVATE) ||
            require.contains(IAttribute.PROTECTED) ||
            require.contains(IAttribute.PACKAGE) ||
            discard.contains(IAttribute.PUBLIC);
    }
    
    public boolean hintDeclared() {
        return require.contains(IAttribute.DECLARED);
    }

    @Override
    public int hashCode() {
        return HashUtils.hashPair(require,discard);
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }
        if (!(object instanceof IHints)) {
            return false;
        }
        AHints that = (AHints) object;
        return this.require().equals(that.require()) && this.discard().equals(that.discard());
    }
    
    @Override
    public String toString() {
        return "AHints{" + "require=" + require + ", discard=" + discard + '}';
    }
    
    private static final class NULLSet extends AbstractSet<IAttribute> {
        @Override
        public Iterator<IAttribute> iterator() {
            return Collections.emptyIterator();
        }

        @Override
        public int size() {
            return 0;
        }

        @Override
        public boolean remove(Object o) {
            return false;
        }

        @Override
        public boolean add(IAttribute e) {
            return false;
        }
    }

    private static final class NULLHints extends AHints {

        public NULLHints() {
            super(new NULLSet(), new NULLSet());
        }
        
        @Override
        public IHints replace(IHints value) {
            return this;
        }
        
    }
}
