#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <time.h>	// for accessing timing operations
#include "Vector.h"
#include "Square.h"

//#define DEBUG
//#define EXTRA_ACCOUNTING

using namespace std;


class Accounting {
public:
  int size;
  unsigned long long soln;
  unsigned long long cand;
  unsigned long long recur;
  unsigned long long *level;
  Accounting(int max) : size(max), soln(0), cand(0), recur(0) {
    level = new unsigned long long[size+1];
    for (int i=0; i<=size; i++)
      level[i]=0;
  };
  ~Accounting() {
    delete [] level;
  }
};

std::ostream&  operator<<(std::ostream& out, const Accounting& a) {
  out << "There were " << a.recur << " recursive calls made.\n";
#ifdef EXTRA_ACCOUNTING  
  for (int i=0; i<=a.size; i++) {
    out << "   " << setw(10) << a.level[i] << " made with " << setw(2) << i << " unfilled cells.\n";
  }
#endif
  out << "There were " << a.cand << " completely filled squares considered.\n";
  out << "There were " << a.soln << " solutions found.\n";
  return out;
}


// some globals
static Accounting* counter;
static bool debug = false;



void PuzzleSolve(Square& S, Vector<int>& V) {
  counter->recur++;
  if (counter->recur%1000000==0) {
    cout << "Number of recursive calls is " << counter->recur << " and counting...\n";
    cout.flush();
  }
  if (counter->recur%10000000LL==0) {
    // progress report
    cout << "--------  Progress Report ---------\n";
    cout << "Number of solutions is " << counter->soln << " and counting...\n";
    cout << "Current recurisive call based on configuration\n" << S << endl << V;
    cout << "------------------------------------\n\n";
    cout.flush();
  }

  if (debug)
    cout << "--------------------------------\nRecurisive call begining with\n" << S << endl << V << "------------------------------\n\n";


  int remaining = V.size();

  counter->level[remaining]++;

  if (remaining==0) {
    counter->cand++;
    if (S.valid()) {
      // found a solution
      counter->soln++;
      if (counter->soln<=10) {
	// print it out, if one of the first ten
	cout << S << endl;
	cout.flush();
      }
    }
  } else {
    /*
     * For each item of vector V, use that item to fill the chosen cell, and recurse
     */
    for (int rank = 0; rank<remaining; rank++) {

      // add the given value to the square
      if (S.add(V.elemAtRank(rank))) {

	// make new list, which is copy of L, but without given item
	Vector<int> newV(V);	// a copy of vector V
	newV.removeAtRank(rank);	// but without the used item

	// recurse
	PuzzleSolve(S,newV);
      }
      else if (debug)
	cout << "--------------------------------\nThe following square was considered,\nbut ruled out as (partially) invalid\n" << S << "------------------------------\n\n";

      // remove the added value
      S.pop();
    }
  }
}


int main(int argc, const char* argv[]) {

  /*
   * The first command-line argument is used to specify n
   */
  int n = -1;
  if (argc>1) {
    n = atoi(argv[1]);
  }
  if (n<1) {
    cout << "Must specify a valid 'n' as first command-line argument.\n";
    exit(1);
  }
  /*
   * If a second command-line argument is given (no matter what), we
   * enter debug mode
   */
  if (argc>2)
    debug = true;
  

  counter = new Accounting(n*n);

  /*
   * Now we create the initially empty square, and a list of values to
   * be used, from 1 to n^2.
   */
  Square S(n);
  Vector<int> L;
  for (int i=0; i<n*n; i++)
    L.insertAtRank(i,i+1);

  /*
   * Let the recursion begin...
   */
  clock();
  clock_t starttime = clock();
  PuzzleSolve(S,L);
  clock_t endtime = clock();

  /*
   * Let's report the results
   */
  cout << "The process is complete.\n" << (*counter);
  double elapsed = ((double) (endtime - starttime))/CLOCKS_PER_SEC;
  cout << "Time used (in seconds) was " << elapsed << "\n";
}
