// Copyright (c) 2013-2020, SIB - Swiss Institute of Bioinformatics and
//                          Biozentrum - University of Basel
// 
// 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.


#ifndef PM3_CORE_ENUMERATOR_HH
#define PM3_CORE_ENUMERATOR_HH

#include <promod3/core/message.hh>
#include <vector>

namespace promod3 { namespace core {

template <typename T>
struct Enumerator{
  Enumerator(const std::vector<T>& num_combinations):
                                   enum_size_(num_combinations.size()),
                                   num_combinations_(num_combinations),
                                   enum_(enum_size_, 0){

    for(typename std::vector<T>::iterator i = num_combinations_.begin();
        i != num_combinations_.end(); ++i){
      if(*i <= 0){
        throw promod3::Error("Number of combinations must be larger than 0 at "
                             "every location when setting up Enumerator!");
      }
    }
  }

  std::vector<T>& CurrentEnum() { return enum_; }

  bool Next(){
    int actual_pos = enum_size_ - 1;
    while(actual_pos >= 0){
      ++enum_[actual_pos];
      if(enum_[actual_pos] >= num_combinations_[actual_pos]){
        enum_[actual_pos] = 0;
        --actual_pos;
      }
      else{
        break;
      }
    }
    // if actual_pos < 0, it means that the first position overflows over
    // the max value defined in num_combinations
    return actual_pos >= 0;
  }

  int enum_size_;
  std::vector<T> num_combinations_;
  std::vector<T> enum_;
};

}} //ns

#endif
