// Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <gdal_priv.h>
#include <functional>
#include <thread>
#include <future>

int main()
{
	// GDAL initialization.
	GDALAllRegister();	
	GDALSetCacheMax(1048576 * 1000); // 1GB aprox.

	// Vector with dataset files.
	std::vector<std::string> files;
	for (int i = 1; i < 3; i++)
	{
		std::string currFile = "Dataset_" + std::to_string(i) + ".grd";
		files.push_back(currFile);
	}

	// Functor for the threads.
	std::function<void(std::string)> funct = [=](std::string filePath)
	{
		// Open source DS.
		GDALDataset* poDSsource = (GDALDataset*)GDALOpen(filePath.c_str(), GA_ReadOnly);

		int sizeX = poDSsource->GetRasterXSize();
		int sizeY = poDSsource->GetRasterYSize();
		double noDataValue = poDSsource->GetRasterBand(1)->GetNoDataValue();
		GDALDataType datatype = poDSsource->GetRasterBand(1)->GetRasterDataType();

		// Create target DS.
		GDALDriver* driver = (GDALDriver*)GDALGetDriverByName("WIZARD");
		char** papszCreationOptions = NULL;
		papszCreationOptions = CSLAddNameValue(papszCreationOptions, "WIZARD_OLD_FILE_VER", "YES");
		papszCreationOptions = CSLAddNameValue(papszCreationOptions, "WIZARD_GRID_TYPE", "TERELEV");
		GDALDataset* poDStarget = driver->Create(std::string(filePath + ".out").c_str(), sizeX, sizeY, 1, datatype, papszCreationOptions);

		// ITERATION. Just copy pixels from source to target (increasing value by 1).
		for (int y = 0; y < sizeY; y++)
		{
			for (int x = 0; x < sizeX; x++)
			{
				short value;

				GDALRasterBlock* poBlockSource = poDSsource->GetRasterBand(1)->GetLockedBlockRef(0, y);
				void* poDataSource = poBlockSource->GetDataRef();
				value = ((short*)poDataSource)[x];
				poBlockSource->DropLock();

				GDALRasterBlock* poBlockTarget = poDStarget->GetRasterBand(1)->GetLockedBlockRef(0, y);
				void* poDataTarget = poBlockTarget->GetDataRef();
				((short*)poDataTarget)[x] = value + 1;
				poBlockTarget->MarkDirty();
				poBlockTarget->DropLock();
			}
		}

		// Close Dataset.
		GDALClose(poDSsource);
		GDALClose(poDStarget);

		// Destroy driver.
		GDALDestroyDriver(driver);
	};

	std::vector<std::future<void>> futures;
	for (std::string currFile : files)
	{
		futures.push_back(std::async(funct, currFile));
	}

	for (const std::future<void>& fut : futures)
	{
		fut.wait();
	}
	
	system("PAUSE");

	return 0;
}

