#ifndef _SequencedPolyomino_H
#define _SequencedPolyomino_H

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

#include "boost/multi_array.hpp"

using namespace std;

template<class T, int N>
using boostmat = typename boost::multi_array<T,N>;

typedef boost::multi_array<int, 2> array_type;
typedef boost::multi_array_types::index_range range_t;

// Function to divide a vector/array by a scalar
template <typename Type>
vector<Type> div_scalar(vector<Type> &V, Type S);

// Function to perform a cumulative sum of the vector
template <typename Type>
vector<Type> cumsum(boostmat<Type,1> &V);

// Function to print arrays/vectors
template <class Type>
void print_arr(vector<Type> V);

// Function that outputs energy matrix for the case where all
// base pairs are equivalent
boostmat<double,2> EquivEnergyMatrix(unordered_map<string,double> 
	parameters, int net_size);
    
// Utility class for measuring program run times
class Timer
{
    private:
        chrono::high_resolution_clock::time_point start_time;
        chrono::high_resolution_clock::time_point stop_time;

    public:
        void start()
        {
            start_time = std::chrono::high_resolution_clock::now();
        }

        void stop()
        {
            stop_time = std::chrono::high_resolution_clock::now();
        }

        double measure()
        {
            using namespace std::chrono;
            return duration<float>
                (stop_time - start_time).count();
        }
};

struct SequencedNeighbourhood {
    int block_id;
    int row;
    int col;
    vector<int> neighbour_locations;
    int backbone_type;
    int neighbourhood_type;
    int label;
    
    SequencedNeighbourhood();
    void clear_neighbourhood();
    void reset_labels();
    void print();
    int getNeighbourhoodType();
};

struct SequencedPolyominoMinimizer{
    int canvas_row_num;
    int canvas_col_num;
    int block_num;
    boostmat<int,2> lattice;
    boostmat<int,2> labelled_lattice;
    int highest_label;
    array<int,2> start_coordinate;
    vector<SequencedNeighbourhood> neighbourhood_classifiers;
    boostmat<bool,2> interaction_graph;
    
    SequencedPolyominoMinimizer(boostmat<int,2> lattice);
    SequencedPolyominoMinimizer(boostmat<int,2> lattice, array<int,2> start_coord_input);
    bool getInteractionConnectivity();
    void getNeighbourhoodClassifiers();
    void createContactMap();
    void printLattice();
    void ResolveLabels();
    void printLabelledLattice();
};


#endif
