#include "loader.h"
#include "machine.h"

Loader::Loader() {}

int Loader::readByte(std::istream &in) {
    char c1, c2;
    if (!in.get(c1) || !in.get(c2)) {
        return -1;
    }
    std::string byte;
    byte += c1;
    byte += c2;
    return std::stoi(byte, nullptr, 16);
}

int Loader::readWord(std::istream &in) {
    int result = 0;
    for (int i = 0; i < 3; i++) {
        int byte = readByte(in);
        if (byte < 0) return -1;
        result = (result << 8) | byte;
    }
    return result;
}

std::string Loader::readString(std::istream &in, int len) {
    std::string result;
    for (int i = 0; i < len; i++) {
        char c;
        if (!in.get(c)) break;
        result += c;
    }
    return result;
}

void skipNewline(std::istream& stream) {
    if (stream.peek() == '\r') {
        stream.get();  // odstrani \r
    }
    if (stream.peek() == '\n') {
        stream.get();  // odstrani \n
    }
}


bool Loader::loadSection(Machine& machine, std::istream& stream) {
    if (stream.get() != 'H') return false;
    readString(stream, 6);  // ime programa ignoriramo
    int start = readWord(stream);
    int length = readWord(stream);
    skipNewline(stream);
    // Preberi text zapise
    int ch = stream.get();
    while (ch == 'T') {
        int loc = readWord(stream);
        int len = readByte(stream);
        while (len-- > 0) {
            if (loc < start || loc >= start + length) return false;
            int val = readByte(stream);
            machine.writeByte(loc++, static_cast<unsigned char>(val));
        }
        skipNewline(stream);
        ch = stream.get();
    }

    // End zapis
    if (ch != 'E') return false;
    machine.setPC(readWord(stream));
    return true;
}

bool Loader::loadObj(Machine& machine, const std::string& filename) {
    std::ifstream file(filename);
    if (!file.is_open()) {
        std::cerr << "Napaka pri odpiranju datoteke: " << filename << "\n";
        return false;
    }
    return loadSection(machine, file);
}

