/*
 *  Copyright 2001-present Stephen Colebourne
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.joda.beans.sample;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;

import org.joda.beans.Bean;
import org.joda.beans.ImmutableBean;
import org.joda.beans.JodaBeanUtils;
import org.joda.beans.MetaBean;
import org.joda.beans.MetaProperty;
import org.joda.beans.gen.BeanDefinition;
import org.joda.beans.gen.PropertyDefinition;
import org.joda.beans.impl.direct.DirectFieldsBeanBuilder;
import org.joda.beans.impl.direct.DirectMetaBean;
import org.joda.beans.impl.direct.DirectMetaProperty;
import org.joda.beans.impl.direct.DirectMetaPropertyMap;

import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableSortedMultiset;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multiset;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.SortedMultiset;
import com.google.common.collect.Table;

/**
 * Mock JavaBean, used for testing.
 * 
 * @author Stephen Colebourne
 */
@BeanDefinition(builderScope = "public", constructorScope = "public")
public final class ImmGuava<T extends Comparable<T>> implements ImmutableBean {

    @PropertyDefinition(validate = "notNull")
    private final ImmutableCollection<T> collection;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableList<T> list;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableSet<T> set;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableSortedSet<T> sortedSet;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableMap<T, String> map;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableSortedMap<T, String> sortedMap;

    @PropertyDefinition(validate = "notNull")
    private final ImmutableBiMap<T, String> biMap;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableMultimap<T, String> multimap;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableListMultimap<T, String> listMultimap;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableSetMultimap<T, String> setMultimap;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableMultiset<T> multiset;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableSortedMultiset<T> sortedMultiset;

    @PropertyDefinition(validate = "notNull")
    private final Collection<T> collectionInterface;
    @PropertyDefinition(validate = "notNull")
    private final List<T> listInterface;
    @PropertyDefinition(validate = "notNull")
    private final Set<T> setInterface;
    @PropertyDefinition(validate = "notNull")
    private final SortedSet<T> sortedSetInterface;
    @PropertyDefinition(validate = "notNull")
    private final Map<T, String> mapInterface;
    @PropertyDefinition(validate = "notNull")
    private final SortedMap<T, String> sortedMapInterface;

    @PropertyDefinition(validate = "notNull")
    private final BiMap<T, String> biMapInterface;
    @PropertyDefinition(validate = "notNull")
    private final Multimap<T, String> multimapInterface;
    @PropertyDefinition(validate = "notNull")
    private final ListMultimap<T, String> listMultimapInterface;
    @PropertyDefinition(validate = "notNull")
    private final SetMultimap<T, String> setMultimapInterface;
    @PropertyDefinition(validate = "notNull")
    private final Multiset<T> multisetInterface;
    @PropertyDefinition(validate = "notNull")
    private final SortedMultiset<T> sortedMultisetInterface;

    @PropertyDefinition(validate = "notNull")
    private final ImmutableList<? extends T> listWildExtendsT;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableList<? extends Number> listWildExtendsNumber;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableList<? extends Comparable<?>> listWildExtendsComparable;

    @PropertyDefinition(validate = "notNull")
    private final ImmutableSet<? extends T> setWildExtendsT;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableSet<? extends Number> setWildExtendsNumber;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableSet<? extends Comparable<?>> setWildExtendsComparable;

//    @PropertyDefinition(validate = "notNull")
//    private final ArrayListMultimap<T, String> listMultimapArray;
//    @PropertyDefinition(validate = "notNull")
//    private final LinkedListMultimap<T, String> listMultimapLinked;
//    @PropertyDefinition(validate = "notNull")
//    private final HashMultimap<T, String> setMultimapHash;
//    @PropertyDefinition(validate = "notNull")
//    private final LinkedHashMultimap<T, String> setMultimapLinkedHash;


    @PropertyDefinition(validate = "notNull", builderType = "List<?>")
    private final ImmutableList<Object> listWildBuilder1;
    @PropertyDefinition(validate = "notNull", builderType = "List<? extends Address>")
    private final ImmutableList<Address> listWildBuilder2;
    @PropertyDefinition(validate = "notNull", builderType = "Map<String, ? extends Address>")
    private final ImmutableMap<String, Address> mapWildBuilder1;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableMap<? extends Number, String> mapWildKey;
    @PropertyDefinition(validate = "notNull")
    private final ImmutableTable<String, Integer, String> table;

