/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * 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.
 */

#pragma once

#include <stddef.h>

#include <string>
#include <utility>
#include <vector>

using Range = std::pair<size_t, size_t>;

class RangeSet {
 public:
  RangeSet() : blocks_(0) {}

  explicit RangeSet(std::vector<Range>&& pairs);

  static RangeSet Parse(const std::string& range_text);

  std::string ToString() const;

  // Get the block number for the i-th (starting from 0) block in the RangeSet.
  size_t GetBlockNumber(size_t idx) const;

  // RangeSet has half-closed half-open bounds. For example, "3,5" contains blocks 3 and 4. So "3,5"
  // and "5,7" are not overlapped.
  bool Overlaps(const RangeSet& other) const;

  // size() gives the number of Range's in this RangeSet.
  size_t size() const {
    return ranges_.size();
  }

  // blocks() gives the number of all blocks in this RangeSet.
  size_t blocks() const {
    return blocks_;
  }

  // We provide const iterators only.
  std::vector<Range>::const_iterator cbegin() const {
    return ranges_.cbegin();
  }

  std::vector<Range>::const_iterator cend() const {
    return ranges_.cend();
  }

  // Need to provide begin()/end() since range-based loop expects begin()/end().
  std::vector<Range>::const_iterator begin() const {
    return ranges_.cbegin();
  }

  std::vector<Range>::const_iterator end() const {
    return ranges_.cend();
  }

  // Reverse const iterators for MoveRange().
  std::vector<Range>::const_reverse_iterator crbegin() const {
    return ranges_.crbegin();
  }

  std::vector<Range>::const_reverse_iterator crend() const {
    return ranges_.crend();
  }

  const Range& operator[](size_t i) const {
    return ranges_[i];
  }

  bool operator==(const RangeSet& other) const {
    // The orders of Range's matter. "4,1,5,8,10" != "4,8,10,1,5".
    return (ranges_ == other.ranges_);
  }

  bool operator!=(const RangeSet& other) const {
    return ranges_ != other.ranges_;
  }

 protected:
  // Actual limit for each value and the total number are both INT_MAX.
  std::vector<Range> ranges_;
  size_t blocks_;
};

// The class is a sorted version of a RangeSet; and it's useful in imgdiff to split the input
// files when we're handling large zip files. Specifically, we can treat the input file as a
// continuous RangeSet (i.e. RangeSet("0-99") for a 100 blocks file); and break it down into
// several smaller chunks based on the zip entries.

// For example, [source: 0-99] can be split into
// [split_src1: 10-29]; [split_src2: 40-49, 60-69]; [split_src3: 70-89]
// Here "10-29" simply means block 10th to block 29th with respect to the original input file.
// Also, note that the split sources should be mutual exclusive, but they don't need to cover
// every block in the original source.
class SortedRangeSet : public RangeSet {
 public:
  SortedRangeSet() {}

  // Ranges in the the set should be mutually exclusive; and they're sorted by the start block.
  explicit SortedRangeSet(std::vector<Range>&& pairs);

  void Insert(const Range& to_insert);

  // Insert the input SortedRangeSet; keep the ranges sorted and merge the overlap ranges.
  void Insert(const SortedRangeSet& rs);

  // Compute the block range the file occupies, and insert that range.
  void Insert(size_t start, size_t len);

  void Clear();

  using RangeSet::Overlaps;

  bool Overlaps(size_t start, size_t len) const;

  // Given an offset of the file, checks if the corresponding block (by considering the file as
  // 0-based continuous block ranges) is covered by the SortedRangeSet. If so, returns the offset
  // within this SortedRangeSet.
  //
  // For example, the 4106-th byte of a file is from block 1, assuming a block size of 4096-byte.
  // The mapped offset within a SortedRangeSet("1-9 15-19") is 10.
  //
  // An offset of 65546 falls into the 16-th block in a file. Block 16 is contained as the 10-th
  // item in SortedRangeSet("1-9 15-19"). So its data can be found at offset 40970 (i.e. 4096 * 10
  // + 10) in a range represented by this SortedRangeSet.
  size_t GetOffsetInRangeSet(size_t old_offset) const;
};
