/*
 * 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 Export;

import API.Utils;
import java.io.File;
import java.io.FileNotFoundException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
import tools.mips.Memory;
import tools.mips.MemoryImportExportInterface;

/**
 *
 * @author Eugenio
 */
public class MemoryInitializationFile implements MemoryImportExportInterface {
    
    public MemoryInitializationFile() {
        
    }
    
    @Override
    public void FromFile(Memory memory) throws Exception {
        String value;
        String[] parts;
        Scanner sc;
        String current = Paths.get(".").toAbsolutePath().normalize().toString();
        // Tenta carregar o arquivo
        boolean read = false;
        try {
            sc = new Scanner(new File(current + memory.File()));
        } catch (FileNotFoundException e) {
            throw new Exception(String.format("O arquivo da memoria não foi encontrado. %s", memory.File()));
        }
        
        while (sc.hasNextLine()) {
            value = sc.nextLine();
            if (value.equals("")) {
                continue;
                // Se encontra o fim do arquivo
            } else if (value.equals("END;")) {
                break;
            } else if (!read) {
                // Se ainda não iniciou a leitura
                // Busca o inicio das palavras
                if (value.equals("BEGIN")) {
                    read = true;
                }
                continue;
                //Se for o inicio de um intervalo vazio de palavras
            } else if (value.charAt(0) == '[') {
                continue;
            }
            // trata e escreve o valor na memória
            parts = value.replaceAll("\\s+", "").split(":");
            memory.W(Long.parseLong(parts[0], 10), parts[1].split(";")[0], 4);
        }
    }
    
    @Override
    public String DumpFile(Memory memory) throws Exception {
        
        String out = Header(memory);
        
        Long address, base = 0L;
        ArrayList<String> buffer = new ArrayList<>();
        TreeMap<Long, String> data = memory.Data();
        Integer pad = data.lastKey().toString().length();
        
        for (Map.Entry<Long, String> o : data.entrySet()) {
            address = o.getKey();
            
            if (address % memory.WORD_BYTES_COUNT == 0) {
                out += Append(base, buffer, pad);
                
                if ((address - base) > memory.WORD_BYTES_COUNT) {
                    out += String.format(
                            "[%d..%d]:\t00000000000000000000000000000000;\n",
                            base + memory.WORD_BYTES_COUNT,
                            address - memory.WORD_BYTES_COUNT
                    );
                }
                base = address;
                buffer = new ArrayList<>();
            }
            buffer.add(o.getValue());
            
        }
        
        out += Append(base, buffer, pad);
        
        out += Footer(memory);
        
        return out;
    }
    
    protected static String Append(Long base, ArrayList<String> buffer, Integer pad) {
        String out = "", bin;
        if (!buffer.isEmpty()) {
            bin = Utils.Join(buffer, "");
            out = Utils.Pad(pad, "" + base)
                    + ":\t"
                    + bin
                    + ";\t% dec "
                    + Long.parseUnsignedLong(Utils.padPreserveSignal(64, bin), 2)
                    + " %\n";
        }
        return out;
    }
    
    protected static String Header(Memory m) {
        return "-- Copyright (C) 1991-2014 Altera Corporation. All rights reserved.\n"
                .concat("-- Your use of Altera Corporation's design tools, logic functions\n")
                .concat("-- and other software and tools, and its AMPP partner logic\n")
                .concat("-- functions, and any output files from any of the foregoing\n")
                .concat("-- (including device programming or simulation files), and any\n")
                .concat("-- associated documentation or information are expressly subject\n")
                .concat("-- to the terms and conditions of the Altera Program License\n")
                .concat("-- Subscription Agreement, the Altera Quartus II License Agreement,\n")
                .concat("-- the Altera MegaCore Function License Agreement, or other\n")
                .concat("-- (including device programming or simulation files), and any\n")
                .concat("-- applicable license agreement, including, without limitation,\n")
                .concat("-- that your use is for the sole purpose of programming logic \n")
                .concat("-- devices manufactured by Altera and sold by Altera or its \n")
                .concat("-- authorized distributors.  Please refer to the applicable \n")
                .concat("-- agreement for further details.\n")
                .concat("-- Quartus II generated Memory Initialization File (.mif)\n")
                .concat("\n")
                .concat("WIDTH = " + m.WordBitSize() + ";\n")
                .concat("DEPTH = " + m.Size() + ";\n\n")
                .concat("ADDRESS_RADIX = DEC;\n")
                .concat("DATA_RADIX = BIN;\n\n")
                .concat("CONTENT\nBEGIN\n");
    }
    
    protected static String Footer(Memory m) {
//        String inst = Utils.Pad(wordSize, "");
//
//        appendLine("\t[" + seHex(InstructionCount(), 0)
//                + ".." + seHex(size - 1, 0) + "]\t:\t" + seHex(inst, 8) + ";");
        return "END;";
    }
    
}