    //------------------------- AUTOGENERATED START -------------------------
    /**
     * The meta-bean for {@code ImmGuava}.
     * @return the meta-bean, not null
     */
    @SuppressWarnings("rawtypes")
    public static ImmGuava.Meta meta() {
        return ImmGuava.Meta.INSTANCE;
    }

    /**
     * The meta-bean for {@code ImmGuava}.
     * @param <R>  the bean's generic type
     * @param cls  the bean's generic type
     * @return the meta-bean, not null
     */
    @SuppressWarnings("unchecked")
    public static <R extends Comparable<R>> ImmGuava.Meta<R> metaImmGuava(Class<R> cls) {
        return ImmGuava.Meta.INSTANCE;
    }

    static {
        MetaBean.register(ImmGuava.Meta.INSTANCE);
    }

    /**
     * Returns a builder used to create an instance of the bean.
     * @param <T>  the type
     * @return the builder, not null
     */
    public static <T extends Comparable<T>> ImmGuava.Builder<T> builder() {
        return new ImmGuava.Builder<>();
    }

    /**
     * Creates an instance.
     * @param collection  the value of the property, not null
     * @param list  the value of the property, not null
     * @param set  the value of the property, not null
     * @param sortedSet  the value of the property, not null
     * @param map  the value of the property, not null
     * @param sortedMap  the value of the property, not null
     * @param biMap  the value of the property, not null
     * @param multimap  the value of the property, not null
     * @param listMultimap  the value of the property, not null
     * @param setMultimap  the value of the property, not null
     * @param multiset  the value of the property, not null
     * @param sortedMultiset  the value of the property, not null
     * @param collectionInterface  the value of the property, not null
     * @param listInterface  the value of the property, not null
     * @param setInterface  the value of the property, not null
     * @param sortedSetInterface  the value of the property, not null
     * @param mapInterface  the value of the property, not null
     * @param sortedMapInterface  the value of the property, not null
     * @param biMapInterface  the value of the property, not null
     * @param multimapInterface  the value of the property, not null
     * @param listMultimapInterface  the value of the property, not null
     * @param setMultimapInterface  the value of the property, not null
     * @param multisetInterface  the value of the property, not null
     * @param sortedMultisetInterface  the value of the property, not null
     * @param listWildExtendsT  the value of the property, not null
     * @param listWildExtendsNumber  the value of the property, not null
     * @param listWildExtendsComparable  the value of the property, not null
     * @param setWildExtendsT  the value of the property, not null
     * @param setWildExtendsNumber  the value of the property, not null
     * @param setWildExtendsComparable  the value of the property, not null
     * @param listWildBuilder1  the value of the property, not null
     * @param listWildBuilder2  the value of the property, not null
     * @param mapWildBuilder1  the value of the property, not null
     * @param mapWildKey  the value of the property, not null
     * @param table  the value of the property, not null
     */
    public ImmGuava(
            Collection<T> collection,
            List<T> list,
            Set<T> set,
            SortedSet<T> sortedSet,
            Map<T, String> map,
            SortedMap<T, String> sortedMap,
            BiMap<T, String> biMap,
            Multimap<T, String> multimap,
            ListMultimap<T, String> listMultimap,
            SetMultimap<T, String> setMultimap,
            Multiset<T> multiset,
            SortedMultiset<T> sortedMultiset,
            Collection<T> collectionInterface,
            List<T> listInterface,
            Set<T> setInterface,
            SortedSet<T> sortedSetInterface,
            Map<T, String> mapInterface,
            SortedMap<T, String> sortedMapInterface,
            BiMap<T, String> biMapInterface,
            Multimap<T, String> multimapInterface,
            ListMultimap<T, String> listMultimapInterface,
            SetMultimap<T, String> setMultimapInterface,
            Multiset<T> multisetInterface,
            SortedMultiset<T> sortedMultisetInterface,
            List<? extends T> listWildExtendsT,
            List<? extends Number> listWildExtendsNumber,
            List<? extends Comparable<?>> listWildExtendsComparable,
            Set<? extends T> setWildExtendsT,
            Set<? extends Number> setWildExtendsNumber,
            Set<? extends Comparable<?>> setWildExtendsComparable,
            List<?> listWildBuilder1,
            List<? extends Address> listWildBuilder2,
            Map<String, ? extends Address> mapWildBuilder1,
            Map<? extends Number, String> mapWildKey,
            Table<String, Integer, String> table) {
        JodaBeanUtils.notNull(collection, "collection");
        JodaBeanUtils.notNull(list, "list");
        JodaBeanUtils.notNull(set, "set");
        JodaBeanUtils.notNull(sortedSet, "sortedSet");
        JodaBeanUtils.notNull(map, "map");
        JodaBeanUtils.notNull(sortedMap, "sortedMap");
        JodaBeanUtils.notNull(biMap, "biMap");
        JodaBeanUtils.notNull(multimap, "multimap");
        JodaBeanUtils.notNull(listMultimap, "listMultimap");
        JodaBeanUtils.notNull(setMultimap, "setMultimap");
        JodaBeanUtils.notNull(multiset, "multiset");
        JodaBeanUtils.notNull(sortedMultiset, "sortedMultiset");
        JodaBeanUtils.notNull(collectionInterface, "collectionInterface");
        JodaBeanUtils.notNull(listInterface, "listInterface");
        JodaBeanUtils.notNull(setInterface, "setInterface");
        JodaBeanUtils.notNull(sortedSetInterface, "sortedSetInterface");
        JodaBeanUtils.notNull(mapInterface, "mapInterface");
        JodaBeanUtils.notNull(sortedMapInterface, "sortedMapInterface");
        JodaBeanUtils.notNull(biMapInterface, "biMapInterface");
        JodaBeanUtils.notNull(multimapInterface, "multimapInterface");
        JodaBeanUtils.notNull(listMultimapInterface, "listMultimapInterface");
        JodaBeanUtils.notNull(setMultimapInterface, "setMultimapInterface");
        JodaBeanUtils.notNull(multisetInterface, "multisetInterface");
        JodaBeanUtils.notNull(sortedMultisetInterface, "sortedMultisetInterface");
        JodaBeanUtils.notNull(listWildExtendsT, "listWildExtendsT");
        JodaBeanUtils.notNull(listWildExtendsNumber, "listWildExtendsNumber");
        JodaBeanUtils.notNull(listWildExtendsComparable, "listWildExtendsComparable");
        JodaBeanUtils.notNull(setWildExtendsT, "setWildExtendsT");
        JodaBeanUtils.notNull(setWildExtendsNumber, "setWildExtendsNumber");
        JodaBeanUtils.notNull(setWildExtendsComparable, "setWildExtendsComparable");
        JodaBeanUtils.notNull(listWildBuilder1, "listWildBuilder1");
        JodaBeanUtils.notNull(listWildBuilder2, "listWildBuilder2");
        JodaBeanUtils.notNull(mapWildBuilder1, "mapWildBuilder1");
        JodaBeanUtils.notNull(mapWildKey, "mapWildKey");
        JodaBeanUtils.notNull(table, "table");
        this.collection = ImmutableList.copyOf(collection);
        this.list = ImmutableList.copyOf(list);
        this.set = ImmutableSet.copyOf(set);
        this.sortedSet = ImmutableSortedSet.copyOfSorted(sortedSet);
        this.map = ImmutableMap.copyOf(map);
        this.sortedMap = ImmutableSortedMap.copyOfSorted(sortedMap);
        this.biMap = ImmutableBiMap.copyOf(biMap);
        this.multimap = ImmutableMultimap.copyOf(multimap);
        this.listMultimap = ImmutableListMultimap.copyOf(listMultimap);
        this.setMultimap = ImmutableSetMultimap.copyOf(setMultimap);
        this.multiset = ImmutableMultiset.copyOf(multiset);
        this.sortedMultiset = ImmutableSortedMultiset.copyOfSorted(sortedMultiset);
        this.collectionInterface = ImmutableList.copyOf(collectionInterface);
        this.listInterface = ImmutableList.copyOf(listInterface);
        this.setInterface = ImmutableSet.copyOf(setInterface);
        this.sortedSetInterface = ImmutableSortedSet.copyOfSorted(sortedSetInterface);
        this.mapInterface = ImmutableMap.copyOf(mapInterface);
        this.sortedMapInterface = ImmutableSortedMap.copyOfSorted(sortedMapInterface);
        this.biMapInterface = ImmutableBiMap.copyOf(biMapInterface);
        this.multimapInterface = ImmutableMultimap.copyOf(multimapInterface);
        this.listMultimapInterface = ImmutableListMultimap.copyOf(listMultimapInterface);
        this.setMultimapInterface = ImmutableSetMultimap.copyOf(setMultimapInterface);
        this.multisetInterface = ImmutableMultiset.copyOf(multisetInterface);
        this.sortedMultisetInterface = ImmutableSortedMultiset.copyOfSorted(sortedMultisetInterface);
        this.listWildExtendsT = ImmutableList.copyOf(listWildExtendsT);
        this.listWildExtendsNumber = ImmutableList.copyOf(listWildExtendsNumber);
        this.listWildExtendsComparable = ImmutableList.copyOf(listWildExtendsComparable);
        this.setWildExtendsT = ImmutableSet.copyOf(setWildExtendsT);
        this.setWildExtendsNumber = ImmutableSet.copyOf(setWildExtendsNumber);
        this.setWildExtendsComparable = ImmutableSet.copyOf(setWildExtendsComparable);
        this.listWildBuilder1 = ImmutableList.copyOf(listWildBuilder1);
        this.listWildBuilder2 = ImmutableList.copyOf(listWildBuilder2);
        this.mapWildBuilder1 = ImmutableMap.copyOf(mapWildBuilder1);
        this.mapWildKey = ImmutableMap.copyOf(mapWildKey);
        this.table = ImmutableTable.copyOf(table);
    }

