import ast

from enum import Enum

from himesis_utils import graph_to_dot


class MutationOperators(Enum):
    RENAME_CLASS = "RENAME"
    DELETE_ELEMENT = "DELETE"

    #CLASSES:
    #Replace class with another class
    #Add/remove classes
    #Change Any/Exists type of classes
    #Change positive/negative type of classes

    #ASSOCIATIONS:
    #Remove/add associations
    #Change class of associations
    #Change positive/negative associations
    #Change direct/indirect associations

    #BACKWARD LINKS
    #Add/remove backward links
    #Change negative/positive

    #ATTRIBUTES
    #Add/remove attributes
    #Change match attrib
    #Change Atom value (what values?)
    #Change apply attrib
    #Change target of attribRef
    #Concat, prefer one or the other side

class Mutator:

    def __init__(self, rule_to_mutate, mutate):
        self.rule_to_mutate = rule_to_mutate
        self.mutate = ast.literal_eval(mutate)

        self.structural_classes = ["MatchModel", "ApplyModel", "paired_with",
                                   "match_contains", "apply_contains"
                                   ]
        self.link_classes = ["directLink_S", "directLink_T", "backward_link"]

    def mutate_rules(self, rules, transformation):

        for i, layer in enumerate(transformation):
            for j, rule in enumerate(layer):
                if self.rule_to_mutate == rule.name:
                    # self.print_rule(rule)
                    self.mutate_rule(rule)
                    # self.print_rule(rule)

                    rules[rule.name] = rule

        #raise Exception()
        return rules, transformation

    def mutate_rule(self, rule):

        print("Mutating " + rule.name + " with " + str(self.mutate))

        op = self.mutate[0]

        if op == MutationOperators.RENAME_CLASS.name:
            op, node_num, change = self.mutate

            rule.vs[node_num]["mm__"] = change

        elif op == MutationOperators.DELETE_ELEMENT.name:
            op, node_num = self.mutate

            assoc_nodes = []
            for edge in rule.es:
                if edge.source == node_num and rule.vs[edge.target]["mm__"] in self.link_classes:
                    assoc_nodes.append(edge.target)
                elif edge.target == node_num and rule.vs[edge.source]["mm__"] in self.link_classes:
                    assoc_nodes.append(edge.source)

            rule.delete_nodes([node_num] + assoc_nodes)

        else:
            raise Exception("Unknown mutation operator: " + op)

    def print_rule(self, rule):
        for v in rule.vs:
            print(v["mm__"])
@@ -33,16 +33,21 @@
 m%0A%0Afrom 
+core.
 himesis_
@@ -1202,16 +1202,43 @@
 link%22%5D%0A%0A
+        self.debug = True%0A%0A
     def 
@@ -1426,24 +1426,25 @@
  rule.name:%0A
+%0A
             
@@ -1446,37 +1446,35 @@
             
- #
  self.
-print
+debug
 _rule(rule)%0A
@@ -1463,32 +1463,38 @@
 .debug_rule(rule
+, True
 )%0A              
@@ -1545,21 +1545,19 @@
     
- #
  self.
-print
+debug
 _rul
@@ -1562,16 +1562,23 @@
 ule(rule
+, False
 )%0A%0A     
@@ -2213,32 +2213,71 @@
 elf.link_classes
+ + %5B%22match_contains%22, %22apply_contains%22%5D
 :%0A              
@@ -2412,16 +2412,55 @@
 _classes
+ + %5B%22match_contains%22, %22apply_contains%22%5D
 :%0A      
@@ -2502,24 +2502,105 @@
 ge.source)%0A%0A
+            print(%22Nodes to delete: %22 + str(node_num) + %22 %22 + str(assoc_nodes))%0A%0A
             
@@ -2758,24 +2758,107 @@
 le):%0A       
+ mms = rule.vs%5B%22mm__%22%5D%0A        print(%22Rule: %22 + rule.name)%0A        print(%5Bv%5B%22mm__%22%5D
  for v in ru
@@ -2862,17 +2862,18 @@
  rule.vs
-:
+%5D)
 %0A       
@@ -2877,24 +2877,487 @@
     
-    print(v%5B%22mm__%22%5D
+print(%5Bstr(edge.source) + %22-%22 + str(edge.target) for edge in rule.es%5D)%0A        print(%5Bstr(mms%5Bedge.source%5D) + %22-%22 + str(mms%5Bedge.target%5D) for edge in rule.es%5D)%0A%0A%0A    def debug_rule(self, rule, stage):%0A%0A        if not self.debug:%0A            return%0A%0A        if stage:%0A            stage_str = %22before%22%0A        else:%0A            stage_str = %22after%22%0A%0A%0A        self.print_rule(rule)%0A        graph_to_dot(rule.name + %22_%22 + str(self.mutate%5B0%5D) + str(self.mutate%5B1%5D) + %22_%22 + stage_str, rule
 )

Add more debugging of mutation.