/**
 * This file is part of Everit - Component Metadata.
 *
 * Everit - Component Metadata is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Everit - Component Metadata is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Everit - Component Metadata.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.everit.osgi.ecm.metadata;

import java.util.Objects;

import org.everit.osgi.ecm.util.method.MethodDescriptor;

public abstract class ReferenceMetadata extends AttributeMetadata<String> {
    public abstract static class ReferenceMetadataBuilder<B extends ReferenceMetadataBuilder<B>> extends
            AttributeMetadataBuilder<String, B> {

        private MethodDescriptor bind = null;

        private ReferenceConfigurationType referenceConfigurationType = ReferenceConfigurationType.FILTER;

        private String referenceId = null;

        @Override
        protected void beforeBuild() {
            Objects.requireNonNull(referenceId, "Reference id must be specified");
            String attributeId = getAttributeId();

            if (attributeId == null) {
                if (ReferenceConfigurationType.CLAUSE.equals(referenceConfigurationType)) {
                    withAttributeId(referenceId + ".clause");
                } else {
                    withAttributeId(referenceId + ".target");
                }
            }
        }

        public MethodDescriptor getBind() {
            return bind;
        }

        public ReferenceConfigurationType getReferenceConfigurationType() {
            return referenceConfigurationType;
        }

        public String getReferenceId() {
            return referenceId;
        }

        @Override
        public Class<String> getValueType() {
            return String.class;
        }

        public B withBind(final MethodDescriptor bind) {
            this.bind = bind;
            return self();
        }

        public B withReferenceConfigurationType(
                final ReferenceConfigurationType referenceConfigurationType) {

            this.referenceConfigurationType = referenceConfigurationType;
            return self();
        }

        public B withReferenceId(final String referenceId) {
            this.referenceId = referenceId;
            return self();
        }

    }

    /**
     * The bind method that should be used to bind the reference. If the annotation is defined on a method, that method
     * and it is not specified otherwise in the annotation, the method will be used as a bind method. If the annotation
     * is attached to a field and the bind method is not defined in the annotation and there is method that has the same
     * name as the field but prefixed with "bind" that method will be used as a bind method. In case there is no bind
     * method but there is a setter for the field, it will be used to set the property.
     */
    private final MethodDescriptor bind;

    private final ReferenceConfigurationType referenceConfigurationType;

    private final String referenceId;

    protected <B extends ReferenceMetadataBuilder<B>> ReferenceMetadata(final ReferenceMetadataBuilder<B> builder) {
        super(builder);
        bind = builder.bind;
        referenceId = builder.referenceId;
        referenceConfigurationType = builder.referenceConfigurationType;
    }

    public MethodDescriptor getBind() {
        return bind;
    }

    public ReferenceConfigurationType getReferenceConfigurationType() {
        return referenceConfigurationType;
    }

    public String getReferenceId() {
        return referenceId;
    }
}

@@ -1158,20 +1158,22 @@
 criptor 
-bind
+setter
  = null;
@@ -1868,36 +1868,38 @@
 odDescriptor get
-Bind
+Setter
 () %7B%0A           
@@ -1902,28 +1902,30 @@
      return 
-bind
+setter
 ;%0A        %7D%0A
@@ -2272,20 +2272,22 @@
 c B with
-Bind
+Setter
 (final M
@@ -2302,20 +2302,22 @@
 criptor 
-bind
+setter
 ) %7B%0A    
@@ -2333,19 +2333,23 @@
 his.
-bind = bind
+setter = setter
 ;%0A  
@@ -3393,20 +3393,22 @@
 criptor 
-bind
+setter
 ;%0A%0A    p
@@ -3664,20 +3664,22 @@
         
-bind
+setter
  = build
@@ -3681,20 +3681,22 @@
 builder.
-bind
+setter
 ;%0A      
@@ -3847,12 +3847,14 @@
  get
-Bind
+Setter
 () %7B
@@ -3869,20 +3869,22 @@
  return 
-bind
+setter
 ;%0A    %7D%0A

Refactor to use setter instead of bind in references