/*
 * 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.solr.common.cloud;

import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.StrUtils;
import org.noggit.JSONWriter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static org.apache.solr.common.cloud.DocCollection.DOC_ROUTER;

/**
 * Class to partition int range into n ranges.
 * @lucene.experimental
 */
public abstract class DocRouter {
  public static final String DEFAULT_NAME = CompositeIdRouter.NAME;
  public static final DocRouter DEFAULT = new CompositeIdRouter();


  public static DocRouter getDocRouter(String routerName) {
    DocRouter router = routerMap.get(routerName);
    if (router != null) return router;
    throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown document router '"+ routerName + "'");
  }

  public String getRouteField(DocCollection coll) {
    if (coll == null) return null;
    @SuppressWarnings({"rawtypes"})
    Map m = (Map) coll.get(DOC_ROUTER);
    if (m == null) return null;
    return (String) m.get("field");
  }

  public static Map<String, Object> getRouterSpec(ZkNodeProps props) {
    Map<String, Object> map = new LinkedHashMap<>();
    for (String s : props.keySet()) {
      if (s.startsWith("router.")) {
        map.put(s.substring(7), props.get(s));
      }
    }
    if (map.get("name") == null)  {
      map.put("name", DEFAULT_NAME);
    }
    return map;
  }

  // currently just an implementation detail...
  private final static Map<String, DocRouter> routerMap;
  static {
    routerMap = new HashMap<>();
    PlainIdRouter plain = new PlainIdRouter();
    // instead of doing back compat this way, we could always convert the clusterstate on first read to "plain" if it doesn't have any properties.
    routerMap.put(null, plain);     // back compat with 4.0
    routerMap.put(PlainIdRouter.NAME, plain);
    routerMap.put(CompositeIdRouter.NAME, DEFAULT_NAME.equals(CompositeIdRouter.NAME) ? DEFAULT : new CompositeIdRouter());
    routerMap.put(ImplicitDocRouter.NAME, new ImplicitDocRouter());
    // NOTE: careful that the map keys (the static .NAME members) are filled in by making them final
  }


  // Hash ranges can't currently "wrap" - i.e. max must be greater or equal to min.
  // TODO: ranges may not be all contiguous in the future (either that or we will
  // need an extra class to model a collection of ranges)
  public static class Range implements JSONWriter.Writable, Comparable<Range> {
    public int min;  // inclusive
    public int max;  // inclusive

    public Range(int min, int max) {
      assert min <= max;
      this.min = min;
      this.max = max;
    }

    public int min() {
      return min;
    }

    public int max() {
      return max;
    }

    public boolean includes(int hash) {
      return hash >= min && hash <= max;
    }

    public boolean isSubsetOf(Range superset) {
      return superset.min <= min && superset.max >= max;
    }

    public boolean overlaps(Range other) {
      return includes(other.min) || includes(other.max) || isSubsetOf(other);
    }

    @Override
    public String toString() {
      return Integer.toHexString(min) + '-' + Integer.toHexString(max);
    }


    @Override
    public int hashCode() {
      // difficult numbers to hash... only the highest bits will tend to differ.
      // ranges will only overlap during a split, so we can just hash the lower range.
      return (min>>28) + (min>>25) + (min>>21) + min;
    }

    @Override
    public boolean equals(Object obj) {
      if (obj.getClass() != getClass()) return false;
      Range other = (Range)obj;
      return this.min == other.min && this.max == other.max;
    }

    @Override
    public void write(JSONWriter writer) {
      writer.write(toString());
    }

    @Override
    public int compareTo(Range that) {
      int mincomp = Integer.compare(this.min, that.min);
      return mincomp == 0 ? Integer.compare(this.max, that.max) : mincomp;
    }
  }

  public Range fromString(String range) {
    int middle = range.indexOf('-');
    String minS = range.substring(0, middle);
    String maxS = range.substring(middle+1);
    long min = Long.parseLong(minS, 16);  // use long to prevent the parsing routines from potentially worrying about overflow
    long max = Long.parseLong(maxS, 16);
    return new Range((int)min, (int)max);
  }

