from ATOM3 import ATOM3

import exporter_ClassDiagram 
import exporter_FileOutputer
import exporter_StateChartDiagram

reload(exporter_ClassDiagram)
reload(exporter_FileOutputer)
reload(exporter_StateChartDiagram)

def export(existingATOM3, model):
    
    classes = []
        
    for classEntity in model.listNodes['CD_Class3']:
        c = exporter_ClassDiagram.ClassDiagram(classEntity, existingATOM3)
        print "Class", c.name, "has been loaded in exporter."
        classes.append(c)
            
    for c in classes:
        exporter = CSharpExporter(c)
        exporter.run()

class CSharpExporter:
        
    def __init__(self, classDiagram):
        
        self.classDiagram = classDiagram
        if classDiagram.stateChart == 0:
            self.stateChart = None
        else:
            self.stateChart = classDiagram.stateChart 
        
    def run(self):
        
        methodList = []
        constructorList = []
        destructorList = []

        self.fOut = exporter_FileOutputer.FileOutputer(self.classDiagram.name + ".cs.txt")
       
        self.fOut.write("using System;")
        self.fOut.write("using System.Collections.Generic;");
        self.fOut.write("using System.Text;");
        
        for code in self.classDiagram.preClassCode:
            self.writeCode(code)

        extend = "";        
        for code in self.classDiagram.extendClassCode:
            extend = code

        self.fOut.indent()        
        self.fOut.write("class " + self.classDiagram.name + extend)
        self.fOut.write("{")
        self.fOut.indent()
        
        for attribute, type, initValue in self.classDiagram.attributes:
            if type == "Float" :
                self.fOut.write("public float " + attribute + " = " + initValue + ";")
            if type == "Integer" :
                self.fOut.write("public int " + attribute + " = " + initValue + ";")
            if type == "Boolean" :
                if initValue == True:
                    self.fOut.write("public bool " + attribute + " = true;")
                else:
                    self.fOut.write("public bool " + attribute + " = false;")
                    
        for name, type in self.classDiagram.objectRef:
            self.fOut.write("public " + type + " " + name + ";")
    
        self.fOut.write()
    
        for parameters, body in self.classDiagram.constructors:
            if (extend==" : VG.Common.Player\n" or extend==" : VG.Common.Player") and parameters=="string _name, int _id":
                self.writeConstructor(self.classDiagram.name, parameters, body,": base(_name, _id)")
            else:
                self.writeConstructor(self.classDiagram.name, parameters, body,"")            
        
        for name, parameters, returnType, body in self.classDiagram.getMethods:
            self.writeGetMethod(name, returnType, body) 
            
        for name, parameters, returnType, body in self.classDiagram.methods:
            self.writeMethod(name, parameters, returnType, body)        
        
        for body in self.classDiagram.destructors:
            self.writeMethod("end", "", "void", body)        
        
        self.fOut.dedent()
        self.fOut.write("}")

        if self.stateChart != None:
           self.processChart(self.classDiagram.name)
    
        self.fOut.write()
        for code in self.classDiagram.postClassCode:
            self.fOut.dedent()
            self.writeCode(code)
        self.fOut.write()
                        
        self.fOut.close()
            
    def writeCode(self, body):
        lineByLine = body.split("\n")
        for line in lineByLine:
            self.fOut.write(line)
    
    def writeConstructor(self, name, parameters, body, extension):
        self.fOut.write("public " + name + "(" + parameters + ") "+extension+" {")
        self.fOut.indent()
        self.writeCode(body)
        if self.stateChart != None:
            self.processChartConstructor()
        self.fOut.dedent()
        self.fOut.write("}")
    
    def writeMethod(self, name, parameters, returnType, body):
        self.fOut.write("public " + returnType + " " + name + "(" + parameters + ") {")
        self.fOut.indent()
        self.writeCode(body)
        self.fOut.dedent()
        self.fOut.write("}\n")  

    def processChartConstructor(self):
        self.fOut.write("fsm = new FSMMachine();");
        for state in self.stateChart.basics:
            if self.stateChart.transitionData[state] != [] :
                self.fOut.write("FSMState "+state.name.getValue()+"_var = new "+state.name.getValue()+"(this);")
                self.fOut.write("fsm.AddState("+state.name.getValue()+"_var);");
                if (self.stateChart.initState == state.name.getValue()):
                    self.fOut.write("fsm.SetDefaultState("+state.name.getValue()+"_var);")
        
    def writeGetMethod(self, name, returnType, body):
        self.fOut.write("public " + returnType + " " + name + " {")
        self.fOut.indent()
        self.writeCode(body)
        self.fOut.dedent()
        self.fOut.write("}\n")  
            
    def processChart(self,classe):        
        for state in self.stateChart.basics:
            # If the state has transition
            if self.stateChart.transitionData[state] != [] :
                self.processState(state,classe);
                
        
    def processState(self, state,classe):
        self.fOut.write("public class "+state.name.getValue()+" : FSMState")
        self.fOut.write("{");
        self.fOut.indent()        
        self.fOut.write("public "+state.name.getValue()+"(object owner) : base(owner) { /* Do nothing */ }");
        self.processTransition(state,classe)
        self.fOut.dedent()
        self.fOut.write("}");
    
    def processTransition(self, state,classe):
        codes = []
        guards = []
        nextState = []
        transitions = self.stateChart.transitionData[state]
        transitionOk = 0
        for transition in transitions:
            if transition["destinationState"] == state.name.getValue():
                self.fOut.write("public override void Update()");
                self.fOut.write("{");  
                self.fOut.indent()        
                for code in transition["triggerCode"]:
                    self.writeCode(code)
                self.fOut.dedent()
                self.fOut.write("}");
                                            
                self.fOut.write("public override void Enter()");
                self.fOut.write("{");
                self.fOut.indent()
                if len(transition["enterCode"])>0:
                    for code in transition["enterCode"]:
                        self.writeCode(code)
                else:
                    self.fOut.write("//Rien à faire ici");
                self.fOut.dedent()
                self.fOut.write("}");

                self.fOut.write("public override void Exit()");
                self.fOut.write("{");
                self.fOut.indent()
                if len(transition["exitCode"])>0:
                    for code in transition["exitCode"]:
                        self.writeCode(code)
                else:
                    self.fOut.write("//Rien à faire ici");
                self.fOut.dedent()
                self.fOut.write("}");  
            else :
                transitionOk = transitionOk + 1
                if len(transition["triggerCode"])>0:
                    codes.append(transition["triggerCode"])
                    guards.append(transition["guard"])
                    nextState.append(transition["destinationState"]);
                    
        if transitionOk > 0 or len(transitions)==1:
            self.fOut.write("public override Type getNextTransition()");
            self.fOut.write("{");
            self.fOut.indent()            
            self.fOut.write(classe+" "+classe+"_var = ("+classe+")owner;");
            if len(codes)>=1:
                i=0
                for code in codes:
                    if guards[i]=="1":
                        guards[i]="true"
                    self.fOut.write("if ("+classe+"_var."+guards[i]+") {");
                    self.fOut.indent() 
                    for code in codes[i]:
                        self.writeCode(code)
                    self.fOut.write("return typeof("+nextState[i]+");");
                    self.fOut.dedent() 
                    self.fOut.write("}");
                    i = i+1
            self.fOut.write("return this.GetType();");
            self.fOut.dedent()
            self.fOut.write("}");