#pragma warning(disable:4996)

#include "IntelHEXRecord.hpp"

#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <vector>

using namespace std;

class IntelHEXRecordImpl {
public:
	string record;
	int length;
	string address;
	string type;
	string data;
};

IntelHEXRecord::IntelHEXRecord(string record)
		: impl_(new IntelHEXRecordImpl()) {
	if (record.at(0) == ':') {
		record = record.substr(1);
	}

	char* e;
	impl_->length = strtol(record.substr(0, 2).c_str(), &e, 16);
	impl_->record = record.substr(0, 2 + 4 + 2 + (impl_->length * 2));
	record = record.substr(2);
	impl_->address = record.substr(0, 4);
	record = record.substr(4);
	impl_->type = record.substr(0, 2);
	record = record.substr(2);
	impl_->data = record.substr(0, impl_->length * 2);
}

IntelHEXRecord::~IntelHEXRecord() {
	delete impl_;
}

int IntelHEXRecord::length() {
	return impl_->length;
}

string IntelHEXRecord::address() {
	return impl_->address;
}

string IntelHEXRecord::type() {
	return impl_->type;
}

string IntelHEXRecord::data() {
	return impl_->data;
}

string IntelHEXRecord::checksum() {
	// ２桁ずつを足し合わせる
	int total = 0;
	for (size_t i = 0; i < impl_->record.size(); i += 2) {
		char* e;
		total += strtol(impl_->record.substr(i, 2).c_str(), &e, 16);
	}

	// ２の補数の１６進表記の後ろ２桁の文字列を取得する
	char char_buffer[128];
	_itoa_s((~total) + 1, char_buffer, 128, 16);
	string result(char_buffer);
	result = result.substr(result.size() - 2);
	for (size_t i = 0; i < result.size(); ++i) {
		result[i] = toupper(result.at(i));
	}
	return result;
}

string IntelHEXRecord::record(bool colon) {
	string result;
	if (colon) {
		result.append(":");
	}

	result.append(impl_->record);
	result.append(checksum());

	return result;
}
