#include <iostream>
#include<string>
#include<set>
#include<algorithm>

struct property {
	std::string name;
	int32_t value;

	bool same_name(property const& o) const {
		return name == o.name;
	}

	bool same_value(property const& o) const {
		return value == o.value;
	}

	bool operator==(property const& o) const {
		return same_name(o) && same_value(o);
	}

	bool operator<(property const& o) const {
		if (!same_name(o)) return name < o.name;
		else return value < o.value;
	}
};

std::set<property> tokenify(std::string input) {
	bool finding_name = true;
	property prop;
	std::set<property> properties;
	while (input.size() > 0) {
		auto colon_index = input.find(':');
		if (finding_name) {
			prop.name = input.substr(0, colon_index);
			finding_name = false;
		}
		else {
			prop.value = std::stoi(input.substr(0, colon_index));
			finding_name = true;
			properties.insert(prop);
		}
		if(colon_index == std::string::npos) 
			break;
		else 
			input = input.substr(colon_index + 1);
	}
	return properties;
}

std::string get_diff_string(std::string const& old_props, std::string const& new_props) {
	std::set<property> old_properties = tokenify(old_props);
	std::set<property> new_properties = tokenify(new_props);

	std::string output;

	for (property const& old_property : old_properties) {
		auto predicate = [&](property const& p) {
			return old_property.same_name(p);
		};
		auto it = std::find_if(new_properties.begin(), new_properties.end(), predicate);
		if (it == new_properties.end()) {
			//We didn't find the property.
			output.append("REMOVE:" + old_property.name + ':');
		}
		else if (!it->same_value(old_property)) {
			//Found the property, but the value changed.
			output.append(it->name + ':' + std::to_string(it->value) + ':');
		}
	}

	//Finally, we need to see which were added.
	for (property const& new_property : new_properties) {
		auto predicate = [&](property const& p) {
			return new_property.same_name(p);
		};
		auto it = std::find_if(old_properties.begin(), old_properties.end(), predicate);
		if (it == old_properties.end()) {
			//We didn't find the property.
			output.append("ADD:" + new_property.name + ':' + new_property.name + ':' + std::to_string(new_property.value) + ':');
		}
		//We already checked for changes in the previous loop, so now we don't care.
	}

	if (output.size() > 0)
		output = output.substr(0, output.size() - 1); //Trim off the last colon

	return output;
}

int main() {
	std::string diff_string = get_diff_string("MASTER:50:SYSTEM:50:STEAM:100:UPLAY:100", "MASTER:30:SYSTEM:50:STEAM:100:ROCKETLEAGUE:80:CHROME:100");
	std::cout << "Diff String was \"" << diff_string << '\"' << std::endl;
}