/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.accumulo.core.iterators;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.accumulo.core.conf.AccumuloConfiguration;
import org.apache.accumulo.core.conf.ConfigurationCopy;
import org.apache.accumulo.core.conf.Property;
import org.apache.accumulo.core.data.ByteSequence;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Range;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.data.impl.KeyExtent;
import org.apache.accumulo.core.data.thrift.IterInfo;
import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope;
import org.apache.accumulo.core.iterators.system.MultiIteratorTest;
import org.apache.accumulo.core.iterators.user.AgeOffFilter;
import org.apache.accumulo.core.iterators.user.SummingCombiner;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class IteratorUtilTest {

  private static final Logger log = LoggerFactory.getLogger(IteratorUtilTest.class);
  private static final Collection<ByteSequence> EMPTY_COL_FAMS = new ArrayList<>();

  static class WrappedIter implements SortedKeyValueIterator<Key,Value> {

    protected SortedKeyValueIterator<Key,Value> source;

    @Override
    public WrappedIter deepCopy(IteratorEnvironment env) {
      throw new UnsupportedOperationException();
    }

    @Override
    public Key getTopKey() {
      return source.getTopKey();
    }

    @Override
    public Value getTopValue() {
      return source.getTopValue();
    }

    @Override
    public boolean hasTop() {
      return source.hasTop();
    }

    @Override
    public void init(SortedKeyValueIterator<Key,Value> source, Map<String,String> options,
        IteratorEnvironment env) throws IOException {
      this.source = source;
    }

    @Override
    public void next() throws IOException {
      source.next();
    }

    @Override
    public void seek(Range range, Collection<ByteSequence> columnFamilies, boolean inclusive)
        throws IOException {
      source.seek(range, columnFamilies, inclusive);
    }
  }

  static class AddingIter extends WrappedIter {

    int amount = 1;

    @Override
    public Value getTopValue() {
      Value val = super.getTopValue();

      int orig = Integer.parseInt(val.toString());

      return new Value(((orig + amount) + "").getBytes());
    }

    @Override
    public void init(SortedKeyValueIterator<Key,Value> source, Map<String,String> options,
        IteratorEnvironment env) throws IOException {
      super.init(source, options, env);

      String amount = options.get("amount");

      if (amount != null) {
        this.amount = Integer.parseInt(amount);
      }
    }
  }

  static class SquaringIter extends WrappedIter {
    @Override
    public Value getTopValue() {
      Value val = super.getTopValue();

      int orig = Integer.parseInt(val.toString());

      return new Value(((orig * orig) + "").getBytes());
    }
  }

  @Test
  public void test1() throws IOException {
    ConfigurationCopy conf = new ConfigurationCopy();

    // create an iterator that adds 1 and then squares
    conf.set(Property.TABLE_ITERATOR_PREFIX + IteratorScope.minc.name() + ".addIter",
        "1," + AddingIter.class.getName());
    conf.set(Property.TABLE_ITERATOR_PREFIX + IteratorScope.minc.name() + ".sqIter",
        "2," + SquaringIter.class.getName());

    TreeMap<Key,Value> tm = new TreeMap<>();

    MultiIteratorTest.newKeyValue(tm, 1, 0, false, "1");
    MultiIteratorTest.newKeyValue(tm, 2, 0, false, "2");

    SortedMapIterator source = new SortedMapIterator(tm);

    SortedKeyValueIterator<Key,Value> iter = IteratorUtil.loadIterators(IteratorScope.minc, source,
        new KeyExtent("tab", null, null), conf, new DefaultIteratorEnvironment(conf));
    iter.seek(new Range(), EMPTY_COL_FAMS, false);

    assertTrue(iter.hasTop());
    assertTrue(iter.getTopKey().equals(MultiIteratorTest.newKey(1, 0)));
    assertTrue(iter.getTopValue().toString().equals("4"));

    iter.next();

    assertTrue(iter.hasTop());
    assertTrue(iter.getTopKey().equals(MultiIteratorTest.newKey(2, 0)));
    assertTrue(iter.getTopValue().toString().equals("9"));

    iter.next();

    assertFalse(iter.hasTop());
  }

  @Test
  public void test4() throws IOException {

    // try loading for a different scope
    AccumuloConfiguration conf = new ConfigurationCopy();

    TreeMap<Key,Value> tm = new TreeMap<>();

    MultiIteratorTest.newKeyValue(tm, 1, 0, false, "1");
    MultiIteratorTest.newKeyValue(tm, 2, 0, false, "2");

    SortedMapIterator source = new SortedMapIterator(tm);

    SortedKeyValueIterator<Key,Value> iter = IteratorUtil.loadIterators(IteratorScope.majc, source,
        new KeyExtent("tab", null, null), conf, new DefaultIteratorEnvironment(conf));
    iter.seek(new Range(), EMPTY_COL_FAMS, false);

    assertTrue(iter.hasTop());
    assertTrue(iter.getTopKey().equals(MultiIteratorTest.newKey(1, 0)));
    assertTrue(iter.getTopValue().toString().equals("1"));

    iter.next();

    assertTrue(iter.hasTop());
    assertTrue(iter.getTopKey().equals(MultiIteratorTest.newKey(2, 0)));
    assertTrue(iter.getTopValue().toString().equals("2"));

    iter.next();

    assertFalse(iter.hasTop());

  }

  @Test
  public void test3() throws IOException {
    // change the load order, so it squares and then adds

    ConfigurationCopy conf = new ConfigurationCopy();

    TreeMap<Key,Value> tm = new TreeMap<>();

    MultiIteratorTest.newKeyValue(tm, 1, 0, false, "1");
    MultiIteratorTest.newKeyValue(tm, 2, 0, false, "2");

    SortedMapIterator source = new SortedMapIterator(tm);

    conf.set(Property.TABLE_ITERATOR_PREFIX + IteratorScope.minc.name() + ".addIter",
        "2," + AddingIter.class.getName());
    conf.set(Property.TABLE_ITERATOR_PREFIX + IteratorScope.minc.name() + ".sqIter",
        "1," + SquaringIter.class.getName());

    SortedKeyValueIterator<Key,Value> iter = IteratorUtil.loadIterators(IteratorScope.minc, source,
        new KeyExtent("tab", null, null), conf, new DefaultIteratorEnvironment(conf));
    iter.seek(new Range(), EMPTY_COL_FAMS, false);

    assertTrue(iter.hasTop());
    assertTrue(iter.getTopKey().equals(MultiIteratorTest.newKey(1, 0)));
    assertTrue(iter.getTopValue().toString().equals("2"));

    iter.next();

    assertTrue(iter.hasTop());
    assertTrue(iter.getTopKey().equals(MultiIteratorTest.newKey(2, 0)));
    assertTrue(iter.getTopValue().toString().equals("5"));

    iter.next();

    assertFalse(iter.hasTop());
  }

  @Test
  public void test2() throws IOException {

    ConfigurationCopy conf = new ConfigurationCopy();

    // create an iterator that adds 1 and then squares
    conf.set(Property.TABLE_ITERATOR_PREFIX + IteratorScope.minc.name() + ".addIter",
        "1," + AddingIter.class.getName());
    conf.set(Property.TABLE_ITERATOR_PREFIX + IteratorScope.minc.name() + ".addIter.opt.amount",
        "7");
    conf.set(Property.TABLE_ITERATOR_PREFIX + IteratorScope.minc.name() + ".sqIter",
        "2," + SquaringIter.class.getName());

    TreeMap<Key,Value> tm = new TreeMap<>();

    MultiIteratorTest.newKeyValue(tm, 1, 0, false, "1");
    MultiIteratorTest.newKeyValue(tm, 2, 0, false, "2");

    SortedMapIterator source = new SortedMapIterator(tm);

    SortedKeyValueIterator<Key,Value> iter = IteratorUtil.loadIterators(IteratorScope.minc, source,
        new KeyExtent("tab", null, null), conf, new DefaultIteratorEnvironment(conf));
    iter.seek(new Range(), EMPTY_COL_FAMS, false);

    assertTrue(iter.hasTop());
    assertTrue(iter.getTopKey().equals(MultiIteratorTest.newKey(1, 0)));
    assertTrue(iter.getTopValue().toString().equals("64"));

    iter.next();

    assertTrue(iter.hasTop());
    assertTrue(iter.getTopKey().equals(MultiIteratorTest.newKey(2, 0)));
    assertTrue(iter.getTopValue().toString().equals("81"));

    iter.next();

    assertFalse(iter.hasTop());

  }

  @Test
  public void test5() throws IOException {
    ConfigurationCopy conf = new ConfigurationCopy();

    // create an iterator that ages off
    conf.set(Property.TABLE_ITERATOR_PREFIX + IteratorScope.minc.name() + ".filter",
        "1," + AgeOffFilter.class.getName());
    conf.set(Property.TABLE_ITERATOR_PREFIX + IteratorScope.minc.name() + ".filter.opt.ttl", "100");
    conf.set(Property.TABLE_ITERATOR_PREFIX + IteratorScope.minc.name() + ".filter.opt.currentTime",
        "1000");

    TreeMap<Key,Value> tm = new TreeMap<>();

    MultiIteratorTest.newKeyValue(tm, 1, 850, false, "1");
    MultiIteratorTest.newKeyValue(tm, 2, 950, false, "2");

    SortedMapIterator source = new SortedMapIterator(tm);

    SortedKeyValueIterator<Key,Value> iter = IteratorUtil.loadIterators(IteratorScope.minc, source,
        new KeyExtent("tab", null, null), conf, new DefaultIteratorEnvironment(conf));
    iter.seek(new Range(), EMPTY_COL_FAMS, false);

    assertTrue(iter.hasTop());
    assertTrue(iter.getTopKey().equals(MultiIteratorTest.newKey(2, 950)));
    iter.next();

    assertFalse(iter.hasTop());

  }

  @Test
  public void onlyReadsRelevantIteratorScopeConfigurations() throws Exception {
    Map<String,String> data = new HashMap<>();

    // Make some configuration items, one with a bogus scope
    data.put(Property.TABLE_ITERATOR_SCAN_PREFIX + "foo", "50," + SummingCombiner.class.getName());
    data.put(Property.TABLE_ITERATOR_SCAN_PREFIX + "foo.opt." + SummingCombiner.ALL_OPTION, "true");
    data.put(Property.TABLE_ITERATOR_PREFIX + ".fakescope.bar",
        "50," + SummingCombiner.class.getName());
    data.put(Property.TABLE_ITERATOR_SCAN_PREFIX + "foo.opt.fakeopt", "fakevalue");

    AccumuloConfiguration conf = new ConfigurationCopy(data);

    List<IterInfo> iterators = new ArrayList<>();
    Map<String,Map<String,String>> options = new HashMap<>();

    IteratorUtil.parseIterConf(IteratorScope.scan, iterators, options, conf);

    assertEquals(1, iterators.size());
    IterInfo ii = iterators.get(0);
    assertEquals(new IterInfo(50, SummingCombiner.class.getName(), "foo"), ii);
  }

  /**
   * Iterators should not contain dots in the name. Also, if the split size on "." is greater than
   * one, it should be 3, i.e., itername.opt.optname
   */
  @Test
  public void testInvalidIteratorFormats() {

    Map<String,String> data = new HashMap<>();
    List<IterInfo> iterators = new ArrayList<>();
    Map<String,Map<String,String>> options = new HashMap<>();
    AccumuloConfiguration conf;

    // create iterator with 'dot' in name
    try {
      data.put(Property.TABLE_ITERATOR_SCAN_PREFIX + "foo.bar",
          "50," + SummingCombiner.class.getName());
      conf = new ConfigurationCopy(data);
      IteratorUtil.parseIterConf(IteratorScope.scan, iterators, options, conf);
    } catch (IllegalArgumentException ex) {
      log.debug("caught expected exception: " + ex.getMessage());
    }
    data.clear();
    iterators.clear();
    options.clear();

    // create iterator with 'dot' in name and with split size of 3. If split size of three, then
    // second part must be 'opt'.
    try {
      data.put(Property.TABLE_ITERATOR_SCAN_PREFIX + "foo.bar.baz",
          "49," + SummingCombiner.class.getName());
      conf = new ConfigurationCopy(data);
      IteratorUtil.parseIterConf(IteratorScope.scan, iterators, options, conf);
    } catch (IllegalArgumentException ex) {
      log.debug("caught expected exception: " + ex.getMessage());
    }
    data.clear();
    iterators.clear();
    options.clear();

    // create iterator with invalid option format
    try {
      data.put(Property.TABLE_ITERATOR_SCAN_PREFIX + "foobar",
          "48," + SummingCombiner.class.getName());
      data.put(Property.TABLE_ITERATOR_SCAN_PREFIX + "foobar.opt", "fakevalue");
      conf = new ConfigurationCopy(data);
      IteratorUtil.parseIterConf(IteratorScope.scan, iterators, options, conf);
      assertEquals(1, iterators.size());
      IterInfo ii = iterators.get(0);
      assertEquals(new IterInfo(48, SummingCombiner.class.getName(), "foobar"), ii);
    } catch (IllegalArgumentException ex) {
      log.debug("caught expected exception: " + ex.getMessage());
    }
    data.clear();
    iterators.clear();
    options.clear();

    // create iterator with 'opt' in incorrect position
    try {
      data.put(Property.TABLE_ITERATOR_SCAN_PREFIX + "foobaz",
          "47," + SummingCombiner.class.getName());
      data.put(Property.TABLE_ITERATOR_SCAN_PREFIX + "foobaz.fake.opt", "fakevalue");
      conf = new ConfigurationCopy(data);
      IteratorUtil.parseIterConf(IteratorScope.scan, iterators, options, conf);
      assertEquals(1, iterators.size());
      IterInfo ii = iterators.get(0);
      assertEquals(new IterInfo(47, SummingCombiner.class.getName(), "foobaz"), ii);
    } catch (IllegalArgumentException ex) {
      log.debug("caught expected exception: " + ex.getMessage());
    }
  }

}
