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

#include "util.h"

#include <fstream>

namespace {
/* Format example:
build/src/libctor_a-libctor_cc.o: src/libctor.cc \
 src/getoptpp/getoptpp.hpp src/ctor.h src/configure.h src/rebuild.h \
 src/A\ B\ C.h src/task.h src/build.h src/unittest.h
 */
std::vector<std::string> readDepsMake(const std::string& dep_file)
{
	auto str = readFile(dep_file);

	std::vector<std::string> output;
	std::string tmp;

	enum class State
	{
		pre_colon,
		post_colon,
		in_escape,
	} state{State::pre_colon};

	auto old_state{state};
	for(const auto& c : str)
	{
		if(c == '\r')
		{
			// just always ignore windows extra newline char
			continue;
		}

		switch(state)
		{
		case State::pre_colon:
			if(c == ':') // ignore everything until the colon
			{
				state = State::post_colon;
				continue;
			}
			continue;

		case State::post_colon:
			if(c == '\n')
			{
				// done
				if(!tmp.empty())
				{
					output.emplace_back(tmp);
				}
				return output;
			}
			if(c == '\\')
			{
				old_state = state;
				state = State::in_escape;
				continue;
			}
			if(c == '\t' || c == ' ') // new token
			{
				if(!tmp.empty())
				{
					output.emplace_back(tmp);
				}
				tmp.clear();
				continue;
			}
			break;

		case State::in_escape:
			if(c == '\n')
			{
				// linewrap
				state = old_state;
				continue;
			}
			state = old_state;
			break;
		}

		tmp += c;
	}

	if(!tmp.empty())
	{
		output.emplace_back(tmp);
	}

	return output;
}
}

std::vector<std::string> readDeps(const std::string& dep_file,
                                  ctor::toolchain toolchain)
{
	if(!std::filesystem::exists(dep_file))
	{
		return {};
	}

	switch(toolchain)
	{
	case ctor::toolchain::any:
	case ctor::toolchain::none:
		return {};

	// makefile .d file based:
	case ctor::toolchain::gcc:
	case ctor::toolchain::clang:
		return readDepsMake(dep_file);
	}

	return {};
}