// implement basic life rules, with a sparse implementation
#ifndef SPARSE_LIFE_H
#define SPARSE_LIFE_H

#include <vector>
#include <algorithm>
#include "Life.h"

class SparseLife : public LifeSimulator
	{
public:
	__int64 CountPopulation(void)
		{
		population_ = 0;
		for (int j = 0; j < height_; ++j)
			for (int i = 0; i < width_; ++i)
				if (0 != GetValue(i,j))
					++population_;
		return population_;
		}

	__int64 GetGeneration(void)
		{
		return generation_;
		}
	void Reset(void)
		{
		population_ = 0;
		generation_ = 0;
		SetSize(width_,height_);
		}
	// get value at cell (i,j)
	unsigned char GetValue(int i, int j) const
		{ // 
		return board_[i+j*width_];
		}
	void SetValue(int i, int j, unsigned char value)
		{
		board_[i+j*width_] = value;
		} // SetValue

	void NextGeneration(void);

	__int64 GetPopulation(void) const
		{
		return population_;
		}
	void SetPopulation(__int64 pop)
		{
		population_ = pop;
		}

	void SetSize(int width, int height)
		{
		width_  = width;
		height_ = height;
		rows_.resize(height);
		for (int pos = 0; pos < height_; ++pos)
			{
			rows_[pos].resize(width_);
			rows_[pos][0] = INT_MAX;
			}


		board_.resize(width*height);
		}
	void GetSize(int & width, int & height) const
		{
		width = width_;
		height = height_;
		}
	bool GetWraparound(void) const
		{
		return wraps_;
		}
	void SetWraparound(bool wrap)
		{
		wraps_ = wrap;
		}

	// call after setting values - converts to internal format
	void ConvertToInternal(void);
	// call before drawing or reading values - converts internal to fast read format
	void ConvertToExternal(void);
	
	SparseLife::SparseLife(void) : 		
			wraps_(true), population_(0),
			generation_(0)
		{
		SetSize(256,256);
		}
	// takes RGB buffer, stride, image width, height, and color to draw r,g,b
	// and viewport
	void DrawBuffer(Viewport & vp, unsigned char * buffer, int stride, int width, int height,
					unsigned char r, unsigned char g, unsigned char b);


private:
	// how we store a row
	typedef std::vector<int> Row; // as big as needed for an entire row, INT_MAX last valid entry

	Row tempRow1_,tempRow2_;   // for the replacing of new data
	std::vector<Row> rows_;    // sparse row format
	std::vector<unsigned char> board_; // external format
	int width_, height_;       // size of board
	bool wraps_;               // do we wrap around?
	__int64 population_;
	__int64 generation_;
	}; // SparseLife

#endif // SPARSE_LIFE_H
// end - SparseLife.h