  public Range fullRange() {
    return new Range(Integer.MIN_VALUE, Integer.MAX_VALUE);
  }

  /**
   * Split the range into partitions.
   * @param partitions number of partitions
   * @param range range to split
   */
  public List<Range> partitionRange(int partitions, Range range) {
    return partitionRange(partitions, range, 0.0f);
  }

  /**
   * Split the range into partitions with inexact sizes.
   * @param partitions number of partitions
   * @param range range to split
   * @param fuzz value between 0 (inclusive) and 0.5 (exclusive) indicating inexact split, i.e. percentage
   *        of variation in resulting ranges - odd ranges will be larger and even ranges will be smaller
   *        by up to that percentage.
   */
  public List<Range> partitionRange(int partitions, Range range, float fuzz) {
    int min = range.min;
    int max = range.max;

    assert max >= min;
    if (fuzz > 0.5f) {
      throw new IllegalArgumentException("'fuzz' parameter must be <= 0.5f but was " + fuzz);
    } else if (fuzz < 0.0f) {
      fuzz = 0.0f;
    }
    if (partitions == 0) return Collections.emptyList();
    long rangeSize = (long)max - (long)min;
    long rangeStep = Math.max(1, rangeSize / partitions);
    long fuzzStep = Math.round(rangeStep * (double)fuzz / 2.0);

    List<Range> ranges = new ArrayList<>(partitions);

    long start = min;
    long end = start;
    boolean odd = true;

    while (end < max) {
      end = start + rangeStep;
      if (fuzzStep > 0) {
        if (odd) {
          end = end + fuzzStep;
        } else {
          end = end - fuzzStep;
        }
        odd = !odd;
      }
      // make last range always end exactly on MAX_VALUE
      if (ranges.size() == partitions - 1) {
        end = max;
      }
      ranges.add(new Range((int)start, (int)end));
      start = end + 1L;
    }

    return ranges;
  }

  /** Returns the Slice that the document should reside on, or null if there is not enough information */
  public abstract Slice getTargetSlice(String id, SolrInputDocument sdoc, String route, SolrParams params, DocCollection collection);

  /** This method is consulted to determine what slices should be queried for a request when
   *  an explicit shards parameter was not used.
   *  This method only accepts a single shard key (or null).  If you have a comma separated list of shard keys,
   *  call getSearchSlices
   **/
  public abstract Collection<Slice> getSearchSlicesSingle(String shardKey, SolrParams params, DocCollection collection);

  /** This method is consulted to determine what search range (the part of the hash ring) should be queried for a request when
   *  an explicit shards parameter was not used.
   *  This method only accepts a single shard key (or null).
   */
  public Range getSearchRangeSingle(String shardKey, SolrParams params, DocCollection collection) {
    throw new UnsupportedOperationException();
  }

  public abstract boolean isTargetSlice(String id, SolrInputDocument sdoc, SolrParams params, String shardId, DocCollection collection);

  public abstract String getName();

  /** This method is consulted to determine what slices should be queried for a request when
   *  an explicit shards parameter was not used.
   *  This method accepts a multi-valued shardKeys parameter (normally comma separated from the shard.keys request parameter)
   *  and aggregates the slices returned by getSearchSlicesSingle for each shardKey.
   **/
  public Collection<Slice> getSearchSlices(String shardKeys, SolrParams params, DocCollection collection) {
    if (shardKeys == null || shardKeys.indexOf(',') < 0) {
      return getSearchSlicesSingle(shardKeys, params, collection);
    }

    List<String> shardKeyList = StrUtils.splitSmart(shardKeys, ",", true);
    HashSet<Slice> allSlices = new HashSet<>();
    for (String shardKey : shardKeyList) {
      allSlices.addAll( getSearchSlicesSingle(shardKey, params, collection) );
    }
    return allSlices;
  }

}

