#include </home/jasper/uni/i-edge/application/plugins/cpp-dump/cpp-dump.hpp>
#include "kernel/rtlil.h"
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"

#include <string>
#include <map>
#include <set>


USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

//Set up pair to map signal to cell driver or trigger
typedef std::pair<RTLIL::Cell*, RTLIL::IdString> sig2driver_entry_t;
static SigSet<sig2driver_entry_t> sig2driver, sig2trigger;

void build_database(RTLIL::Design *design, SigMap *sigmap){
    log("Building database of all cells and their matching connections /n");

    CellTypes ct(design);

		for (auto mod : design->selected_modules())
		{
			
			sig2driver.clear();
			sig2trigger.clear();
			for (auto cell : mod->cells()) {
				for (auto &conn_it : cell->connections()) {
					
					if (ct.cell_output(cell->type, conn_it.first) || !ct.cell_known(cell->type)) {
						RTLIL::SigSpec sig = conn_it.second;
						sigmap->apply(sig);
						sig2driver.insert(sig, sig2driver_entry_t(cell, conn_it.first));
					}
					if (ct.cell_input(cell->type, conn_it.first) && cell->hasPort(ID::Y) &&
							cell->getPort(ID::Y).size() == 1 && (conn_it.first == ID::A || conn_it.first == ID::B)) {
						RTLIL::SigSpec sig = conn_it.second;
					    sigmap->apply(sig);
						sig2trigger.insert(sig, sig2driver_entry_t(cell, conn_it.first));
					}
				}
			}
        }
}

struct MyPass : public Pass {
    MyPass() : Pass("my_cmd", "just a simple test") { }

    void execute(std::vector<std::string> args, RTLIL::Design *design) override
    {
        log("Arguments to my_cmd:\n");
        for (auto &arg : args)
            log(" %s\n", arg.c_str());

        
        
        log("Modules in current design:\n");
        for (auto mod : design->modules())
        {

            // Instantiate SigMap for the current module
            SigMap sigmap(mod);

            build_database(design, &sigmap);

            log(" %s (%d wires, %d cells)\n", log_id(mod), GetSize(mod->wires()), GetSize(mod->cells()));

 

            for (auto wire : mod->wires())
            {
                // Use sigmap to canonicalize the signal
                RTLIL::SigSpec sig = sigmap(wire);

                log("----------/------------\n");
                //print all info on the wire itself
                log("current wire %s, width: %d, start_offset %d, port_id %d, port_input %d, port_output %d, upto %d, is_signed %d, %s \n",
                    log_id(wire->name), wire->width, wire->start_offset, wire->port_id, wire->port_input, wire->port_output, wire->upto, wire->is_signed, log_id(wire->name));
                log("Out: %d, in: %d \n",wire->port_output,wire->port_input);
            }
                log("----------/------------\n");
            for (auto cell : mod->cells()){
                log("current cell: %s, type %s\n",log_id(cell->name),log_id(cell->type));
                for( auto cellport_list : cell->connections_){
                    RTLIL::SigSpec sigInCell = cellport_list.second;
                    log("in pair: %s, connection to: %s\n",log_id(cellport_list.first),(sigInCell.is_wire() ? log_id(sigInCell.as_wire()->name): "not wire"));
                    std::set<sig2driver_entry_t> cellport_test;
                    sig2driver.find(sigInCell, cellport_test);
                    for(auto cell: cellport_test){
                        log("for %s find result: %s:%s, %s\n",(sigInCell.is_wire() ? log_id(sigInCell.as_wire()->name): "not wire"),log_id(cell.first),log_id(cell.first->type),log_id(cell.second));
                    }
                }
            }
        } 

    }
} MyPass;

PRIVATE_NAMESPACE_END
