/*!
 * Copyright (c) <2023> <Andreas Niskanen, University of Helsinki>
 * 
 * 
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * 
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifdef DEBUG
#include <iostream>
#endif

#include "DynamicAF.h"

using namespace std;

DynamicAF::DynamicAF() : args(0), count(0) {
	static_mode = true;
#if defined(DYNAMIC_MODE)
	static_mode = false;
#endif
}

bool DynamicAF::add_argument(int32_t arg)
{
	if (arg < 0) return false;
	if (arg_to_int.count(arg) > 0) {
		return false;
	}
#ifdef DEBUG
	cout << "c Adding argument " << arg << "\n";
#endif
	int_to_arg.push_back(arg);
	arg_to_int[arg] = args++;
	attackers.push_back({});
	arg_exists.push_back(true);
	arg_encoded.push_back(false);
	atts_encoded.push_back(false);
	accepted_var.push_back(++count);
#ifdef DEBUG
	var_to_str[count] = "in(" + to_string(arg) + ")";
#endif
	rejected_var.push_back(++count);
#ifdef DEBUG
	var_to_str[count] = "out(" + to_string(arg) + ")";
#endif
	range_var.push_back(++count);
#ifdef DEBUG
	var_to_str[count] = "range(" + to_string(arg) + ")";
#endif
	arg_exists_var.push_back(++count);
#ifdef DEBUG
	var_to_str[count] = "exists(" + to_string(arg) + ")";
#endif
	return true;
}

bool DynamicAF::del_argument(int32_t arg)
{
	if (arg < 0) return false;
	if (arg_to_int.count(arg) == 0) {
		return false;
	}
#ifdef DEBUG
	cout << "c Deleting argument " << arg << "\n";
#endif
	int32_t arg_index = arg_to_int[arg];
	arg_exists[arg_index] = false;
	arg_to_int.erase(arg);
	attackers[arg_index].clear();
	for (uint32_t i = 0; i < args; i++) {
		auto it = attackers[i].find(arg_index);
		if (it != attackers[i].end()) {
			attackers[i].erase(it);
			atts_encoded[i] = false;
		}
	}
	return true;
}

bool DynamicAF::add_attack(int32_t source, int32_t target)
{
	if (source < 0 || target < 0) return false;
	if (arg_to_int.count(source) == 0 || arg_to_int.count(target) == 0) {
		return false;
	}
	int32_t source_index = arg_to_int[source];
	int32_t target_index = arg_to_int[target];
	if (!arg_exists[source_index] || !arg_exists[target_index]) {
		return false;
	}
	auto it = attackers[target_index].find(source_index);
	if (it != attackers[target_index].end()) {
		return false;
	}
#ifdef DEBUG
	cout << "c Adding attack " << source << "->" << target << "\n";
#endif
	attackers[target_index].insert(source_index);
	atts_encoded[target_index] = false;
	return true;
}

bool DynamicAF::del_attack(int32_t source, int32_t target)
{
	if (source < 0 || target < 0) return false;
	if (arg_to_int.count(source) == 0 || arg_to_int.count(target) == 0) {
		return false;
	}
	int32_t source_index = arg_to_int[source];
	int32_t target_index = arg_to_int[target];
	if (!arg_exists[source_index] || !arg_exists[target_index]) {
		return false;
	}
	auto it = attackers[target_index].find(source_index);
	if (it == attackers[target_index].end()) {
		return false;
	}
#ifdef DEBUG
	cout << "c Deleting attack " << source << "->" << target << "\n";
#endif
	attackers[target_index].erase(it);
	atts_encoded[target_index] = false;
	return true;
}

void DynamicAF::set_encoded()
{
	for (uint32_t i = 0; i < args; i++) {
		if (arg_exists[i]) {
			arg_encoded[i] = true;
			atts_encoded[i] = true;
		}
	}
}

void DynamicAF::set_not_encoded()
{
	for (uint32_t i = 0; i < args; i++) {
		arg_encoded[i] = false;
		atts_encoded[i] = false;
	}
}