#include <iomanip>
#include "Square.h"

using namespace std;

/*
 *  Creates an nxn square
 */
Square::Square(int width) : n(width), numFilled(0) {
  max = n*n;
  target = (n*(max+1))/2;

  entry = new int*[n];   // array of what will be arrays
  for (int i=0; i<n; i++) {
    entry[i] = new int[n];
    for (int j=0; j<n; j++)
      entry[i][j] = 0;
  }

  used = new bool[max+1];
}



/*
 * This is used to add a new value to an 'empty' cell of the square.
 * Which empty cell is left as an implementation detail of the Square.
 *
 * The boolean return value is 'false' if the newly added value is
 * known to cause a (partially) complete square which is guaranteed
 * to be invalid, no matter how the remaining squares are completed.
 */
bool Square::add(int value) {

  if (numFilled<max) {
    Cell next = whichCell(numFilled,n);
    numFilled++;
    entry[next.r][next.c] = value;
    return partialValidate(next.r,next.c);
  } else {
    return false;
  }

}



/*
 * This removes the most recently added value from the square
 */
void Square::pop() {
  if (numFilled>0) {
    numFilled--;
    Cell last = whichCell(numFilled,n);
    entry[last.r][last.c] = 0;
  }
}


/*
 * Return the width of the square
 */
int Square::width() const {
  return n;
}


/*
 * This accessor returns the (row,column) entry to value, where both
 * rows and columns are zero-indexed.
 *
 * Returns '-1' if the command fails (e.g., the indicies are invalid)
 */
int Square::get(int row, int column) const {
  if (row<0 || row>=n || column<0 || column>=n)
    return -1;
  else
    return entry[row][column];
}


/*
 * Checks validity of the current settings, ensuring that all rows,
 * columns and diagonals add up to the desired value.  Furthermore,
 * it verifies that each number from [1, n^2] has been used once,
 * and only once.
 */
bool Square::valid() {
  bool success = true;
  
  // first, lets check and see if every number was used once and only once.
  for (int i=max; i>0; i--)
    used[i] = false;

  for (int i=0; i<n; i++)
    for (int j=0; j<n; j++)
      used[entry[i][j]] = true;

  for (int i=max; i>0; i--)
    if (!used[i])
      success = false;	// did not use all values


  // look for canonical form
  if (success)
    success = canonical();

  // next lets check the sums of the rows
  for (int row=0; success && row<n; row++)
    success = checkRow(row);

  // next lets check the sums of the columns
  for (int col=0; success && col<n; col++)
    success = checkCol(col);

  // next lets check the main diagonal
  if (success)
    success = checkDiag();

  // next lets check the reverse diagonal
  if (success)
    success = checkRevDiag();

  return success;
}



/*
 * Destructor
 */
Square::~Square() {

  // first delete the inner arrays
  for (int i=0; i<n; i++) 
    delete [] entry[i];

  // then delete the outer array
  delete [] entry;

  // also delete the buffer
  delete [] used;
}


/*
 * display square
 */
std::ostream&  operator<<(std::ostream& out, const Square& s) {
  for (int row = 0; row<s.width(); row++) {
    for (int col=0; col<s.width(); col++) {
      out << setw(3) << s.get(row,col) << " ";
    }
    out << std::endl;
  }
  return out;
}



/*************************************************************
 * Remainder of file details private functions
 *************************************************************/


/*
 * The generic version of a routine which checks the validity of a
 * particular cross-section (e.g. row, column or diagonal).
 *
 * returns 'true' if the sum is the target
 */
bool Square::checkGeneric(int startRow, int startCol, int deltaRow, int deltaCol) {

  int sum = 0;
  int row = startRow;
  int col = startCol;
  for (int count=0; count<n; count++) {
    int val = entry[row][col];
    sum += val;
    row += deltaRow;
    col += deltaCol;
  }

  return (sum==target);
}


/*
 * In an nxn square, there are n^2 spots to fill in eventually.
 * Assuming that 'prevCount' cells have already been filled, this
 * routine identifies where in the square the next insertion should be
 * placed.
 */
Square::Cell Square::whichCell(int prevCount, int n) {

  // this implementaiton fills out the square in row-major order.

  Cell result;

  result.r = prevCount/n;
  result.c = prevCount%n;

  return result;

}


/*
 * Checks whether the current (partial) settings is in canonical form.
 * That is with top-left corner as the smallest of the corners, and
 * top-right corner as the smaller of its two adjacent corners.
 */
bool Square::canonical() {
  return true;   // stub
}


/*
 * Presuming that (row,col) was the most recently set entry, this
 * method attempts to determine whether that entry invalidates the
 * partial solution.
 *
 * If it becomes clear that this solution cannot be extended to a
 * valid solution, this method returns false.  Otherwise it returns
 * true (Note that it still may be impossible to complete the
 * solution).
 */
bool Square::partialValidate(int row, int col) {
  return true;  // stub
}



