#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include <vector>
#include <sstream>
#include <algorithm>    //define copy

using namespace std;

#include "global.h"
#include "randomize.h"
#include "generateG1.h"
#include "generateG2.h"
#include "kerniganlin.h"
//#include "breuer.h"

void breuer(std::vector<std::vector<int> >& blocksR)  //declare function
{
    /*-------------------Get Block Info-------------------------------*/
    int cellsTemp = cells;
    int blockIteration = 0;
    int verticalCutCount = 0;
    int horizontalCutCount = 0;
    int totalVerticalCuts = 0;
    int totalHorizontalCuts = 0;
    int blockRows = 0;
    int blockColumns = 0;
    bool blocksSquare = false;

    while (cellsTemp > 1)
    {

        if (cellsTemp % 2)          //if cellsTemp is odd
        {
            cellsTemp = (cellsTemp + 1) / 2;
        }
        else                        //if cellsTemp is even
        {
            cellsTemp = cellsTemp / 2;
        }

        blockIteration++;

        if (blockIteration % 2)
        {
            totalVerticalCuts = totalVerticalCuts + int(pow(2, verticalCutCount));
            verticalCutCount++;
        }
        else
        {
            totalHorizontalCuts = totalHorizontalCuts + int(pow(2, horizontalCutCount));
            horizontalCutCount++;
        }

    }//end while

    if (blockIteration % 2) //makes a rectangle N x N*2
    {
        blockRows = int(pow(2, blockIteration - verticalCutCount));
        blockColumns = blockRows * 2;
        blocksSquare = false;           //blocks is not a square shape
    }
    else            //make blockIteration x blockIteration matrix
    {
        blockRows = int(sqrt(pow(2, blockIteration)));
        blockColumns = blockRows;
        blocksSquare = true;            //blocks is a square shape
    }

    blocksR.resize(blockRows);              //size blockTable to make blockRows number of rows
    for (int i = 0; i < blockRows; i++)         //size blockTable to look like rectangle or square
        blocksR[i].resize(blockColumns);        //size each row of blockTable

    //get row,y column of middle top left block
    int initialBlockRow = 0;
    int initialBlockColumn = 0;
    int initBR = 0, initBC = 0;

    if (cells > 2)
    {
        initialBlockRow = initBR = (blockRows / 2) - 1;
        initialBlockColumn = initBC = (blockColumns / 2) - 1;
    }
    else
    {
        initialBlockRow = initBR = 0;
        initialBlockColumn = initBC = 0;
    }
    /*-------------------Get Block Info-------------------------------*/
    

    
    //blockCellinfo block;                                  //declare block of type blockCellinfo
    //gain.gainMax = numeric_limits<int>::min();            //initial value for gainMax is minimum of int

    std::vector<std::vector<int> > bothPartitions;
    std::vector<std::vector<int> > storeBlocks;
    bool allBlocksallocated = false, vertical = true;
    int partSize = cells, m = 0, n = 0, blockSize = 0;
    int countVertCuts = 0, countHorizCuts = 0;
    int dummyCells = cells;

    storeBlocks.resize(blockRows*blockColumns);             //

    //Make first cut
    bothPartitions = kerniganlin(true);             //returns partA in row 0 and partB in row 1

    partA.resize(bothPartitions[0].size());         //resize vector to partA size and fill with 0's
    partB.resize(bothPartitions[1].size());         //resize vector to partB size and fill with 0's
    unlockedA.resize(bothPartitions[0].size());     //resize vector to partA size and fill with 0's
    unlockedB.resize(bothPartitions[1].size());     //resize vector to partB size and fill with 0's

    storeBlocks[0].resize(bothPartitions[0].size());
    storeBlocks[1].resize(bothPartitions[1].size());
    copy(bothPartitions[0].begin(), bothPartitions[0].end(), storeBlocks[0].begin());           //copy part A into at initial position in blocksR
    copy(bothPartitions[1].begin(), bothPartitions[1].end(), storeBlocks[1].begin());           //copy part B into at initial position + 1 right in blocksR

    partSize = int(blocksR[m].size());                              //get first partition size

    //repeat cuts
    while (allBlocksallocated != true)
    {
        if (partSize % 2)               //if N is odd (true), dummy row was added during parseFile
            partSize += 1;              //account for additional dummy row, N should be even always

        partA.resize(bothPartitions[0].size());     //resize partA to be equal to # elements in bothPartitions[0]
        partB.resize(bothPartitions[1].size());     //resize partB to be equal to # elements in bothPartitions[1]

        copy(bothPartitions[0].begin(), bothPartitions[0].end(), partA.begin());    //copy # elements in bothPartitions[0] to partA
        copy(bothPartitions[1].begin(), bothPartitions[1].end(), partB.begin());    //copy # elements in bothPartitions[1] to partB

        unlockedA.resize(partA.size()); //resize unlockedA to partA size
        unlockedB.resize(partB.size()); //resize unlockedB to partB size
        copy(partA.begin(), partA.end(), unlockedA.begin());      //copy partA into unlockedA
        copy(partB.begin(), partB.end(), unlockedB.begin());      //copy partB into unlockedB

        //make partA, partB, unlockedA, unlockedB ready before calling KL

        if (vertical && countVertCuts < totalVerticalCuts)
        {
            countVertCuts++;

            if (partA.size() % 2)                   //if cells is odd (true), dummy row added
            {
                blockSize = partA.size() + 1;               //account for additional dummy row, blocksR should be even always
                dummyCells++;                               //increment dummycells count starting from dummycells + 1
                bothPartitions[0].push_back(dummyCells);    //push dummycell onto bothPartitions[0]

                //push dummy cell onto netconnections and netConnectionsFilledCol?? netpins??

                dummyCells++;                               //increment dummycells count starting from dummycells + 1
                bothPartitions[1].push_back(dummyCells);    //push dummycell onto bothPartitions[1]
            }
            else
            {
                blockSize = partA.size();           //no dummy row added
            }

            int bP = 0;
            while (bP < 2)
            {
                partA.clear();              //clear vector
                partB.clear();              //clear vector
                partA.resize(blockSize/2);  //resize vector to be the size bothPartitions[X]
                partB.resize(blockSize/2);  //resize vector to be the size bothPartitions[X]

                copy(storeBlocks[bP].begin(), (storeBlocks[bP].begin() + (blockSize / 2)), partA.begin());          //copy storeBlocks into partA
                copy((storeBlocks[bP].begin() + (blockSize / 2)), storeBlocks[bP].end(), partB.begin());            //copy storeBlocks into partB
                
                unlockedA.resize(partA.size()); //resize vector to partA size and fill with 0's
                unlockedB.resize(partB.size()); //resize vector to partB size and fill with 0's
                copy(partA.begin(), partA.end(), unlockedA.begin());      //copy partA into unlockedA
                copy(partB.begin(), partB.end(), unlockedB.begin());      //copy partB into unlockedB

                bothPartitions = kerniganlin(false);        //returns partA in row 0 and partB in row 1

                if (bP == 0)
                {
                    blocksR[0][0] = bothPartitions[0][0];
                    blocksR[1][0] = bothPartitions[1][0];
                }
                else
                {
                    blocksR[0][1] = bothPartitions[0][0];
                    blocksR[1][1] = bothPartitions[1][0];
                }
                
                //copy(bothPartitions[0].begin(), bothPartitions[0].end(), blocksR[initBR*(blockColumns - 1) + initBC + bP].begin());           //copy part A into at initial position in blocksR
                //copy(bothPartitions[1].begin(), bothPartitions[1].end(), blocksR[(initBR + 1)*(blockColumns) + initBC + bP].begin());         //copy part B into at initial position + 1 right in blocksR

                bP++;   //increment to address bothPartitions[1]


                //blocksR[(initBR)*blockColumns + initBC].resize(bothPartitions[0].size());     //resize vector to blocks size for that row
                //blocksR[(initBR + 1)*blockColumns + initBC].resize(bothPartitions[1].size()); //resize vector to blocks size for that row

            }

            allBlocksallocated = true;
            vertical = false;   //next cut(s) are horizontal
        }//if vertical cuts

        else
        {
            bothPartitions = kerniganlin(false);                //returns partA in row 0 and partB in row 1

            vertical = true;    //next cut(s) are vertical
        }

    }//end while all blocks allocated

}//end breuer