/*
 * Copyright (C) 2007 The Guava Authors
 *
 * 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 com.google.common.collect;

import static com.google.common.base.Preconditions.checkArgument;

import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.collect.testing.features.CollectionFeature;
import com.google.common.collect.testing.features.CollectionSize;
import com.google.common.collect.testing.google.MultisetTestSuiteBuilder;
import com.google.common.collect.testing.google.TestStringMultisetGenerator;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.Nullable;

/**
 * Unit test for {@link AbstractMultiset}.
 *
 * @author Kevin Bourrillion
 * @author Louis Wasserman
 */
@SuppressWarnings("serial") // No serialization is used in this test
@GwtCompatible(emulated = true)
public class SimpleAbstractMultisetTest extends TestCase {
  @GwtIncompatible("suite")
  public static Test suite() {
    TestSuite suite = new TestSuite();
    suite.addTestSuite(SimpleAbstractMultisetTest.class);
    suite.addTest(MultisetTestSuiteBuilder.using(new TestStringMultisetGenerator() {
          @Override
          protected Multiset<String> create(String[] elements) {
            Multiset<String> ms = new NoRemoveMultiset<String>();
            Collections.addAll(ms, elements);
            return ms;
          }
        })
        .named("NoRemoveMultiset")
        .withFeatures(CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_VALUES,
            CollectionFeature.SUPPORTS_ADD)
        .createTestSuite());
    return suite;
  }

  public void testFastAddAllMultiset() {
    final AtomicInteger addCalls = new AtomicInteger();
    Multiset<String> multiset = new NoRemoveMultiset<String>() {
      @Override
      public int add(String element, int occurrences) {
        addCalls.incrementAndGet();
        return super.add(element, occurrences);
      }
    };
    ImmutableMultiset<String> adds =
        new ImmutableMultiset.Builder<String>().addCopies("x", 10).build();
    multiset.addAll(adds);
    assertEquals(addCalls.get(), 1);
  }

  public void testRemoveUnsupported() {
    Multiset<String> multiset = new NoRemoveMultiset<String>();
    multiset.add("a");
    try {
      multiset.remove("a");
      fail();
    } catch (UnsupportedOperationException expected) {}
    assertTrue(multiset.contains("a"));
  }

  private static class NoRemoveMultiset<E> extends AbstractMultiset<E>
      implements Serializable {
    final Map<E, Integer> backingMap = Maps.newHashMap();

    @Override public int add(@Nullable E element, int occurrences) {
      checkArgument(occurrences >= 0);
      Integer frequency = backingMap.get(element);
      if (frequency == null) {
        frequency = 0;
      }
      if (occurrences == 0) {
        return frequency;
      }
      checkArgument(occurrences <= Integer.MAX_VALUE - frequency);
      backingMap.put(element, frequency + occurrences);
      return frequency;
    }

    @Override
    Iterator<Entry<E>> entryIterator() {
      final Iterator<Map.Entry<E, Integer>> backingEntries = backingMap.entrySet().iterator();
      return new UnmodifiableIterator<Multiset.Entry<E>>() {
        @Override
        public boolean hasNext() {
          return backingEntries.hasNext();
        }

        @Override
        public Multiset.Entry<E> next() {
          final Map.Entry<E, Integer> mapEntry = backingEntries.next();
          return new Multisets.AbstractEntry<E>() {
            @Override
            public E getElement() {
              return mapEntry.getKey();
            }

            @Override
            public int getCount() {
              Integer frequency = backingMap.get(getElement());
              return (frequency == null) ? 0 : frequency;
            }
          };
        }
      };
    }

    @Override
    int distinctElements() {
      return backingMap.size();
    }
  }
}
