// file: PlainFinder.cpp
// by: Dawn Lawrie
// date: February 17, 2005

#include <fstream>
#include "PlainFinder.h"

// Constructor
// @ param s - size of the map
PlainFinder::PlainFinder(int s) :
  size(s), theMap(new int*[s]), visit(new bool*[s]) {
  
  for (int i = 0; i < size; i++) {
    theMap[i] = new int[size];
    visit[i] = new bool[size];
  }
}

// Destructor
PlainFinder::~PlainFinder() {
  for (int i = 0; i < size; i++) {
    delete [] theMap[i];
    delete [] visit[i];
  }
  delete [] theMap;
  delete [] visit;
}

// Finds the largest plain and returns information
// precondition: map contains data
// postcondition: return value holds the number of regions in the 
//        largest plain and the corredinates of one of the regions
// @return - size and location of the largest plain
Plain PlainFinder::findLargestPlain() {

  Plain best;
  best.max = 0;

  initVisit();
  for (int r = 0; r < size; r++) {
    for (int c = 0; c < size; c++) {
      if (!visit[r][c]) {
	int value = theMap[r][c];
	int plainSize = 1;
	visit[r][c] = true;
	plainSize += calcPlain(value, r, c+1); // east
	plainSize += calcPlain(value, r, c-1); // west
	plainSize += calcPlain(value, r+1, c); // south
	plainSize += calcPlain(value, r-1, c); // north
	
	if (plainSize > best.max) {
	  best.max = plainSize;
	  best.x = c;
	  best.y = r;
	}
      }
    }
  } 
  return best;
}

// Recursively finds size of plain
// @param value - elevation of current plain
// @param rPos - row of the region
// @param cPos - column of the region
// @return - size of plain explored from this position
int PlainFinder::calcPlain(int value, int rPos, int cPos) {

  // Out of bounds east or west
  if (cPos < 0 || cPos >= size)
    return 0;
  // Out of bounds north or south
  else if (rPos < 0 || rPos >= size)
    return 0;
  // Already visited
  else if (visit[rPos][cPos])
    return 0;
  // Not the correct elevation
  else if (theMap[rPos][cPos] != value)
    return 0;
  // Part of the plain
  else {
    int plainSize = 1;
    visit[rPos][cPos] = true;
    plainSize += calcPlain(value, rPos, cPos+1); // east
    plainSize += calcPlain(value, rPos, cPos-1); // west
    plainSize += calcPlain(value, rPos+1, cPos); // south
    plainSize += calcPlain(value, rPos-1, cPos); // north
    return plainSize;
  }
}

// Reads a file and puts the values in an array
// preconditions: map has been allocted and the file
//         holds data for the size map
// postcondtion: If read sucessful, true is returned and map has data
//      from the file.
//      Otherwise, false is return and the map is invalid
// @param - name of file containing elevation data
// @return - true if read sucessful
bool PlainFinder::initMap(string fileName) {
  ifstream data(fileName.c_str());
  
  if (!data)
    return false;
  int i, j;
  for (i = 0; i < size && !data.eof(); i++) 
    for (j = 0; j < size && !data.eof(); j++) 
      data >> theMap[i][j];

  if (i != size || j != size) 
    return false;
  else
    return true;
}

// Sets all the elements in visit to false
void PlainFinder::initVisit() {
  for (int i = 0; i < size; i++) 
    for (int j = 0; j < size; j++) 
      visit[i][j] = false;
}

// Prints map in the terminal window
// precondition: map contains data
// postcondition: the map data is displayed to standard out
void PlainFinder::displayMap() {
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < size; j++) { 
      cout << theMap[i][j] << "\t";
    }
    cout << endl;
  }
}
