import importlib


class Toolchain:
    def __init__(self, config):
        self.config = config

    def generate(self, path):
        pins_generator = importlib.import_module(f".pins", f"riocore.generator.pins.qdf")
        pins_generator.Pins(self.config).generate(path)

        verilogs = " ".join(self.config["verilog_files"])
        clkname = "sysclk"
        family = self.config["family"]
        ftype = self.config["type"]

        makefile_data = []
        makefile_data.append("")
        makefile_data.append("# Toolchain: Quartus")
        makefile_data.append("")
        makefile_data.append("PROJECT   := rio")
        makefile_data.append("TOP       := rio")
        makefile_data.append(f"PART      := {ftype}")
        makefile_data.append(f'FAMILY    := "{family}"')
        makefile_data.append(f"VERILOGS  := {verilogs}")
        makefile_data.append("")
        makefile_data.append("QC   = quartus_sh")
        makefile_data.append("QP   = quartus_pgm")
        makefile_data.append("QM   = quartus_map")
        makefile_data.append("QF   = quartus_fit")
        makefile_data.append("QA   = quartus_asm")
        makefile_data.append("QS   = quartus_sta")
        makefile_data.append("ECHO = echo")
        makefile_data.append("Q   ?= @")
        makefile_data.append("")
        makefile_data.append("STAMP = echo done >")
        makefile_data.append("")
        makefile_data.append("QCFLAGS = --flow compile")
        makefile_data.append("QPFLAGS =")
        makefile_data.append("QMFLAGS = --read_settings_files=on $(addprefix --source=,$(VERILOGS))")
        makefile_data.append("QFFLAGS = --part=$(PART) --read_settings_files=on")
        makefile_data.append("")
        makefile_data.append("ASIGN = $(PROJECT).qsf $(PROJECT).qpf")
        makefile_data.append("")
        makefile_data.append("all: $(PROJECT)")
        makefile_data.append("")
        makefile_data.append("map: smart.log $(PROJECT).map.rpt")
        makefile_data.append("fit: smart.log $(PROJECT).fit.rpt")
        makefile_data.append("asm: smart.log $(PROJECT).asm.rpt")
        makefile_data.append("sta: smart.log $(PROJECT).sta.rpt")
        makefile_data.append("smart: smart.log")
        makefile_data.append("")
        makefile_data.append("$(ASIGN):")
        makefile_data.append('	$(Q)$(ECHO) "Generating asignment files."')
        makefile_data.append("	$(QC) --prepare -f $(FAMILY) -t $(TOP) $(PROJECT)")
        makefile_data.append("	echo >> $(PROJECT).qsf")
        makefile_data.append("	cat pins.qdf >> $(PROJECT).qsf")
        makefile_data.append("")
        makefile_data.append("smart.log: $(ASIGN)")
        makefile_data.append('	$(Q)$(ECHO) "Generating smart.log."')
        makefile_data.append("	$(QC) --determine_smart_action $(PROJECT) > smart.log")
        makefile_data.append("")
        makefile_data.append("$(PROJECT): smart.log $(PROJECT).asm.rpt $(PROJECT).sta.rpt")
        makefile_data.append("")
        makefile_data.append("$(PROJECT).map.rpt: map.chg $(VERILOGS)")
        makefile_data.append("	$(QM) $(QMFLAGS) $(PROJECT)")
        makefile_data.append("	$(STAMP) fit.chg")
        makefile_data.append("")
        makefile_data.append("$(PROJECT).fit.rpt: fit.chg $(PROJECT).map.rpt")
        makefile_data.append("	$(QF) $(QFFLAGS) $(PROJECT)")
        makefile_data.append("	$(STAMP) asm.chg")
        makefile_data.append("	$(STAMP) sta.chg")
        makefile_data.append("")
        makefile_data.append("$(PROJECT).asm.rpt: asm.chg $(PROJECT).fit.rpt")
        makefile_data.append("	$(QA) $(PROJECT)")
        makefile_data.append("")
        makefile_data.append("$(PROJECT).sta.rpt: sta.chg $(PROJECT).fit.rpt")
        makefile_data.append("	$(QS) $(PROJECT)")
        makefile_data.append("")
        makefile_data.append("map.chg:")
        makefile_data.append("	$(STAMP) map.chg")
        makefile_data.append("fit.chg:")
        makefile_data.append("	$(STAMP) fit.chg")
        makefile_data.append("sta.chg:")
        makefile_data.append("	$(STAMP) sta.chg")
        makefile_data.append("asm.chg:")
        makefile_data.append("	$(STAMP) asm.chg")
        makefile_data.append("")
        makefile_data.append("clean:")
        makefile_data.append('	$(Q)$(ECHO) "Cleaning."')
        makefile_data.append("	rm -rf db incremental_db")
        makefile_data.append("	rm -f smart.log *.rpt *.sof *.chg *.qsf *.qpf *.summary *.smsg *.pin *.jdi")
        makefile_data.append("")
        makefile_data.append("load: prog")
        makefile_data.append("prog: $(PROJECT).sof")
        makefile_data.append('	$(Q)$(ECHO) "Programming."')
        makefile_data.append('	$(QP) --no_banner --mode=jtag -o "P;$(PROJECT).sof"')
        makefile_data.append("")
        makefile_data.append("")
        open(f"{path}/Makefile", "w").write("\n".join(makefile_data))

        clock = self.config["speed"]
        sdc_data = []
        sdc_data.append("")
        sdc_data.append(f'create_clock -name {clkname} -period "{float(clock) / 1000000} MHz" [get_ports {clkname}]')
        sdc_data.append("derive_pll_clocks")
        sdc_data.append("derive_clock_uncertainty")
        sdc_data.append("")
        open(f"{path}/rio.sdc", "w").write("\n".join(sdc_data))
