import "logging.eol";
import "common.eol";
import "helper.eol";
import "debug.eol";
import "reusable.eol";
import "execution.eol";

pre { 
	var modelFile = new Native("java.io.File") (TDL.getModelImpl().getURI().toString().replaceAll("^file:",""));

    ("Transforming : " +modelFile.getName()).log(1);
    //TODO:export configuration
      
    //use data mapping
    var useDataMapping = false;
    //??
    var transformAlt = true;
    //generate functions to simulate the SUT 
    var simulateSUT = false;
    //generate testcases
    var createTestcase = true;
    //generate SimpleDataType subtype
    var generateSDT = true;
    //resolve Integer to integer, etc.
    var resolvePredefined = true;
    //generate qualified names
    var qualifiedNaming = false;
    //generate age timers
    var generateAgeTimers = true;

    //add package prefix 
    //(until naming in multi-package / multi-module naming is resolved)
    var packagePrefix = false;


    var predefined = new Set();
    predefined.add("String");
    predefined.add("Integer");
    predefined.add("Boolean");
    predefined.add("Verdict");

    var f = new TTCN!TTCN3File();
    var stack = new Map();
    var currentScope;
}

post {
    //Clean orphaned module defnition lists
    for (m in TTCN!TTCN3Module.allInstances()) {
        if (m.defs.isDefined() and m.defs.definitions.isEmpty()) {
            delete m.defs;
        }
    }
    ("Done!").log(1);
    
}

rule Package2Module 
    transform p : TDL!Package
    to m : TTCN!TTCN3Module {
    //guard : true
    //TODO: to support annotations and test objectives 
    //      need to add contained comments as a feature
    //      in modules
    //TODO: to support annotations and comments for elements 
    //      need to add contained comments as a feature
    //      in module definitions
    ("  Package: "+p.name).log(1);
    m.name = p.TTCNname();
    f.modules.add(m);
    if (p.packagedElement.notEmpty() or p.`import`.notEmpty()) {
        m.defs = new TTCN!ModuleDefinitionsList();
        
        if (generateAgeTimers) {
            //default MP for component lifetime
            var md = new TTCN!ModuleDefinition();
            md.def = new TTCN!ModuleParDef;
            md.def.param = new TTCN!ModulePar;
            md.def.param.type = new TTCN!Type();
            md.def.param.type.`pre` = "float";
            md.def.param.list = new TTCN!ModuleParList;
            
            var mp = new TTCN!ModuleParameter;
            mp.name = "mp_componentElapsedTimerMaxDuration";
            if (packagePrefix) {
            	mp.name = p.name+"_"+mp.name;
            }
            md.def.param.list.params.add(mp);
            
            m.~mpElapsedTime = mp;
            
            m.defs.definitions.add(md);
        }
    }
}

rule ElementImport2ImportDef 
    transform ei : TDL!ElementImport
    to i : TTCN!ImportDef {
    guard : ei.importedPackage.equivalent().isDefined()
    
    ("Import from: "+ei.importedPackage.name).log(1);
    i.name = ei.importedPackage.equivalent().name;
    //i.name = "mappings";
    
    var md = new TTCN!ModuleDefinition();
    md.def = i;
    var m = ei.eContainer.equivalent();
    m.defs.definitions.add(md);
    
    if (ei.importedElement.notEmpty()) {
        i.importSpec = new TTCN!ImportSpec();
        for (ie in ei.importedElement.select(x|x.equivalent().isDefined())) {
            var e = new TTCN!ImportElement();           
            //TODO: make reusable, extend to other types
            if (ie.isKindOf(TDL!DataType) 
              or ie.isKindOf(TDL!GateType)
              or ie.isKindOf(TDL!ComponentType)) {
                e.type = new TTCN!ImportTypeDefSpec();
                e.~kind = e.type;
            } else if (ie.isKindOf(TDL!DataInstance)) {
                //TODO: check if it is a constant instead
                if (ie.isValue()) {
                    e.const = new TTCN!ImportConstSpec();
                    e.~kind = e.const;
                } else {
                    e.template = new TTCN!ImportTemplateSpec();
                    e.~kind = e.template;
                }
            } else if (ie.isKindOf(TDL!Function)) {
                e.`function` = new TTCN!ImportFunctionSpec();
                e.~kind = e.`function`;
            } else {
                //TODO: handle others
                ("  TODO: "+self+" : Imports for " + ie.type.name + " are not supported yet!").log(1);
                delete e;
                continue;
            }

            e.~kind.idOrAll = new TTCN!IdentifierListOrAllWithExcept();
            e.~kind.idOrAll.idList = new TTCN!IdentifierList();
            //TODO: resolve if imported from mappings?
            //TODO: extract equivalent name resolution to an operation
            if (e.const.isDefined()) {
                e.~kind.idOrAll.idList.ids.add(ie.equivalent().defs.list.get(0).name);
            } else if (e.template.isDefined()) {
                e.~kind.idOrAll.idList.ids.add(ie.equivalent().base.name);
            } else {
                e.~kind.idOrAll.idList.ids.add(ie.equivalent().name);
            }
            i.importSpec.element.add(e);
        }
    } else {
        i.all = new TTCN!AllWithExcepts();
    }
}

