/*
 * Copyright (C) 2013 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 com.google.common.annotations.GwtCompatible;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.concurrent.LazyInit;
import com.google.j2objc.annotations.WeakOuter;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Spliterator;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * Skeletal, implementation-agnostic implementation of the {@link Table} interface.
 *
 * @author Louis Wasserman
 */
@GwtCompatible
abstract class AbstractTable<R, C, V> implements Table<R, C, V> {

  @Override
  public boolean containsRow(@Nullable Object rowKey) {
    return Maps.safeContainsKey(rowMap(), rowKey);
  }

  @Override
  public boolean containsColumn(@Nullable Object columnKey) {
    return Maps.safeContainsKey(columnMap(), columnKey);
  }

  @Override
  public Set<R> rowKeySet() {
    return rowMap().keySet();
  }

  @Override
  public Set<C> columnKeySet() {
    return columnMap().keySet();
  }

  @Override
  public boolean containsValue(@Nullable Object value) {
    for (Map<C, V> row : rowMap().values()) {
      if (row.containsValue(value)) {
        return true;
      }
    }
    return false;
  }

  @Override
  public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) {
    Map<C, V> row = Maps.safeGet(rowMap(), rowKey);
    return row != null && Maps.safeContainsKey(row, columnKey);
  }

  @Override
  public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
    Map<C, V> row = Maps.safeGet(rowMap(), rowKey);
    return (row == null) ? null : Maps.safeGet(row, columnKey);
  }

  @Override
  public boolean isEmpty() {
    return size() == 0;
  }

  @Override
  public void clear() {
    Iterators.clear(cellSet().iterator());
  }

  @CanIgnoreReturnValue
  @Override
  public V remove(@Nullable Object rowKey, @Nullable Object columnKey) {
    Map<C, V> row = Maps.safeGet(rowMap(), rowKey);
    return (row == null) ? null : Maps.safeRemove(row, columnKey);
  }

  @CanIgnoreReturnValue
  @Override
  public V put(R rowKey, C columnKey, V value) {
    return row(rowKey).put(columnKey, value);
  }

  @Override
  public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
    for (Table.Cell<? extends R, ? extends C, ? extends V> cell : table.cellSet()) {
      put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
    }
  }

  @LazyInit private transient @Nullable Set<Cell<R, C, V>> cellSet;

  @Override
  public Set<Cell<R, C, V>> cellSet() {
    Set<Cell<R, C, V>> result = cellSet;
    return (result == null) ? cellSet = createCellSet() : result;
  }

  Set<Cell<R, C, V>> createCellSet() {
    return new CellSet();
  }

  abstract Iterator<Table.Cell<R, C, V>> cellIterator();

  abstract Spliterator<Table.Cell<R, C, V>> cellSpliterator();

  @WeakOuter
  class CellSet extends AbstractSet<Cell<R, C, V>> {
    @Override
    public boolean contains(Object o) {
      if (o instanceof Cell) {
        Cell<?, ?, ?> cell = (Cell<?, ?, ?>) o;
        Map<C, V> row = Maps.safeGet(rowMap(), cell.getRowKey());
        return row != null
            && Collections2.safeContains(
                row.entrySet(), Maps.immutableEntry(cell.getColumnKey(), cell.getValue()));
      }
      return false;
    }

    @Override
    public boolean remove(@Nullable Object o) {
      if (o instanceof Cell) {
        Cell<?, ?, ?> cell = (Cell<?, ?, ?>) o;
        Map<C, V> row = Maps.safeGet(rowMap(), cell.getRowKey());
        return row != null
            && Collections2.safeRemove(
                row.entrySet(), Maps.immutableEntry(cell.getColumnKey(), cell.getValue()));
      }
      return false;
    }

    @Override
    public void clear() {
      AbstractTable.this.clear();
    }

    @Override
    public Iterator<Table.Cell<R, C, V>> iterator() {
      return cellIterator();
    }

    @Override
    public Spliterator<Cell<R, C, V>> spliterator() {
      return cellSpliterator();
    }

    @Override
    public int size() {
      return AbstractTable.this.size();
    }
  }

  @LazyInit private transient @Nullable Collection<V> values;

  @Override
  public Collection<V> values() {
    Collection<V> result = values;
    return (result == null) ? values = createValues() : result;
  }

  Collection<V> createValues() {
    return new Values();
  }

  Iterator<V> valuesIterator() {
    return new TransformedIterator<Cell<R, C, V>, V>(cellSet().iterator()) {
      @Override
      V transform(Cell<R, C, V> cell) {
        return cell.getValue();
      }
    };
  }

  Spliterator<V> valuesSpliterator() {
    return CollectSpliterators.map(cellSpliterator(), Table.Cell::getValue);
  }

  @WeakOuter
  class Values extends AbstractCollection<V> {
    @Override
    public Iterator<V> iterator() {
      return valuesIterator();
    }

    @Override
    public Spliterator<V> spliterator() {
      return valuesSpliterator();
    }

    @Override
    public boolean contains(Object o) {
      return containsValue(o);
    }

    @Override
    public void clear() {
      AbstractTable.this.clear();
    }

    @Override
    public int size() {
      return AbstractTable.this.size();
    }
  }

  @Override
  public boolean equals(@Nullable Object obj) {
    return Tables.equalsImpl(this, obj);
  }

  @Override
  public int hashCode() {
    return cellSet().hashCode();
  }

  /** Returns the string representation {@code rowMap().toString()}. */
  @Override
  public String toString() {
    return rowMap().toString();
  }
}
