/* Copyright (C) 2007  Mikko Sysikaski <mikko.sysikaski@gmail.com>
 * This program is free software distributed under GNU General Public License
 * version 3 or (at your option) any later version.
 * No warranty of any kind is provided. See the accompanying file COPYING for details.
 */

#include "modifiableboard.h"
#include <fstream>
#include <cstring>

void ModifiableBoard::save(const char* filename)
{
	std::ofstream out(filename);
	if (!out.is_open()) {
		fprintf(stderr, "Couldn't open file %s for writing!\n", filename);
		return;
	}
	out << m_y << ' ' << m_x << '\n';
	for(int y=0; y<m_y; ++y) {
		for(int x=0; x<m_x; ++x) {
			char ch = m_board[y*m_x + x];
			if (ch < 10)
				ch += '0';
			else
				ch += 'a'-10;
			out.put(ch);
		}
		out << '\n';
	}
	out << '\n';
	for(int y=0; y<m_y; ++y) {
		for(int x=0; x<m_x; ++x) {
			out.put(m_blocks[y*m_x + x]+'0');
		}
		out << '\n';
	}

	if (m_minTime >= 0)
		out << '\n' << m_minTime << '\n';
}
void ModifiableBoard::create(int h, int w)
{
	using std::memset;
	
	delete[] m_board;
	delete[] m_blocks;
	
	m_board = new char[h*w];
	m_blocks = new BlockT[h*w];
	memset(m_board, 0, h*w);
	memset(m_blocks, 0, h*w*sizeof(BlockT));
	
	m_y = h;
	m_x = w;

	m_minTime = -1;
}

void ModifiableBoard::insertRows(int place, int amount)
{
//	printf("Adding rows: %i %i\n", place, amount);
	int y = m_y + amount;
	char* board = new char[y*m_x];
	memcpy(board, m_board, m_x*place);
	memset(board+m_x*place, 0, m_x*amount);
	memcpy(board+m_x*(place+amount), m_board+m_x*place, m_x*(m_y-place));
	delete[] m_board;
	m_board = board;
	
	BlockT* blocks = new BlockT[y*m_x];
	memcpy(blocks, m_blocks, m_x*place*sizeof(BlockT));
	memset(blocks+m_x*place, 0, m_x*amount*sizeof(BlockT));
	memcpy(blocks+m_x*(place+amount), m_blocks+m_x*place, m_x*(m_y-place)*sizeof(BlockT));
	delete[] m_blocks;
	m_blocks = blocks;
	
	m_y = y;
}
template<class T>
inline void multiCopy(T* dst, T* src, int size, int dstGap, int srcGap, int amount)
{
	for(int i=0; i<amount; ++i) {
		memcpy(dst, src, size*sizeof(T));
		dst += dstGap;
		src += srcGap;
	}
}
template<class T>
inline void multiSet(T* dst, int c, int size, int gap, int amount)
{
	for(int i=0; i<amount; ++i) {
		memset(dst, c, size*sizeof(T));
		dst += gap;
	}
}
void ModifiableBoard::insertColumns(int place, int amount)
{
//	printf("Omg doing insert: %i %i\n", place, amount);
	int x = m_x + amount;
	char* board = new char[m_y*x];
	multiCopy(board, m_board, place, x, m_x, m_y);
	multiSet(board+place, 0, amount, x, m_y);
	multiCopy(board+place+amount, m_board+place, m_x-place, x, m_x, m_y);
	delete[] m_board;
	m_board = board;
	
	BlockT* blocks = new BlockT[m_y*x];
	multiCopy(blocks, m_blocks, place, x, m_x, m_y);
	multiSet(blocks+place, 0, amount, x, m_y);
	multiCopy(blocks+place+amount, m_blocks+place, m_x-place, x, m_x, m_y);
	delete[] m_blocks;
	m_blocks = blocks;
	
	m_x = x;
}
void ModifiableBoard::deleteRows(int place, int amount)
{
	memcpy(m_board+m_x*place, m_board+m_x*(place+amount), m_x*(m_y-place-amount));
	memcpy(m_blocks+m_x*place, m_blocks+m_x*(place+amount),
		m_x*(m_y-place-amount)*sizeof(BlockT));
	m_y -= amount;
}
void ModifiableBoard::deleteColumns(int place, int amount)
{
	int x = m_x-amount;
	char* board = new char[m_y*x];
	multiCopy(board, m_board, place, x, m_x, m_y);
	multiCopy(board+place, m_board+place+amount, x-place, x, m_x, m_y);
	delete[] m_board;
	m_board = board;
	
	BlockT* blocks = new BlockT[m_y*x];
	multiCopy(blocks, m_blocks, place, x, m_x, m_y);
	multiCopy(blocks+place, m_blocks+place+amount, x-place, x, m_x, m_y);
	delete[] m_blocks;
	m_blocks = blocks;
	
	m_x = x;
}