rule DRM2ImportDef 
    transform drm : TDL!DataResourceMapping
    to i : TTCN!ImportDef {
    guard : useDataMapping
    i.name = drm.resourceURI.replaceAll("\"","");
    //i.name = "mappings";
    
    var md = new TTCN!ModuleDefinition();
    md.def = i;
    var m = drm.eContainer.equivalent();
    m.defs.definitions.add(md);

    i.importSpec = new TTCN!ImportSpec();
}

rule DEM2ImportElement
    transform dem : TDL!DataElementMapping
    to e : TTCN!ImportElement {
    guard : useDataMapping
    
    var i = dem.dataResourceMapping.equivalent();
    i.importSpec.element.add(e);
    
    if (dem.mappableDataElement.isKindOf(TDL!DataType)) {
        e.type = new TTCN!ImportTypeDefSpec();
        e.type.idOrAll = new TTCN!IdentifierListOrAllWithExcept();
        e.type.idOrAll.idList = new TTCN!IdentifierList();
        e.type.idOrAll.idList.ids.add(dem.elementURI.replaceAll("\"",""));
        
    } else {
        if (dem.mappableDataElement.isKindOf(TDL!DataInstance)) {
            e.template = new TTCN!ImportTemplateSpec();
            e.template.idOrAll = new TTCN!IdentifierListOrAllWithExcept();
            e.template.idOrAll.idList = new TTCN!IdentifierList();
            e.template.idOrAll.idList.ids.add(dem.elementURI.replaceAll("\"",""));
        } else {
        	("  TODO: "+self+" : Not implemented yet: "+dem.mappableDataElement.type.name).log(1);
	        //TODO: handle others
        }
    }
}

//Generative, use mappings instead
rule SimpleDT2R 
    transform dt : TDL!SimpleDataType
    to s : TTCN!SubTypeDefNamed {
    guard : not useDataMapping and not (resolvePredefined and predefined.includes(dt.name))
    
    s.name = dt.TTCNname();
    
    s.type = new TTCN!Type();

    //TODO: handle predefined data types
    var m = dt.eContainer.equivalent();
    if (generateSDT) {
        //create default simple data type?
        s.type.ref = new TTCN!TypeReference(); 
        s.type.ref.head = m.getSDT(); 
    } else {
        s.type.`pre` = "charstring";
    }
    
    var t = m.createTypeDefBody();
    t.sub = s;
}

//Generative, use mappings instead
rule EnumDT2E 
    transform dt : TDL!EnumDataType
    to e : TTCN!EnumDefNamed {
    guard : not useDataMapping
    
    e.name = dt.TTCNname();
    
    var module = dt.eContainer.equivalent();
    var t = module.createTypeDefBody();    

    t.structured = new TTCN!StructuredTypeDef();
    t.structured.enumDef = e;
    
    e.list = new TTCN!EnumerationList();
}

rule EnumInstance2E 
    transform di : TDL!SimpleDataInstance
    to e : TTCN!Enumeration {
    guard : not useDataMapping and di.eContainer.isKindOf(TDL!EnumDataType)
    
    e.name = di.TTCNname();
    
    var ep = di.dataType.equivalent();
    ep.list.enums.add(e);
}


