ModuleInfoBuilder.java

package autumn.lang.internals;

import autumn.lang.Delegate;
import autumn.lang.Module;
import autumn.lang.ModuleInfo;
import autumn.lang.annotations.Start;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * Instances of this class are used to construct ModuleInfo objects.
 *
 * @author Mackenzie High
 */
public final class ModuleInfoBuilder
{
    private final Module instance;

    private final ArrayList<Class> annotations = Lists.newArrayList();

    private final ArrayList<Class> exceptions = Lists.newArrayList();

    private final ArrayList<Class> enums = Lists.newArrayList();

    private final ArrayList<Class> designs = Lists.newArrayList();

    private final ArrayList<Class> structs = Lists.newArrayList();

    private final ArrayList<Class> tuples = Lists.newArrayList();

    private final ArrayList<Class> functors = Lists.newArrayList();

    private final ArrayList<Delegate> delegates = Lists.newArrayList();

    /**
     * Sole Constructor.
     *
     * @param instance is the module object itself.
     */
    public ModuleInfoBuilder(final Module instance)
    {
        Preconditions.checkNotNull(instance);

        this.instance = instance;
    }

    /**
     * This method declares that an annotation-type is defined directly within the module.
     *
     * @param type is the type.
     */
    public void addAnnotation(final Class type)
    {
        Preconditions.checkNotNull(type);

        annotations.add(type);
    }

    /**
     * This method declares that an exception-type is defined directly within the module.
     *
     * @param type is the type.
     */
    public void addException(final Class type)
    {
        Preconditions.checkNotNull(type);

        exceptions.add(type);
    }

    /**
     * This method declares that an enum-type is defined directly within the module.
     *
     * @param type is the type.
     */
    public void addEnum(final Class type)
    {
        Preconditions.checkNotNull(type);

        enums.add(type);
    }

    /**
     * This method declares that a design-type is defined directly within the module.
     *
     * @param type is the type.
     */
    public void addDesign(final Class type)
    {
        Preconditions.checkNotNull(type);

        designs.add(type);
    }

    /**
     * This method declares that a struct-type is defined directly within the module.
     *
     * @param type is the type.
     */
    public void addStruct(final Class type)
    {
        Preconditions.checkNotNull(type);

        structs.add(type);
    }

    /**
     * This method declares that a tuple-type is defined directly within the module.
     *
     * @param type is the type.
     */
    public void addTuple(final Class type)
    {
        Preconditions.checkNotNull(type);

        tuples.add(type);
    }

    /**
     * This method declares that a functor-type is defined directly within the module.
     *
     * @param type is the type.
     */
    public void addFunctor(final Class type)
    {
        Preconditions.checkNotNull(type);

        functors.add(type);
    }

    /**
     * This method declares that a function is defined directly within the module.
     *
     * @param delegate refers to the function.
     */
    public void add(final Delegate delegate)
    {
        Preconditions.checkNotNull(delegate);

        delegates.add(delegate);
    }

    /**
     * This method creates a ModuleInfo object based on the information that was provided to this builder.
     *
     * @return the newly created object.
     */
    public ModuleInfo build()
    {
        final ModuleInfoBuilder SELF = this;

        /**
         * TODO: This should be static in order to avoid holding onto the builder.
         */
        return new ModuleInfo()
        {
            private final List<Class> annotations = Collections.unmodifiableList(SELF.annotations);

            private final List<Class> exceptions = Collections.unmodifiableList(SELF.exceptions);

            private final List<Class> enums = Collections.unmodifiableList(SELF.enums);

            private final List<Class> designs = Collections.unmodifiableList(SELF.designs);

            private final List<Class> structs = Collections.unmodifiableList(SELF.structs);

            private final List<Class> tuples = Collections.unmodifiableList(SELF.tuples);

            private final List<Class> functors = Collections.unmodifiableList(SELF.functors);

            private final List<Delegate> delegates = Collections.unmodifiableList(SELF.delegates);

            @Override
            public Module instance()
            {
                return instance;
            }

            @Override
            public String name()
            {
                return type().getName();
            }

            @Override
            public Class type()
            {
                return instance().getClass();
            }

            @Override
            public List<Class> annotations()
            {
                return annotations;
            }

            @Override
            public List<Class> enums()
            {
                return enums;
            }

            @Override
            public List<Class> exceptions()
            {
                return exceptions;
            }

            @Override
            public List<Class> designs()
            {
                return designs;
            }

            @Override
            public List<Class> tuples()
            {
                return tuples;
            }

            @Override
            public List<Class> structs()
            {
                return structs;
            }

            @Override
            public List<Class> functors()
            {
                return functors;
            }

            @Override
            public List<Delegate> functions()
            {
                return delegates;
            }

            @Override
            public boolean isStart()
            {
                for (Delegate x : functions())
                {
                    final boolean test1 = x.method().isAnnotationPresent(Start.class);

                    final boolean test2 = test1 && x.name().equals("main");

                    final boolean test3 = test1 && x.parameterTypes().equals(Lists.newArrayList(String[].class));

                    final boolean test4 = test1 && x.returnType().equals(void.class);

                    if (test1 && test2 && test3 && test4)
                    {
                        return true;
                    }
                }

                return false;
            }

            @Override
            public Set<Class> types()
            {
                final Set<Class> result = Sets.newIdentityHashSet();

                result.addAll(annotations());
                result.addAll(designs());
                result.addAll(enums());
                result.addAll(exceptions());
                result.addAll(functors());
                result.addAll(structs());
                result.addAll(tuples());

                return Collections.unmodifiableSet(result);
            }

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