'''
This code is developed by professor Jørn Vatn. The code can be used
by students and employees at NTNU. The code comes with no warranties.

You are not allowed to use the code for commercial purposes without
written permission from Jørn Vatn
'''
FTA = []
AND = -1
OR = -2
import cutLib as c

def getMCS(ret='text',isDual=False):    
    MCSs = [[0]]
    moreToDo = True
    count = 0
    while moreToDo:
        count += 1
        moreToDo = False        
        if count > 1:
            count = 0
        for i in range(len(FTA)):
            gate = FTA[i]
            if gate[1] == AND:
                if c.expandH(MCSs, gate):
                    moreToDo = True
            else:
                if c.expandV(MCSs, gate):
                    moreToDo = True
    c.makeMinimal(MCSs)
    if isDual:
       for i, cut in enumerate(MCSs):
           for j in range(len(cut)):
             cut[j]=-cut[j]
           MCSs[i] = cut
    if ret == "text":
        return c.MCSs2txt(MCSs)
    else:
        
        return MCSs

def MOCUS(txtFTA,isDual=False):
    global FTA
    FTA = []
    if isDual: #Interchange AND and OR gates
        AND = -2
        OR = -1
    else:
        AND = -1
        OR = -2    
    c.initFTAstru()
    for ln in txtFTA:
      c.gate2num(ln[0])
    for ln in txtFTA:
      c.gate2num(ln[0])
      gate = [c.gate2num(ln[0]),0]  
      if ln[1] == "AND":
          gate[1] = AND
      elif ln[1]== "OR":
          gate[1] = OR
      for j in range(2,len(ln)):
          if c.isGate(ln[j]):
            gate.append(c.gate2num(ln[j]))
          else:
            gate.append(c.basic2num(ln[j]))             
      FTA.append(gate)
    return getMCS("",isDual)

def eventToCut(basic, isDual = False):
# To use in connection with ETA, when a barrier is a single event
    n = c.basic2num(basic)
    if isDual:
        n = -n
    return [[n]]   

def mergeCutSets(cut1, cut2, cut3=[], cut4=[], cut5=[]):
   if len(cut5)>0:
        return mergeCutSets(mergeCutSets(cut1, cut2, cut3, cut4),cut5)
   elif len(cut4)>0:
        return mergeCutSets(mergeCutSets(cut1, cut2, cut3),cut4)
   elif len(cut3)>0:
        return mergeCutSets(mergeCutSets(cut1, cut2),cut3)                     
   newCuts = []
   for c1 in cut1:
      for c2 in cut2:
         found = False
         for e1 in c1:
            if found:
               break
            for e2 in c2:
               if e1 == -e2:
                  found = True
                  break
         if not found:           
           newCut = c1+c2
           c.trimList(newCut)                      
           newCuts.append(sorted(newCut))   
   c.makeMinimal(newCuts)
   return newCuts

#  ***  M A I N   P R O G R A M   ***
#PSD system, fault tree: PSDTree
PSDTree=[  
["TOP", "OR", "PSDV", "LU", "PSW"],  
["PSDV", "OR", "PSDC", "PSDI", "Common"],  
["PSDI", "AND", "PSD1", "PSD2"],  
["PSW", "OR", "PSWC", "PSWI"],  
["PSWI", "AND", "PSW1", "PSW2"]  ]

#PSV system, fault tree: PSVTree
PSVTree = [  
["TOP", "OR", "PSVC", "PSVV", "Common"],  
["PSVV", "AND", "PSV1", "PSV2"] ]

print("Fault tree and dual fault tree for PSD-system:")
PSD=MOCUS(PSDTree)
PSDc=MOCUS(PSDTree,True)
print(c.MCSs2txt(PSD))
print(c.MCSs2txt(PSDc))

print("Fault tree and dual fault tree for PSV-system:")
PSV=MOCUS(PSVTree)
PSVc=MOCUS(PSVTree,True)
print(c.MCSs2txt(PSV))
print(c.MCSs2txt(PSVc))

print("4 - Rupture or explosion of separator:")
print(c.MCSs2txt(mergeCutSets(eventToCut("Init"), PSD, PSV, eventToCut("RD"))))
 
print("3 - Gas flowing out of rupture disc:")
print(c.MCSs2txt(mergeCutSets(eventToCut("Init"), PSD, PSV, eventToCut("RD", True))))
print("2 - Gas relieved to flare:")
print(c.MCSs2txt(mergeCutSets(eventToCut("Init"), PSD, PSVc)))
print("1 - Controlled shutdown, no gas 'lost':")
print(c.MCSs2txt(mergeCutSets(eventToCut("Init"), PSDc)))