    @SuppressWarnings("unchecked")
    @Override
    public ImmGuava.Meta<T> metaBean() {
        return ImmGuava.Meta.INSTANCE;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the collection.
     * @return the value of the property, not null
     */
    public ImmutableCollection<T> getCollection() {
        return collection;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the list.
     * @return the value of the property, not null
     */
    public ImmutableList<T> getList() {
        return list;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the set.
     * @return the value of the property, not null
     */
    public ImmutableSet<T> getSet() {
        return set;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the sortedSet.
     * @return the value of the property, not null
     */
    public ImmutableSortedSet<T> getSortedSet() {
        return sortedSet;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the map.
     * @return the value of the property, not null
     */
    public ImmutableMap<T, String> getMap() {
        return map;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the sortedMap.
     * @return the value of the property, not null
     */
    public ImmutableSortedMap<T, String> getSortedMap() {
        return sortedMap;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the biMap.
     * @return the value of the property, not null
     */
    public ImmutableBiMap<T, String> getBiMap() {
        return biMap;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the multimap.
     * @return the value of the property, not null
     */
    public ImmutableMultimap<T, String> getMultimap() {
        return multimap;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the listMultimap.
     * @return the value of the property, not null
     */
    public ImmutableListMultimap<T, String> getListMultimap() {
        return listMultimap;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the setMultimap.
     * @return the value of the property, not null
     */
    public ImmutableSetMultimap<T, String> getSetMultimap() {
        return setMultimap;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the multiset.
     * @return the value of the property, not null
     */
    public ImmutableMultiset<T> getMultiset() {
        return multiset;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the sortedMultiset.
     * @return the value of the property, not null
     */
    public ImmutableSortedMultiset<T> getSortedMultiset() {
        return sortedMultiset;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the collectionInterface.
     * @return the value of the property, not null
     */
    public Collection<T> getCollectionInterface() {
        return collectionInterface;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the listInterface.
     * @return the value of the property, not null
     */
    public List<T> getListInterface() {
        return listInterface;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the setInterface.
     * @return the value of the property, not null
     */
    public Set<T> getSetInterface() {
        return setInterface;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the sortedSetInterface.
     * @return the value of the property, not null
     */
    public SortedSet<T> getSortedSetInterface() {
        return sortedSetInterface;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the mapInterface.
     * @return the value of the property, not null
     */
    public Map<T, String> getMapInterface() {
        return mapInterface;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the sortedMapInterface.
     * @return the value of the property, not null
     */
    public SortedMap<T, String> getSortedMapInterface() {
        return sortedMapInterface;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the biMapInterface.
     * @return the value of the property, not null
     */
    public BiMap<T, String> getBiMapInterface() {
        return biMapInterface;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the multimapInterface.
     * @return the value of the property, not null
     */
    public Multimap<T, String> getMultimapInterface() {
        return multimapInterface;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the listMultimapInterface.
     * @return the value of the property, not null
     */
    public ListMultimap<T, String> getListMultimapInterface() {
        return listMultimapInterface;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the setMultimapInterface.
     * @return the value of the property, not null
     */
    public SetMultimap<T, String> getSetMultimapInterface() {
        return setMultimapInterface;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the multisetInterface.
     * @return the value of the property, not null
     */
    public Multiset<T> getMultisetInterface() {
        return multisetInterface;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the sortedMultisetInterface.
     * @return the value of the property, not null
     */
    public SortedMultiset<T> getSortedMultisetInterface() {
        return sortedMultisetInterface;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the listWildExtendsT.
     * @return the value of the property, not null
     */
    public ImmutableList<? extends T> getListWildExtendsT() {
        return listWildExtendsT;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the listWildExtendsNumber.
     * @return the value of the property, not null
     */
    public ImmutableList<? extends Number> getListWildExtendsNumber() {
        return listWildExtendsNumber;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the listWildExtendsComparable.
     * @return the value of the property, not null
     */
    public ImmutableList<? extends Comparable<?>> getListWildExtendsComparable() {
        return listWildExtendsComparable;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the setWildExtendsT.
     * @return the value of the property, not null
     */
    public ImmutableSet<? extends T> getSetWildExtendsT() {
        return setWildExtendsT;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the setWildExtendsNumber.
     * @return the value of the property, not null
     */
    public ImmutableSet<? extends Number> getSetWildExtendsNumber() {
        return setWildExtendsNumber;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the setWildExtendsComparable.
     * @return the value of the property, not null
     */
    public ImmutableSet<? extends Comparable<?>> getSetWildExtendsComparable() {
        return setWildExtendsComparable;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the listWildBuilder1.
     * @return the value of the property, not null
     */
    public ImmutableList<Object> getListWildBuilder1() {
        return listWildBuilder1;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the listWildBuilder2.
     * @return the value of the property, not null
     */
    public ImmutableList<Address> getListWildBuilder2() {
        return listWildBuilder2;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the mapWildBuilder1.
     * @return the value of the property, not null
     */
    public ImmutableMap<String, Address> getMapWildBuilder1() {
        return mapWildBuilder1;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the mapWildKey.
     * @return the value of the property, not null
     */
    public ImmutableMap<? extends Number, String> getMapWildKey() {
        return mapWildKey;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets the table.
     * @return the value of the property, not null
     */
    public ImmutableTable<String, Integer, String> getTable() {
        return table;
    }

    //-----------------------------------------------------------------------
    /**
     * Returns a builder that allows this bean to be mutated.
     * @return the mutable builder, not null
     */
    public Builder<T> toBuilder() {
        return new Builder<>(this);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (obj != null && obj.getClass() == this.getClass()) {
            ImmGuava<?> other = (ImmGuava<?>) obj;
            return JodaBeanUtils.equal(this.collection, other.collection) &&
                    JodaBeanUtils.equal(this.list, other.list) &&
                    JodaBeanUtils.equal(this.set, other.set) &&
                    JodaBeanUtils.equal(this.sortedSet, other.sortedSet) &&
                    JodaBeanUtils.equal(this.map, other.map) &&
                    JodaBeanUtils.equal(this.sortedMap, other.sortedMap) &&
                    JodaBeanUtils.equal(this.biMap, other.biMap) &&
                    JodaBeanUtils.equal(this.multimap, other.multimap) &&
                    JodaBeanUtils.equal(this.listMultimap, other.listMultimap) &&
                    JodaBeanUtils.equal(this.setMultimap, other.setMultimap) &&
                    JodaBeanUtils.equal(this.multiset, other.multiset) &&
                    JodaBeanUtils.equal(this.sortedMultiset, other.sortedMultiset) &&
                    JodaBeanUtils.equal(this.collectionInterface, other.collectionInterface) &&
                    JodaBeanUtils.equal(this.listInterface, other.listInterface) &&
                    JodaBeanUtils.equal(this.setInterface, other.setInterface) &&
                    JodaBeanUtils.equal(this.sortedSetInterface, other.sortedSetInterface) &&
                    JodaBeanUtils.equal(this.mapInterface, other.mapInterface) &&
                    JodaBeanUtils.equal(this.sortedMapInterface, other.sortedMapInterface) &&
                    JodaBeanUtils.equal(this.biMapInterface, other.biMapInterface) &&
                    JodaBeanUtils.equal(this.multimapInterface, other.multimapInterface) &&
                    JodaBeanUtils.equal(this.listMultimapInterface, other.listMultimapInterface) &&
                    JodaBeanUtils.equal(this.setMultimapInterface, other.setMultimapInterface) &&
                    JodaBeanUtils.equal(this.multisetInterface, other.multisetInterface) &&
                    JodaBeanUtils.equal(this.sortedMultisetInterface, other.sortedMultisetInterface) &&
                    JodaBeanUtils.equal(this.listWildExtendsT, other.listWildExtendsT) &&
                    JodaBeanUtils.equal(this.listWildExtendsNumber, other.listWildExtendsNumber) &&
                    JodaBeanUtils.equal(this.listWildExtendsComparable, other.listWildExtendsComparable) &&
                    JodaBeanUtils.equal(this.setWildExtendsT, other.setWildExtendsT) &&
                    JodaBeanUtils.equal(this.setWildExtendsNumber, other.setWildExtendsNumber) &&
                    JodaBeanUtils.equal(this.setWildExtendsComparable, other.setWildExtendsComparable) &&
                    JodaBeanUtils.equal(this.listWildBuilder1, other.listWildBuilder1) &&
                    JodaBeanUtils.equal(this.listWildBuilder2, other.listWildBuilder2) &&
                    JodaBeanUtils.equal(this.mapWildBuilder1, other.mapWildBuilder1) &&
                    JodaBeanUtils.equal(this.mapWildKey, other.mapWildKey) &&
                    JodaBeanUtils.equal(this.table, other.table);
        }
        return false;
    }

    @Override
    public int hashCode() {
        int hash = getClass().hashCode();
        hash = hash * 31 + JodaBeanUtils.hashCode(collection);
        hash = hash * 31 + JodaBeanUtils.hashCode(list);
        hash = hash * 31 + JodaBeanUtils.hashCode(set);
        hash = hash * 31 + JodaBeanUtils.hashCode(sortedSet);
        hash = hash * 31 + JodaBeanUtils.hashCode(map);
        hash = hash * 31 + JodaBeanUtils.hashCode(sortedMap);
        hash = hash * 31 + JodaBeanUtils.hashCode(biMap);
        hash = hash * 31 + JodaBeanUtils.hashCode(multimap);
        hash = hash * 31 + JodaBeanUtils.hashCode(listMultimap);
        hash = hash * 31 + JodaBeanUtils.hashCode(setMultimap);
        hash = hash * 31 + JodaBeanUtils.hashCode(multiset);
        hash = hash * 31 + JodaBeanUtils.hashCode(sortedMultiset);
        hash = hash * 31 + JodaBeanUtils.hashCode(collectionInterface);
        hash = hash * 31 + JodaBeanUtils.hashCode(listInterface);
        hash = hash * 31 + JodaBeanUtils.hashCode(setInterface);
        hash = hash * 31 + JodaBeanUtils.hashCode(sortedSetInterface);
        hash = hash * 31 + JodaBeanUtils.hashCode(mapInterface);
        hash = hash * 31 + JodaBeanUtils.hashCode(sortedMapInterface);
        hash = hash * 31 + JodaBeanUtils.hashCode(biMapInterface);
        hash = hash * 31 + JodaBeanUtils.hashCode(multimapInterface);
        hash = hash * 31 + JodaBeanUtils.hashCode(listMultimapInterface);
        hash = hash * 31 + JodaBeanUtils.hashCode(setMultimapInterface);
        hash = hash * 31 + JodaBeanUtils.hashCode(multisetInterface);
        hash = hash * 31 + JodaBeanUtils.hashCode(sortedMultisetInterface);
        hash = hash * 31 + JodaBeanUtils.hashCode(listWildExtendsT);
        hash = hash * 31 + JodaBeanUtils.hashCode(listWildExtendsNumber);
        hash = hash * 31 + JodaBeanUtils.hashCode(listWildExtendsComparable);
        hash = hash * 31 + JodaBeanUtils.hashCode(setWildExtendsT);
        hash = hash * 31 + JodaBeanUtils.hashCode(setWildExtendsNumber);
        hash = hash * 31 + JodaBeanUtils.hashCode(setWildExtendsComparable);
        hash = hash * 31 + JodaBeanUtils.hashCode(listWildBuilder1);
        hash = hash * 31 + JodaBeanUtils.hashCode(listWildBuilder2);
        hash = hash * 31 + JodaBeanUtils.hashCode(mapWildBuilder1);
        hash = hash * 31 + JodaBeanUtils.hashCode(mapWildKey);
        hash = hash * 31 + JodaBeanUtils.hashCode(table);
        return hash;
    }

    @Override
    public String toString() {
        StringBuilder buf = new StringBuilder(1152);
        buf.append("ImmGuava{");
        buf.append("collection").append('=').append(JodaBeanUtils.toString(collection)).append(',').append(' ');
        buf.append("list").append('=').append(JodaBeanUtils.toString(list)).append(',').append(' ');
        buf.append("set").append('=').append(JodaBeanUtils.toString(set)).append(',').append(' ');
        buf.append("sortedSet").append('=').append(JodaBeanUtils.toString(sortedSet)).append(',').append(' ');
        buf.append("map").append('=').append(JodaBeanUtils.toString(map)).append(',').append(' ');
