#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "cube.hh"

template <int dim>
Cube<dim>::Cube(bool invariant = false) : invariant_(invariant) {
    if (invariant_) {
        nChildren_ = 1;
    } else {
        nChildren_ = std::pow(2, dim);
    }
    children_.resize(nChildren_, nullptr);
}

template <int dim>
Cube<dim>::Cube(const Vector& A, const Vector& B, bool invariant = false) : invariant_(invariant) {
    setCorners(A, B);

    if (invariant_) {
        nChildren_ = 1;
    } else {
        nChildren_ = std::pow(2, dim);
    }
    children_.resize(nChildren_, nullptr);
}

// generate a combination of unit basis vectors from binary number
template <int dim>
void Cube<dim>::parseBinary(int binary, Vector& shift) const {

    shift = 0;
    for (int d=0; d<dim; d++) {
        // yields true, if d-th digit of binary is a 1
        if (binary & std::pow(2, d)) {
            // use d-th basis vector
            shift[d] = 1;
        }
    }
}

// constructs child cubes and sets children_
template <int dim>
void Cube<dim>::split() {
    if (invariant_) {
        children_[0] = this;
    } else {
        const int nNewCubes = std::pow(2, dim);
        newCubes.resize(nNewCubes);

        Vector midPoint = A_;
        midPoint += 1/2*(B_ - A_);

        const double h = std::pow(2.0, std::round(std::log(midPoint[0]-A_[0])/std::log(2)));

        newCubes[0] = new Cube(A_, midPoint, false);
        newCubes[nNewCubes-1] = new Cube(midPoint, B_, true);

        for (int i=1; i<nNewCubes-1; i++) {
            Vector shift;
            parseBinary(i, shift);
            shift *= h;

            newCubes[i] = new Cube(A_+shift, midPoint+shift);
        }
    } else {
        children_.resize(1);
    }
}

#include "cube_tmpl.cc"