//Generative, use mappings instead
rule StructuredDT2R 
    transform dt : TDL!StructuredDataType
    to r : TTCN!RecordDefNamed {
    guard : not useDataMapping
        
    r.name = dt.TTCNname();
    
    var module = dt.eContainer.equivalent();
    var t = module.createTypeDefBody();    

    t.structured = new TTCN!StructuredTypeDef();
    t.structured.record = r;
    
    r.body = new TTCN!StructDefBody();  

    //add inherited members
    //TODO: use for all members? what about equivalent()? -> needs special handling
    //TODO: also unions and other constraints need special handling..
    for (m in dt.allMembers().select(e | e.eContainer() != dt)) {
	    var f = new TTCN!StructFieldDef();
	    f.name = m.TTCNname();
	    if (m.isOptional) {
	        f.optional = "optional";
	    }
	    f.type = m.dataType.getTTCNType();
        r.body.defs.add(f);
    }
    
}

//Generative, use mappings instead
rule CollectionDT2RoR 
    transform dt : TDL!CollectionDataType
    to r : TTCN!RecordOfDefNamed {
    guard : not useDataMapping
        
    r.name = dt.TTCNname();
    
    var module = dt.eContainer.equivalent();
    var t = module.createTypeDefBody();    

    t.structured = new TTCN!StructuredTypeDef();
    t.structured.recordOf = r;
    
    r.type = dt.itemType.getTTCNType();  
}

rule M2SFD 
    transform m : TDL!Member
    to f : TTCN!StructFieldDef {
    guard : not useDataMapping
    
    f.name = m.TTCNname();
    if (m.isOptional) {
        f.optional = "optional";
    }
    f.type = m.dataType.getTTCNType();
    
    var r = m.eContainer.equivalent();
    r.body.defs.add(f);
}

//Generative, use mappings instead
rule Action2FD 
    transform a : TDL!Action
    to fd : TTCN!FunctionDef {
    guard : not useDataMapping
        
	a.transformTo(fd);
}

//Generative, use mappings instead
rule Function2FD 
    transform f : TDL!Function
    to fd : TTCN!FunctionDef {
    guard : not useDataMapping
    
    f.transformTo(fd);
        
    fd.returnType = new TTCN!ReturnType();
    fd.returnType.type = f.returnType.getTTCNType();
    //TODO: add distinction between value and template?
}

/*
//TODO: Breaks generation
rule FP2FFP 
    transform f : TDL!FormalParameter
    to ffp : TTCN!FunctionFormalPar {
	//guard : false

	var fd = f.eContainer.equivalent();
	
	if (fd.parameterList.oclIsUndefined()) {
		fd.parameterList = new TTCN!FunctionFormalParList();
	}
	
	//ffp.name = f.TTCNname();
	
	f.dataType.getTTCNType();

    ffp.template = new TTCN!FormalTemplatePar();
    ffp.~kind = fp.template;
    
    ffp.~kind.name = f.TTCNname();
    
    //TODO: direction support?
    
    ffp.~kind.type = fp.dataType.getTTCNType();
    fd.parameterList.params.add(ffp);
}
*/

