//#ifndef _PolySim
//#define _PolySim

#include <iostream>
#include <numeric>
#include <iterator>
#include <vector>
#include <unordered_map>
#include <math.h>
#include <random>
#include <chrono>
#include <unistd.h>
#include <fstream>

#include <boost/multi_array.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>

#include "polyomino_minimizer_2.cpp"
#include "sequenced_polyomino_minimizer.cpp"
#include "sequenced_polyomino_minimizer.hpp"
#include "proof_test.cpp"

boostmat<int,2> generateRectangle(int m, int n) {
    boostmat<int,2> rectangle_lattice;
    rectangle_lattice.resize( boost::extents[m+3][n+3] );
    
    std::fill_n(rectangle_lattice.data(), rectangle_lattice.num_elements(), -1);
    int counter = 0;
    for (int i = 1; i < m+1; i++) {
        if (i == 3) {
            for (int j = n+1; j > 0; j--) {
                rectangle_lattice[i][j] = counter;
                counter++;
            }
        } else if (i == 2) {
            for (int j = 1; j <= n+1; j++) {
                    rectangle_lattice[i][j] = counter;
                    counter++;
            }
        } else {
            if (i%2 == 0) {
                for (int j = 1; j < n+1; j++) {
                    rectangle_lattice[i][j] = counter;
                    counter++;
                }
            } else {
                for (int j = n; j > 0; j--) {
                    rectangle_lattice[i][j] = counter;
                    counter++;
                }
            }
        }
    }

    return(rectangle_lattice);
} 


int main() {
    
    ofstream fs; 
    fs.open("kinked_rectangle_min_kit.csv");

    fs << "m" << ";" << "n" << ";" << "unsequenced" << ";" << "backboned" << ";" << "backboned_no_neut" << ";" << "sequenced" << ";" << "sequenced_no_neut" << "" << endl;

    for (int m = 5; m <= 20; m++) {
        for (int n = 2; n <= 20; n++) {
            boostmat<int,2> rectangle_lattice = generateRectangle(m,n);
            PrintBoostMatrix(rectangle_lattice);

            vector<Neighbourhood> maximal_contact_map = latticetoMaximalContactMap(rectangle_lattice,m*n+2);

            auto [running_min, running_min_contact, running_min_label] = polyomino_minimizer_no_neutral(maximal_contact_map, rectangle_lattice);

            boostmat<Block,2> block_matrix = GetBlockIdentities(rectangle_lattice,m*n+2);
            ValidateWalk(rectangle_lattice, block_matrix, m*n+2);
            int output = GetNumberofBlocks(block_matrix);
            
            cout << "unsequenced: " << running_min << "/ backboned: " << output << endl;
            
            int seq_no_neutral;
            
            if (n > 2 || m > 5) {
                seq_no_neutral = 7;
                // 1 2 3
                // 6 7 4 3
                // 2 7 5 3
                // 2 7 2
                // 2 7 2
                // 3 2 3

                // OR

                // 1 2 
                // 7 3 2
                // 6 4 2
                // 6 5
                // 6 5
                // 3 3
            } else {
                seq_no_neutral = 6;
                // 1 2
                // 6 3 2
                // 5 4 2
                // 5 5
                // 2 2
            }

            // In this case, backboned and sequenced will always need 4
            fs << m << ";" << n << ";" << running_min << ";" << 4 << ";" << output << ";" << 4 << ";" << seq_no_neutral << endl;
        }
    }

    fs.close();
}