#ifndef COMPARISON_BENCHMARKS_BASE_MATRIX_DIV_CONQUER_H
#define COMPARISON_BENCHMARKS_BASE_MATRIX_DIV_CONQUER_H

#include <vector>
#include <cstdio>
#include <cstdlib>

namespace comparison_benchmarks {
namespace base {
namespace matrix_div_conquer {

const int CUTOFF_SIZE = 8;

class blocked_matrix_view {
 public:
  blocked_matrix_view(double *data, size_t size) : data_{data},
                                                   size_{size} {
    if (size > BLOCK_LOOKUPS_SIZE) {
      init_block_lookup(size);
    }
  }

  void fill_default_data();

  blocked_matrix_view quadrant_1_1() {
    size_t elements_per_quarter = (size_ / 2) * (size_ / 2);
    return blocked_matrix_view(data_ + 0 * elements_per_quarter, size_ / 2);
  }
  blocked_matrix_view quadrant_1_2() {
    size_t elements_per_quarter = (size_ / 2) * (size_ / 2);
    return blocked_matrix_view(data_ + 1 * elements_per_quarter, size_ / 2);
  }
  blocked_matrix_view quadrant_2_1() {
    size_t elements_per_quarter = (size_ / 2) * (size_ / 2);
    return blocked_matrix_view(data_ + 2 * elements_per_quarter, size_ / 2);
  }
  blocked_matrix_view quadrant_2_2() {
    size_t elements_per_quarter = (size_ / 2) * (size_ / 2);
    return blocked_matrix_view(data_ + 3 * elements_per_quarter, size_ / 2);
  }

  double &at(size_t row, size_t column) {
    return data_[BLOCK_LOOKUPS[block_lookup_at(row, column)]];
  }

  double *get_data() {
    return data_;
  }

 private:
  double *const data_;
  const size_t size_;

  // Lookup indices for non divide-conquer block lookups
  static std::vector<size_t> BLOCK_LOOKUPS;
  static size_t BLOCK_LOOKUPS_SIZE;

  static void fill_block_lookup(size_t size, std::vector<size_t> &BLOCK_LOOKUP);
  static void init_block_lookup(size_t max_size);
  static size_t block_lookup_at(size_t row, size_t column) {
    return row * BLOCK_LOOKUPS_SIZE + column;
  }
};

void multiply_naive(size_t size, blocked_matrix_view &result, blocked_matrix_view &a, blocked_matrix_view &b);

}
}
}

#endif // COMPARISON_BENCHMARKS_BASE_MATRIX_DIV_CONQUER_H