rule TC2FD
    transform tc : TDL!TestConfiguration
    to fd : TTCN!FunctionDef {
    
    fd.name = "setupTestConfiguration_"+tc.TTCNname();
    
    var md = new TTCN!ModuleDefinition();
    md.def = fd;

    var m = tc.eContainer.equivalent();
    m.defs.definitions.add(md);

    //CREATE MTC TYPE
    var mtc = m.createTypeDefBody();    
    mtc.structured = new TTCN!StructuredTypeDef();
    mtc.structured.component = new TTCN!ComponentDef();
    mtc.structured.component.name = "MTC_"+tc.TTCNname();

    //CREATE SYSTEM TYPE 
    //TODO: Is this necessary?
    var sut = m.createTypeDefBody();    
    sut.structured = new TTCN!StructuredTypeDef();
    sut.structured.component = new TTCN!ComponentDef();
    sut.structured.component.name = "SYSTEM_"+tc.TTCNname();

    fd.runsOn = new TTCN!RunsOnSpec();
    fd.runsOn.component = mtc.structured.component;
    
    fd.system = new TTCN!SystemSpec();
    fd.system.component = sut.structured.component;
    
    fd.statement = new TTCN!StatementBlock();
    
    var sl = new TTCN!FunctionStatementList();
    fd.statement.stat.add(sl);

    //create components
    for (ci in tc.componentInstance.select(c|simulateSUT or c.role = TDL!ComponentInstanceRole#Tester)) {
        var s = new TTCN!FunctionStatement();
        s.basic = new TTCN!BasicStatements();
        s.basic.assign = new TTCN!Assignment();
        s.basic.assign.ref = new TTCN!VariableRef();
        s.basic.assign.ref.ref = new TTCN!ReferencedValue();
        s.basic.assign.ref.ref.head = new TTCN!Head();
        s.basic.assign.ref.ref.head.target = ci.equivalent();
        
        s.basic.assign.expression = new TTCN!OpCall();
        s.basic.assign.expression.configuration = new TTCN!ConfigurationOps();
        s.basic.assign.expression.configuration.create = new TTCN!CreateOp();
        s.basic.assign.expression.configuration.create.type = ci.type.equivalent();
         
        sl.statements.add(s);
        sl.sc.add(";");
    }
    
    //merge ports of SUT components into sut 
    if (not simulateSUT) {
        for (c in tc.connection) {
            if (c.endPoint.get(0).component.role = TDL!ComponentInstanceRole#SUT and 
                c.endPoint.get(1).component.role = TDL!ComponentInstanceRole#Tester ) {
                c.endPoint.get(0).mergeIntoSUT(sut);               
            }
            if (c.endPoint.get(1).component.role = TDL!ComponentInstanceRole#SUT and 
               c.endPoint.get(0).component.role = TDL!ComponentInstanceRole#Tester ) {
                c.endPoint.get(1).mergeIntoSUT(sut);               
            }
        }
    }
    
    //handle multiple connections to the same gate
    for (c in tc.connection) {
        if (//c.endPoint.get(0).component.role = TDL!ComponentInstanceRole#SUT and 
            c.endPoint.get(1).component.role = TDL!ComponentInstanceRole#Tester ) {
            c.endPoint.get(1).createConnectionPort();               
        }
        if (//c.endPoint.get(1).component.role = TDL!ComponentInstanceRole#SUT and 
           c.endPoint.get(0).component.role = TDL!ComponentInstanceRole#Tester ) {
            c.endPoint.get(0).createConnectionPort();               
        }
    }
    
    
    //create connections
    for (c in tc.connection) { 
        if (simulateSUT or 
              (c.endPoint.get(0).component.role = TDL!ComponentInstanceRole#Tester and 
               c.endPoint.get(1).component.role = TDL!ComponentInstanceRole#Tester )) {
            var s = new TTCN!FunctionStatement();
            s.configuration = new TTCN!ConfigurationStatements();
            s.configuration.connect = new TTCN!ConnectStatement();
            s.configuration.connect.spec = new TTCN!SingleConnectionSpec();
            s.configuration.connect.spec.port1 = c.endPoint.get(0).equivalent();
            s.configuration.connect.spec.port2 = c.endPoint.get(1).equivalent();
            sl.statements.add(s);
            sl.sc.add(";");
        } else if ((c.endPoint.get(0).component.role = TDL!ComponentInstanceRole#SUT and 
                    c.endPoint.get(1).component.role = TDL!ComponentInstanceRole#SUT )) {
            //skip
        } else {
        //FIXED:confusion between different system interfaces if multiple configurations include the same SUT component.. 
//            var p1 = c.endPoint.get(0).equivalent();
//            var p2 = c.endPoint.get(1).equivalent();
//            ("MAP: "+p1.component.getComponentName()+":"+p1.port.name
//               +"->"+p2.component.getComponentName()+":"+p2.port.name).println();
            var s = new TTCN!FunctionStatement();
            s.configuration = new TTCN!ConfigurationStatements();
            s.configuration.map = new TTCN!MapStatement();
            s.configuration.map.spec = new TTCN!SingleConnectionSpec();
            s.configuration.map.spec.port1 = c.endPoint.get(0).equivalent();
            s.configuration.map.spec.port2 = c.endPoint.get(1).equivalent();
            sl.statements.add(s);
            sl.sc.add(";");
        }
    }

}

rule TD2FD 
    transform td : TDL!TestDescription
    to fd : TTCN!FunctionDef {
    
    td.transformTo(fd);
        
    fd.runsOn = new TTCN!RunsOnSpec();
    fd.runsOn.component = ("MTC_"+td.testConfiguration.TTCNname()).getComponent();

    stack.put(fd.name,new OrderedSet());
    stack.get(fd.name).add(fd.statement);

    var sl = new TTCN!FunctionStatementList();
    fd.statement.stat.add(sl);
    
    if (not createTestcase) {
        var s = new TTCN!FunctionStatement();
        s.behavior = new TTCN!BehaviourStatements();
        s.behavior.`function` = new TTCN!FunctionInstance();
        s.behavior.`function`.ref = td.testConfiguration.equivalent();

        sl.statements.add(s);
        sl.sc.add(";");
    }

    for (ci in td.testConfiguration.componentInstance.select(c|simulateSUT or c.role = TDL!ComponentInstanceRole#Tester)) {
        var cf = new TTCN!FunctionDef();
    
    	td.transformTo(cf);
   
        cf.name = td.getMainContext(ci);
    
        cf.runsOn = new TTCN!RunsOnSpec();
        cf.runsOn.component = ci.type.equivalent();
    
        stack.put(cf.name,new OrderedSet());
        stack.get(cf.name).add(cf.statement);
    
        var fs = new TTCN!FunctionStatement();
        fs.configuration = new TTCN!ConfigurationStatements();
        fs.configuration.startTc = new TTCN!StartTCStatement();
        fs.configuration.startTc.ref = new TTCN!ComponentOrDefaultReference();
        fs.configuration.startTc.ref.variable = new TTCN!VariableRef();
        fs.configuration.startTc.ref.variable.ref = new TTCN!ReferencedValue();
        fs.configuration.startTc.ref.variable.ref.head = new TTCN!Head();
        fs.configuration.startTc.ref.variable.ref.head.target = ci.equivalent();

        fs.configuration.startTc.`function` = new TTCN!FunctionInstance();
        fs.configuration.startTc.`function`.ref = cf; 
        
        sl.statements.add(fs);
        sl.sc.add(";");
    }   
    
    if (td.behaviourDescription.isDefined()) {
        td.behaviourDescription.behaviour.~rule = self;
        td.behaviourDescription.behaviour.execute();
    }
    
    stack.clear();
    
    if (createTestcase) {
        var tc = new TTCN!TestcaseDef();
        tc.name = "tc_"+td.TTCNname();
        
        var tmd = new TTCN!ModuleDefinition();
        tmd.def = tc;
    
        var m = td.eContainer.equivalent();
        m.defs.definitions.add(tmd);
        
        tc.spec = new TTCN!ConfigSpec();
        tc.spec.runsOn = new TTCN!RunsOnSpec();
        tc.spec.runsOn.component = ("MTC_"+td.testConfiguration.TTCNname()).getComponent();
        tc.spec.systemSpec = new TTCN!SystemSpec();
        tc.spec.systemSpec.component = ("SYSTEM_"+td.testConfiguration.TTCNname()).getComponent();
    
        tc.statement = new TTCN!StatementBlock();
    
        stack.put(tc.name,new OrderedSet());
        stack.get(tc.name).add(tc.statement);
    
        var tsl = new TTCN!FunctionStatementList();
        tc.statement.stat.add(tsl);
        
        //setup configuration
        var tsc = new TTCN!FunctionStatement();
        tsc.behavior = new TTCN!BehaviourStatements();
        tsc.behavior.`function` = new TTCN!FunctionInstance();
        tsc.behavior.`function`.ref = td.testConfiguration.equivalent();
        
        tsl.statements.add(tsc);
        tsl.sc.add(";");

        //start behaviour
        var tsb = new TTCN!FunctionStatement();
        tsb.behavior = new TTCN!BehaviourStatements();
        tsb.behavior.`function` = new TTCN!FunctionInstance();
        tsb.behavior.`function`.ref = fd;
        
        //TODO: add parameters
        
        
        tsl.statements.add(tsb);
        tsl.sc.add(";");

        //all done
        var tsd = new TTCN!FunctionStatement();
        tsd.configuration = new TTCN!ConfigurationStatements();
        tsd.configuration.done = new TTCN!DoneStatement();
        tsd.configuration.done.component = new TTCN!ComponentOrAny();
        tsd.configuration.done.component.all = "all";

        tsl.statements.add(tsd);
        tsl.sc.add(";");
    }
}

rule GR2PR 
    transform gr : TDL!GateReference
    to pr : TTCN!PortRef {
    guard : simulateSUT or gr.checkGateReference() 
    
    var cr = new TTCN!ComponentRef();
    pr.component = cr;
    
    if (simulateSUT or gr.component.role = TDL!ComponentInstanceRole#Tester ) {
        cr.ref = new TTCN!ComponentOrDefaultReference();
        cr.ref.variable = new TTCN!VariableRef();
        cr.ref.variable.ref = new TTCN!ReferencedValue();
        cr.ref.variable.ref.head = new TTCN!Head();
        cr.ref.variable.ref.head.target = gr.component.equivalent();
        pr.port = gr.gate.equivalent();
    } else {
        cr.system = "system";
        //will be replaced with system port in TC2FD
        pr.port = gr.gate.equivalent();
        //TODO: is there a case for cr.mtc?
    }
        
}


rule CT2C 
    transform ct : TDL!ComponentType
    to c : TTCN!ComponentDef {

    c.name = ct.TTCNname();

    var m = ct.eContainer.equivalent();
    var t = m.createTypeDefBody();
    
    if (ct.extension.isDefined()) {
        c.`extends`.add(ct.extension.extending.equivalent());
        //(ct+"->"+ct.extension.extending.equivalent()).println();
    }

    t.structured = new TTCN!StructuredTypeDef();
    t.structured.component = c;

    if (generateAgeTimers) {
        var ti = new TTCN!SingleVarInstance();
        ti.name = "T_elapsedTimeOfComponent";  
        ti.ac = ":="; //TODO: Why is this needed?
        ti.expr = new TTCN!Value();
        ti.expr.ref = new TTCN!ReferencedValue();
        ti.expr.ref.head = new TTCN!Head;
        ti.expr.ref.head.target = c.getElapsedTime();
        
        var d = new TTCN!ComponentDefList();
        c.defs.add(d);
    
        d.sc = ";";
        d.element = new TTCN!ComponentElementDef();
        
        d.element.timer = new TTCN!TimerInstance();
        d.element.timer.list = new TTCN!VarList();
        d.element.timer.list.variables.add(ti);
    }
    
}


rule CI2V 
    transform ci : TDL!ComponentInstance
    to v : TTCN!SingleVarInstance {
    guard : simulateSUT or ci.role = TDL!ComponentInstanceRole#Tester

    v.name = ci.TTCNname(); 
    
    var d = new TTCN!ComponentDefList();
    d.sc = ";";
    d.element = new TTCN!ComponentElementDef();
    d.element.variable = new TTCN!VarInstance();
    d.element.variable.listType = new TTCN!Type(); 
    d.element.variable.listType.ref = new TTCN!TypeReference();
    d.element.variable.listType.ref.head = ci.type.equivalent();
    d.element.variable.list = new TTCN!VarList();
    
    d.element.variable.list.variables.add(v);

    var mtc = ("MTC_"+ci.eContainer().TTCNname()).getComponent();
    mtc.defs.add(d);
}


rule GT2P 
    transform gt : TDL!GateType
    to p : TTCN!PortDef {
    //guard : true
    p.name = gt.TTCNname();

    var m = gt.eContainer.equivalent();
    var t = m.createTypeDefBody();    

    t.structured = new TTCN!StructuredTypeDef();
    t.structured.port = p;

    p.body = new TTCN!PortDefBody();
    p.body.attribs = new TTCN!PortDefAttribs();
    
    if (gt.kind.name = "Message") {
        p.body.attribs.message = new TTCN!MessageAttribs();
        //FIX
        var ml = new TTCN!MessageList();
        ml.direction = "inout";
        ml.allOrTypeList = new TTCN!AllOrTypeList();
        ml.allOrTypeList.typeList = new TTCN!TypeList();
        p.body.attribs.message.messages.add(ml);
        
        //ADAPT
        for (dt in gt.dataType) {
            var t = dt.getTTCNType();
            ml.allOrTypeList.typeList.types.add(t);
        }
    } else {
        //TODO: handle procedure based gates..
    }
    
}

rule GI2PE
    transform gi : TDL!GateInstance
    to pe : TTCN!PortElement {

    pe.name = gi.TTCNname();

    var c = gi.eContainer.equivalent();
    var d = new TTCN!ComponentDefList();
    c.defs.add(d);

    d.sc = ";";
    d.element = new TTCN!ComponentElementDef();
    d.element.port = new TTCN!PortInstance();

    d.element.port.ref = gi.type.equivalent();
    d.element.port.instances.add(pe);
}       

rule T2TI 
    transform t : TDL!Timer
    to ti : TTCN!SingleVarInstance {
    
    ti.name = t.TTCNname();

    var c = t.eContainer.equivalent();
    var d = new TTCN!ComponentDefList();
    c.defs.add(d);

    d.sc = ";";
    d.element = new TTCN!ComponentElementDef();
    
    d.element.timer = new TTCN!TimerInstance();
    d.element.timer.list = new TTCN!VarList();
    d.element.timer.list.variables.add(ti);
}

rule V2VI 
    transform v : TDL!Variable
    to vi : TTCN!SingleVarInstance {

    vi.name = v.TTCNname();

    var c = v.eContainer.equivalent();
    var d = new TTCN!ComponentDefList();
    c.defs.add(d);

    d.sc = ";";
    d.element = new TTCN!ComponentElementDef();
    
    d.element.variable = new TTCN!VarInstance();
    d.element.variable.listType = v.dataType.getTTCNType();
    d.element.variable.list = new TTCN!VarList();
    d.element.variable.list.variables.add(vi);
}


rule SimpleDI2TD
    transform di : TDL!SimpleDataInstance
    to td : TTCN!TemplateDef {
    //guard : false
    guard : not useDataMapping 
    	and not di.isValue() 
    	and di.dataType.name <> "Verdict"
    	and di.dataType.name <> "Boolean"
    	and not di.eContainer.isKindOf(TDL!EnumDataType)

    var md = new TTCN!ModuleDefinition();
    md.def = td;
    var m = di.eContainer.equivalent();
    m.defs.definitions.add(md);
    
    td.base = new TTCN!BaseTemplate();
    td.base.name = di.TTCNname();
    td.base.type = di.dataType.getTTCNType();

    td.body = di.name.getStringBody();
}

rule SimpleDI2C
    transform di : TDL!SimpleDataInstance
    to cd : TTCN!ConstDef {
    //guard : false
    guard : not useDataMapping and di.isValue()

    var md = new TTCN!ModuleDefinition();
    md.def = cd;
    var m = di.eContainer.equivalent();
    m.defs.definitions.add(md);

    cd.type = di.dataType.getTTCNType();
    
    cd.defs = new TTCN!ConstList();

    var scd = new TTCN!SingleConstDef;
    scd.name = di.TTCNname();
    scd.expr = new TTCN!Value();
    scd.expr.predef = new TTCN!PredefinedValue();
    scd.expr.predef.charString = "\""+di.name+"\"";

    scd.assign = ":="; //TODO: this shall not be necessary

    cd.defs.list.add(scd);
}

rule StructuredDI2TD
    transform di : TDL!StructuredDataInstance
    to td : TTCN!TemplateDef {
    //guard : false
    guard : not useDataMapping and not di.isValue()

	di.~rule = self;

	(di.name).log(1);

    var md = new TTCN!ModuleDefinition();
    md.def = td;
    var m = di.eContainer.equivalent();
    m.defs.definitions.add(md);
    
    td.base = new TTCN!BaseTemplate();
    td.base.name = di.TTCNname();
    td.base.type = di.dataType.getTTCNType();
    //TODO:unassigned fields
    //check if there is unassigned member handling
    //handle accordingly -> separate branch under .field
    var tb = new TTCN!TemplateBody();
    td.body = tb;

    if ((di.unassignedMember.isDefined()
           and not (di.unassignedMember = TDL!UnassignedMemberTreatment#undefined)
           and not di.dataType.allMembers().forAll(m|
                di.memberAssignment.exists(ma|ma.member = m)))
         //does it need to be recursive?
         or di.memberAssignment.exists(ma|
                ma.memberSpec.isKindOf(TDL!AnyValue) 
             or ma.memberSpec.isKindOf(TDL!AnyValueOrOmit))
      ) {
        //NOTE: implementation treats unset unassigned member (and other enums) as if 
        //  they have been set to the first value by default.
        //TODO: add none / omit as default option? 
//        ("Wildcard: "+di.name).log(1);
//        ("  "+di.unassignedMember+
//         "  "+di.unassignedMember.isDefined()+
//         "  "+(not di.dataType.member.forAll(m|di.memberAssignment.exists(ma|ma.member = m)))+
//         "  "+di.memberAssignment.exists(ma|ma.memberSpec.isKindOf(TDL!AnyValue) 
//              or ma.memberSpec.isKindOf(TDL!AnyValueOrOmit))).log(1);
        tb.field = di.transformWildcardMemberAssignment();
    } else {
        ("Structure -> Simple: "+di.name).log(1);
        tb.simple = new TTCN!SimpleSpec();
        tb.simple.expr = di.transformMemberAssignment();
    }
    
}

rule StructuredDI2C
    transform di : TDL!StructuredDataInstance
    to cd : TTCN!ConstDef {
    //guard : false
    guard : not useDataMapping and di.isValue()

	di.~rule = self;

    var md = new TTCN!ModuleDefinition();
    md.def = cd;
    var m = di.eContainer.equivalent();
    m.defs.definitions.add(md);

    cd.type = di.dataType.getTTCNType();
    
    cd.defs = new TTCN!ConstList();

    var scd = new TTCN!SingleConstDef;
    scd.name = di.TTCNname();
    
    scd.expr = di.transformMemberAssignment();

    scd.assign = ":="; //TODO: this shall not be necessary

    cd.defs.list.add(scd);
}

rule CollectionDI2TD
    //TODO: the specification in the standard is insufficient
    transform di : TDL!CollectionDataInstance
    to td : TTCN!TemplateDef {
    //guard : false
    guard : not useDataMapping and not di.isValue()

    var md = new TTCN!ModuleDefinition();
    md.def = td;
    var m = di.eContainer.equivalent();
    m.defs.definitions.add(md);
    
    td.base = new TTCN!BaseTemplate();
    td.base.name = di.TTCNname();
    td.base.type = di.dataType.getTTCNType();
    //TODO:unassigned fields
    //check if there is unassigned member handling
    //handle accordingly -> separate branch under .field
    var tb = new TTCN!TemplateBody();
    td.body = tb;
    
    tb.simple = new TTCN!SimpleSpec();
    tb.simple.expr = new TTCN!ArrayExpression();
    
    tb.simple.expr.list = new TTCN!ArrayElementExpressionList();
    
    for (i in di.item) {
        if (i.isKindOf(TDL!DataInstanceUse) and i.dataInstance.isDefined()) {
            var v = new TTCN!Value();
            v.ref = new TTCN!ReferencedValue();
            v.ref.head = new TTCN!Head();
            
            var e = i.dataInstance.equivalent();
            if (e.isKindOf(TTCN!TemplateDef)) {
                v.ref.head.target = e.base;
            } else if (e.isKindOf(TTCN!ConstDef)) {
                v.ref.head.target = e.defs.list.get(0);             
            } else {
                //what else can it be?
            }
            tb.simple.expr.list.expr.add(v);
        } else {
			//TODO: inline definition
			("  TODO: "+self+" : Not Implemented Yet : "+di.item.type.name).log(1);
			var v = new TTCN!Value();
      		v.predef = new TTCN!PredefinedValue();
        	v.predef.charString = "\"TODO_NOT_SUPPORTED_YET\"";
			tb.simple.expr.list.expr.add(v);
        }
    }
}

rule CollectionDI2C
    //TODO: the specification in the standard is insufficient
    transform di : TDL!CollectionDataInstance
    to cd : TTCN!ConstDef {
    //guard : false
    guard : not useDataMapping and di.isValue()

	di.~rule = self;

    var md = new TTCN!ModuleDefinition();
    md.def = cd;
    var m = di.eContainer.equivalent();
    m.defs.definitions.add(md);
    
    cd.type = di.dataType.getTTCNType();
    
    cd.defs = new TTCN!ConstList();

    var scd = new TTCN!SingleConstDef;
    scd.name = di.TTCNname();
    
    scd.expr = new TTCN!ArrayExpression();
    scd.expr.list = new TTCN!ArrayElementExpressionList();

    for (i in di.item) {
        if (i.isKindOf(TDL!DataInstanceUse) and i.dataInstance.isDefined()) {
            var v = new TTCN!Value();
            v.ref = new TTCN!ReferencedValue();
            v.ref.head = new TTCN!Head();
            
            var e = i.dataInstance.equivalent();
            if (e.isKindOf(TTCN!TemplateDef)) {
                v.ref.head.target = e.base; //TODO: is that even possible here?
            } else if (e.isKindOf(TTCN!ConstDef)) {
                v.ref.head.target = e.defs.list.get(0);             
            } else {
                //what else can it be?
            }
            scd.expr.list.expr.add(v);
        }
    }

    scd.assign = ":="; //TODO: this shall not be necessary

    cd.defs.list.add(scd);
    
}
