import numpy as np

def get_addresses(groups, i, s, d, lim): #function [i, s, d, lim] = get_addresses(groups, i, s, d, lim)

    #% Initiate any sets not so far covered by s
    if len(s)!=0: #~isempty(s)
       fnames = list(s)#s.keys() #fnames = fieldnames(s);
    else:
       fnames = {} #fnames = {};
    #end
       
    for ig in range(len(groups)):#in groups: #ig = 1:length(groups)
        gp = groups[ig] #gp = groups {ig};
        for ig2 in gp: #for ig2 in gp :#ig2 = 1:length(gp) 
            if not np.isin(ig2,fnames): #if ~ismember(gp{ig2},fnames)
                s[ig2] = [] #s[gp[ig2]] = []; #s.(gp{ig2}) = [];
            #end
        #end
    #end

    if len(groups) == 1: #length(groups) == 1
        gp1 = groups[0] #gp1 = groups{1};
        for ig1 in gp1: #for ig1 in range(len(gp1)): #ig1 = 1:length(gp1)
            #lim = lim+1 #lim = lim+1;
            i[ig1] = np.array([lim])
            #i = dict({ig1: lim}) #i[ig1] = lim #i[gp1[ig1]] = lim #i.(gp1{ig1}) = lim;
            s[ig1] = np.append(s[ig1], lim).astype(int) #s[gp1[ig1]] = [s[gp1[ig1]], lim] #s.(gp1{ig1}) = [s.(gp1{ig1}), lim];
            d[lim] = [ig1] #d[lim] = [gp1[ig1]]
            lim = lim+1 #lim = lim+1; #Changed the position here because indexing in Python is not the same as in Matlab
        #end
    #end

    if len(groups) == 2 :#length(groups) == 2
        gp1 = groups[0]; gp2 = groups[1] #gp1 = groups{1}; gp2 = groups{2} #gp1 = groups{1}; gp2 = groups{2};
    
        for ig1 in gp1: #for ig1 in range(len(gp1)): #ig1 = 1:length(gp1)
            i[ig1] = {}
            for ig2 in range(len(gp2)): #for ig2 in range(len(gp2)): #ig2 = 1:length(gp2)
                #lim = lim+1 #lim = lim+1;
                i[ig1][ig2] = np.array([lim])
                #i = dict({ig1: dict({ig2: lim})}) #i[ig1][ig2] = lim #i[gp1[ig1]][gp2[ig2]] = lim #i.(gp1{ig1}).(gp2{ig2}) = lim;
                s[ig1] = np.append(s[ig1], lim).astype(int) #s[gp1[ig1]] = [s[gp1[ig1]], lim] #s.(gp1{ig1}) = [s.(gp1{ig1}), lim];
                s[ig2] = np.append(s[ig2], lim).astype(int) #s[gp2[ig2]] = [s[gp2[ig2]], lim] #s.(gp2{ig2}) = [s.(gp2{ig2}), lim];
                d[lim] = [ig1, ' ', ig2] #d[lim] = [gp1[ig1], ' ', gp2[ig2]] #d{lim} = [gp1{ig1}, ' ', gp2{ig2}];
                lim = lim+1 #lim = lim+1; #Changed the position here because indexing in Python is not the same as in Matlab
            #end
        #end
    #end

    if len(groups) == 3: #length(groups) == 3
        gp1 = groups[0]; gp2 = groups[1]; gp3 = groups[2]#gp1 = groups{1}; gp2 = groups{2}; gp3 = groups{3};
        for ig1 in range(len(gp1)): #for ig1 in range(len(gp1)): #ig1 = 1:length(gp1)
            i[ig1] = {}
            for ig2 in gp2: #for ig2 in range(len(gp2)): #ig2 = 1:length(gp2)
                i[ig1][ig2] = {}
                for ig3 in gp3: #for ig3 in range(len(gp3)): #ig3 = 1:length(gp3)
                    #lim = lim+1#lim = lim+1;
                    i[ig1][ig2][ig3] = np.array([lim])
                    #i = dict({ig1: dict({ig2: dict({ig3 : lim})})}) #i[ig1][ig2][ig3] = lim #i.(gp1{ig1}).(gp2{ig2}).(gp3{ig3}) = lim;
                    s[ig1] = np.append(s[ig1], lim).astype(int)#s.(gp1{ig1}) = [s.(gp1{ig1}), lim];
                    s[ig2] = np.append(s[ig2], lim).astype(int) #s[gp2[ig2]] = [s[gp2[ig2]], lim] #s.(gp2{ig2}) = [s.(gp2{ig2}), lim];
                    s[ig3] = np.append(s[ig3], lim).astype(int) #s[gp3[ig3]] = [s[gp3[ig3]], lim] #s.(gp3{ig3}) = [s.(gp3{ig3}), lim];
                    d[lim] = [ig1,  ' ', ig2,  ' ', ig3] #d[lim] = [gp1[ig1],  ' ', gp2[ig2],  ' ', gp3[ig3]] #d{lim} = [gp1{ig1},  ' ', gp2{ig2},  ' ', gp3{ig3}];
                    lim = lim+1 #lim = lim+1; #Changed the position here because indexing in Python is not the same as in Matlab
                #end
            #end
        #end
    #end

    if len(groups) == 4 :#length(groups) == 4
        gp1 = groups[0]; gp2 = groups[1]; gp3 = groups[2]; gp4 = groups[3] #gp1 = groups{1}; gp2 = groups{2}; gp3 = groups{3}; gp4 = groups{4};
        for ig1 in gp1: #for ig1 in range(len(gp1)): #ig1 = 1:length(gp1)
            i[ig1] = {}
            for ig2 in gp2: #for ig2 in range(len(gp2)): #for ig2 = 1:length(gp2)
                i[ig1][ig2] = {}
                for ig3 in gp3: #for ig3 in range(len(gp3)): #for ig3 = 1:length(gp3)
                    i[ig1][ig2][ig3] = {}
                    for ig4 in gp4: #for ig4 in range(len(gp4)): #for ig4 = 1:length(gp4)
                        #lim = lim+1 #lim = lim+1;
                        #i4 = dict({ig4:lim}); i3 = dict({ig3 : i4}); i2 = dict({ig2: i3})
                        i[ig1][ig2][ig3][ig4] = np.array([lim])
                        #i = dict({ig1: dict({ig2: dict({ig3 : dict({ig4:lim})})})}) #i[ig1][ig2][ig3][ig4] = lim#i[gp1[ig1]][gp2[ig2]][gp3[ig3]][gp4[ig4]] = lim#i.(gp1{ig1}).(gp2{ig2}).(gp3{ig3}).(gp4{ig4}) = lim;
                        s[ig1] = np.append(s[ig1], lim).astype(int)#s[gp1[ig1]] = [s[gp1[ig1]], lim]#s.(gp1{ig1}) = [s.(gp1{ig1}), lim];
                        s[ig2] = np.append(s[ig2], lim).astype(int) #s[gp2[ig2]] = [s[gp2[ig2]], lim] #s.(gp2{ig2}) = [s.(gp2{ig2}), lim];
                        s[ig3] = np.append(s[ig3], lim).astype(int) #s[gp3[ig3]] = [s[gp3[ig3]], lim] #s.(gp3{ig3}) = [s.(gp3{ig3}), lim];
                        s[ig4] = np.append(s[ig4], lim).astype(int) #s[gp4[ig4]] = [s[gp4[ig4]], lim] #s.(gp4{ig4}) = [s.(gp4{ig4}), lim];
                        d[lim] = [ig1,  ' ', ig2,  ' ', ig3,  ' ', ig4]#d[lim] = [gp1[ig1],  ' ', gp2[ig2],  ' ', gp3[ig3],  ' ', gp4[ig4]]#d{lim} = [gp1{ig1},  ' ', gp2{ig2},  ' ', gp3{ig3},  ' ', gp4{ig4}];
                        lim = lim+1 #lim = lim+1; #Changed the position here because indexing in Python is not the same as in Matlab
                    #end
                #end
            #end
        #end
    #end


    if len(groups) == 5: #length(groups) == 5
        gp1 = groups[0]; gp2 = groups[1]; gp3 = groups[2]; gp4 = groups[3]; gp5 = groups[4] #gp1 = groups{1}; gp2 = groups{2}; gp3 = groups{3}; gp4 = groups{4}; gp5 = groups{5};
        for ig1 in gp1: #for ig1 in range(len(gp1)): #ig1 = 1:length(gp1)
            i[ig1] = {}
            for ig2 in gp2: #for ig2 in range(len(gp2)): #ig2 = 1:length(gp2)
                i[ig1][ig2] = {}
                for ig3 in gp3: #for ig3 in range(len(gp3)): #ig3 = 1:length(gp3)
                    i[ig1][ig2][ig3] = {}
                    for ig4 in gp4: #for ig4 in range(len(gp4)): #ig4 = 1:length(gp4)
                        i[ig1][ig2][ig3][ig4] = {}
                        for ig5 in gp5: #for ig5 in range(len(gp5)): #ig5 = 1:length(gp5)
                            #lim = lim+1 #lim = lim+1;
                            i[ig1][ig2][ig3][ig4] [ig5] = np.array([lim])
                            #i = dict({ig1: dict({ig2: dict({ig3 : dict({ig4: dict({ig5: lim})})})})}) #i[ig1][ig2][ig3][ig4][ig5] = lim #i[gp1[ig1]][gp2[ig2]][gp3[ig3]][gp4[ig4]][gp5[ig5]] = lim #i.(gp1{ig1}).(gp2{ig2}).(gp3{ig3}).(gp4{ig4}).(gp5{ig5}) = lim;
                            s[ig1] = np.append(s[ig1], lim).astype(int) #s[gp1[ig1]] = [s[gp1[ig1]], lim] #s.(gp1{ig1}) = [s.(gp1{ig1}), lim];
                            s[ig2] = np.append(s[ig2], lim).astype(int)  #s[gp2[ig2]] = [s[gp2[ig2]], lim]  #s.(gp2{ig2}) = [s.(gp2{ig2}), lim];
                            s[ig3] = np.append(s[ig3], lim).astype(int) #s[gp3[ig3]] = [s[gp3[ig3]], lim] #s.(gp3{ig3}) = [s.(gp3{ig3}), lim];
                            s[ig4] = np.append(s[ig4], lim).astype(int) #s[gp4[ig4]] = [s[gp4[ig4]], lim] #s.(gp4{ig4}) = [s.(gp4{ig4}), lim];
                            s[ig5] = np.append(s[ig5], lim).astype(int) #s[gp5[ig5]] = [s[gp5[ig5]], lim] #s.(gp5{ig5}) = [s.(gp5{ig5}), lim];
                            d[lim] = [ig1,  ' ', ig2,  ' ', ig3,  ' ', ig4,  ' ', ig5] #d[lim] = [gp1[ig1],  ' ', gp2[ig2],  ' ', gp3[ig3],  ' ', gp4[ig4],  ' ', gp5[ig5]] #d{lim} = [gp1{ig1},  ' ', gp2{ig2},  ' ', gp3{ig3},  ' ', gp4{ig4},  ' ', gp5{ig5}];
                            lim = lim+1 #lim = lim+1; #Changed the position here because indexing in Python is not the same as in Matlab
                        #end
                    #end
                #end
            #end
        #end
    #end
    i['nstates'] = lim #i.nstates = lim;

    return([i, s, d, lim])