// -*- c++ -*-
// Distributed under the BSD 2-Clause License.
// See accompanying file LICENSE for details.
#include "task.h"

#include <unistd.h>
#include <iostream>

#include "settings.h"

Task::Task(const BuildConfiguration& config, const Settings& settings,
           const std::string& sourceDir)
	: config(config)
	, output_system(config.system)
	, settings(settings)
	, sourceDir(sourceDir)
{
}

int Task::registerDepTasks(const std::set<std::shared_ptr<Task>>& tasks)
{
	for(const auto& depStr : depends())
	{
		bool found{false};
		for(const auto& task : tasks)
		{
			if(*task == depStr)
			{
				dependsTasks.insert(task);
				found = true;
			}
		}
		if(!found)
		{
			std::cerr << "Could not find dependency " << depStr << " needed by " <<
				target() << " target\n";
			return 1;
		}
	}

	return 0;
}

bool Task::operator==(const std::string& depStr)
{
	return
		name() == depStr ||
		target() == depStr ||
		sourceDir + "/" + target() == depStr ||
		targetFile().string() == depStr
		;
}

std::string Task::name() const
{
	return config.name;
}

bool Task::dirty()
{
	for(const auto& task : dependsTasks)
	{
		if(task->dirty())
		{
			return true;
		}
	}

	return dirtyInner();
}

bool Task::ready()
{
	for(const auto& task : dependsTasks)
	{
		if(task->dirty() || task->state() == State::Running)
		{
			return false;
		}
	}

	task_state.store(State::Ready);
	return true;
}

int Task::run()
{
	if(task_state.load() == State::Done)
	{
		return 0;
	}

	task_state.store(State::Running);
	auto ret = runInner();
	if(ret == 0)
	{
		task_state.store(State::Done);
	}
	else
	{
		task_state.store(State::Error);
	}

	return ret;
}

State Task::state() const
{
	return task_state.load();
}

const BuildConfiguration& Task::buildConfig() const
{
	return config;
}

TargetType Task::targetType() const
{
	return target_type;
}

Language Task::sourceLanguage() const
{
	return source_language;
}

OutputSystem Task::outputSystem() const
{
	return output_system;
}

std::string Task::compiler() const
{
	switch(sourceLanguage())
	{
	case Language::C:
		switch(outputSystem())
		{
		case OutputSystem::Host:
			return getConfiguration(cfg::host_cc, "/usr/bin/gcc");
		case OutputSystem::Build:
			return getConfiguration(cfg::build_cc, "/usr/bin/gcc");
		}
	case Language::Cpp:
		switch(outputSystem())
		{
		case OutputSystem::Host:
			return getConfiguration(cfg::host_cxx, "/usr/bin/g++");
		case OutputSystem::Build:
			return getConfiguration(cfg::build_cxx, "/usr/bin/g++");
		}
	default:
		std::cerr << "Unknown CC target type\n";
		exit(1);
		break;
	}
}

std::set<std::shared_ptr<Task>> Task::getDependsTasks()
{
	return dependsTasks;
}