/*
 * Copyright 2009-2020 The VOTCA Development Team (http://www.votca.org)
 *
 * 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.
 *
 */

// Standard includes
#include <functional>
#include <iostream>
#include <stdexcept>

// Local VOTCA includes
#include "votca/tools/rangeparser.h"
#include "votca/tools/tokenizer.h"

namespace votca {
namespace tools {

RangeParser::RangeParser()
    //: _has_begin(false) , _has_end(false)
    = default;

void RangeParser::Parse(std::string str) {
  // remove all spaces in string
  std::string::iterator it = std::remove_if(
      str.begin(), str.end(), std::bind2nd(std::equal_to<char>(), ' '));
  str = std::string(str.begin(), it);

  Tokenizer tok(str, ",");
  for (std::string bl : tok) {
    ParseBlock(bl);
  }
}

void RangeParser::ParseBlock(std::string str) {
  Tokenizer tokenizer(str, ":");
  std::vector<std::string> toks;

  block_t block;
  block._stride = 1;

  tokenizer.ToVector(toks);
  if (toks.size() > 3 || toks.size() < 1) {
    throw std::runtime_error("invalid range");
  }

  block._begin = block._end = std::stoi(toks[0]);

  if (toks.size() == 2) {
    block._end = std::stoi(toks[1]);
  }

  if (toks.size() == 3) {
    block._stride = std::stoi(toks[1]);
    block._end = std::stoi(toks[2]);
  }

  if (block._begin * block._stride > block._end * block._stride) {
    throw std::runtime_error(
        std::string("invalid range " + str +
                    ": begin, end and stride do not form a closed interval"));
  }

  _blocks.push_back(block);
}

RangeParser::iterator& RangeParser::iterator::operator++() {
  _current += (*_block)._stride;
  if (_current > (*_block)._end) {
    ++_block;
    if (_block != _parent->_blocks.end()) {
      _current = (*_block)._begin;
    } else {
      _current = -1;
    }
  }
  return *this;
}

}  // namespace tools
}  // namespace votca
