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

package net.ranides.assira.reflection.impl.bean;

import net.ranides.assira.generic.Wrappers;
import net.ranides.assira.generic.Wrappers.AbstractWrapper;
import net.ranides.assira.reflection.*;

/**
 * Abstract base class for BeanProperty implementations.
 *
 * Stores information about type and name.
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public abstract class ABeanProperty implements BeanProperty {
    
    private final IClass<?> type;
    private final String name;

    protected ABeanProperty(IClass<?> type, String name) {
        this.type = type;
        this.name = name;
    }

    @Override
    public String name() {
        return name;
    }

    @Override
    public IClass<?> type() {
        return type;
    }

    @Override
    public BeanPropertyBinding<Object> bind(Object that) {
        return new RBinding(that);
    }
    
    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    public <T> BeanPropertyBinding<T> $bind(Object that) {
        return (BeanPropertyBinding)new RBinding(that);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T $get(Object that) {
        return (T)get(that);
    }

    @Override
    public Object replace(Object that, Object value) {
        Object prv = isReadable() ? get(that) : null;
        set(that, value);
        return prv;
    }

    private class RBinding implements BeanPropertyBinding<Object>, AbstractWrapper<Object> {
        
        private final Object that;

        public RBinding(Object that) {
            this.that = that;
        }

        @Override
        public Object object() {
            return that;
        }

        @Override
        public String name() {
            return ABeanProperty.this.name();
        }

        @Override
        public boolean isReadable() {
            return ABeanProperty.this.isReadable();
        }

        @Override
        public boolean isWritable() {
            return ABeanProperty.this.isWritable();
        }

        @Override
        public Object get() {
            return ABeanProperty.this.get(that);
        }

        @Override
        public void set(Object value) {
            ABeanProperty.this.set(that, value);
        }

        @Override
        public Object replace(Object value) {
            return ABeanProperty.this.replace(that, value);
        }

        @Override
        public IClass<?> type() {
            return ABeanProperty.this.type();
        }

        @Override
        public IClass<?> parent() {
            return ABeanProperty.this.parent();
        }
    }

}
