/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package tools.mips;

import API.Utils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;

/**
 *
 * @author EUGENIO CARVALHO
 */
public class Memory {

    protected boolean writable;
    protected String file;
    protected Integer size;
    protected LinkedHashMap<Long, Long> data = new LinkedHashMap<>();
    public boolean AllAddress = false;

    public Memory ReadOnly() {
        this.writable = false;
        return this;
    }

    public Memory Writable() {
        this.writable = true;
        return this;
    }

    public Memory(String filename, int size, boolean all) throws IOException {
        this.file = filename;
        this.size = size;
        this.AllAddress = all;
        if (all) {
            for (long i = 0; i < size; i += 4) {
                data.put(i, (long) 0);
            }
        }

        if (!filename.equals("")) {
            ReadFile();
        }
    }

    public void Reset() {
        for (long i = 0; i < size; i += 4) {
            data.put(i, (long) 0);
        }
    }

    @Override
    public String toString() {
        String out = "";
        for (Map.Entry<Long, Long> o : data.entrySet()) {
            out = out.concat(o.getKey() + "\t:\t" + o.getValue() + "\n");
        }

        return out;
    }

    protected void ReadFile() throws FileNotFoundException, IOException {
        String current = Paths.get(".").toAbsolutePath().normalize().toString();
//        String content = new String(Files.readAllBytes(Paths.get(current + file)));
//        System.out.println("current + this.file:" + current + this.file);
        long addr = -4;
        Scanner sc = new Scanner(new File(current + this.file));
        String value;
        String[] parts;
        while (sc.hasNextLine()) {
//            content += sc.nextLine() + "\n";
            value = sc.nextLine();
            if (value.equals("")) {
                continue;
            }

            parts = value.replaceAll("\\s+", "").split(":");
//            System.out.println("parts:" + new ArrayList<String>(Arrays.asList(parts)));
            if (parts.length == 1) {
                addr += 4;
            } else {
                addr = Long.parseLong(parts[0], 10);
                value = parts[1];
            }

//            System.out.println("Read:" + (long) addr + ":" + Long.parseLong(value, 10));
            data.put((long) addr, Long.parseLong(value, 10));
        }
//        System.out.println("ReadFiel:" + content);
    }

    public long R(long address) throws Exception {
        valid(address);
        return data.get((address + size) % size);
    }

    public void W(long address, long value) throws Exception {
        valid(address);
        data.put((address + size) % size, value);
    }

    protected void valid(long address) throws Exception {

//        System.out.println("VALID:" + address + ":" + size);
        if (Math.abs(address) > size) {
            throw new Exception("Address '" + address + "' out of range limit " + size + "!");
        }
    }

    public Memory Save() {
        return Save(file);
    }

    public Memory Save(String filename) {
        String out = "";
        for (Map.Entry<Long, Long> entry : data.entrySet()) {
            out = out.concat(Utils.pad(4, "" + entry.getKey()) + ":\t" + entry.getValue() + "\n");
        }
        Utils.WriteFile(filename, out);

        return this;
    }

}
