//
// see http://www.sparxsystems.com/enterprise_architect_user_guide/12.0/automation_and_scripting/reference.html
//
// $Id$
// $HeadURL$
// $Author$
//
// -> tabs to spaces
// sed -i "s/\t/    /g" ea_export_script.txt
// -> remove trailing spaces
// sed -i "s/[ ]*$//g" ea_export_script.txt
//

!INC Local Scripts.EAConstants-JScript
!INC EAScriptLib.JScript-Database
!INC EAScriptLib.JScript-XML
!INC EAScriptLib.JScript-TaggedValue

function warnOut( msg )
{
    Session.Output( "WARN: " + msg );
}

function infoOut( msg )
{
    Session.Output( "INFO: " + msg );
}

function TVGetElementTaggedValueEx( theElement /* : EA.Element */, taggedValueName /* : String */, defaultValue /* : String */ ) /* : variant */
{
    var result = defaultValue;

    if ( theElement != null && taggedValueName.length > 0 )
    {
        for ( var j = 0; j < theElement.TaggedValuesEx.Count; j++ )
        {
            var taggedValue as EA.TaggedValue;
            taggedValue = theElement.TaggedValuesEx.GetAt(j);
            if (taggedValue.Name == taggedValueName)
            {
                result = taggedValue.Value;
                break;
            }
        }
    }

    return result;
}


function getFrameworkPackage( element_ )
{
    if ( element_ == null )
        return null;
    var element as EA.Element;
    element = element_;
    if ( element.Stereotype == "framework" )
        return element;

    var elementId = element.PackageID;
    if ( element.ObjectType == otPackage )
    {
        var package as EA.Package;
        package = element;
        var packageElement as EA.Element;
        packageElement = package.Element;
        if ( packageElement == null )
            return null;
        if ( packageElement.Stereotype == "framework" )
            return package;
        elementId = element.ParentID;
    }
    //Session.Output( "Name: " + element.Name + " PackageID: " + elementId );
    element = Repository.GetPackageByID( elementId );

    return getFrameworkPackage( element )
}

function getFrameworkElement( element_ )
{
    var element as EA.Element;
    element = element_;
    if ( element.Stereotype == "framework" )
        return element;
    var package as EA.Package;
    package = getFrameworkPackage( element_ );
    if ( package == null )
        return null;
    return package.Element;
}

function getConnectorFromElement( _element, connectorType )
{
    var element as EA.Element;
    element = _element;

    if ( element == null )
        return null;

    for( var j = 0; j < element.Connectors.Count; j++ )
    {
        var connector as EA.Connector;
        connector = element.Connectors.GetAt( j );
        if( connector == null )
            continue;
        if( connector.ClientID != element.ElementID )
            continue;
        if( connector.Type != connectorType )
            continue;
        return connector;
    }
    return null;
}


function getMethodFromElement( _element, methodString )
{
    var element as EA.Element;
    element = _element;

    if( element == null || methodString == null )
        return null;

    var methods as EA.Collection;
    methods = element.MethodsEx;

    return getCollectionAttribute(methods, methodString);
}

function getCollectionAttribute(_collections, methodName)
{
    var collections as EA.Collection;

    //Session.Output( "Find methodName:" + methodName );
    collections = _collections;
    // method.GetByName() does not work on non-existing attributes
    for( var i = 0; i < collections.Count; ++i )
    {
        var method as EA.Method;
        method = collections.GetAt( i );
        //Session.Output( "MethodName: " + method.Name );
        if( method && method.Name == methodName )
            return method;
    }
    return null;
}

function getKeyColumnFromMethod( element, methodString )
{
    var method as EA.Method;
    method = getMethodFromElement( element, methodString );
    if( method == null )
    {
        Session.Output( "Can not find PK/FK '" + methodString + "' in Table " + element.Name );
        return null;
    }
    if( method.Parameters.Count != 1 )
        return null;

    return method.Parameters.GetAt(0).Name;
}

function getTaggedValueGroup( element, groupName )
{
    var groupsTaggedValue = TVGetElementTaggedValue( element, groupName );
    if ( groupsTaggedValue != null )
    {
        tmp1 = DBGetFieldValueString( "Notes", "t_propertytypes", "Property = \'" + groupName + "\' " );

        var startIndex = tmp1.lastIndexOf( "=" ) + 1;
        var endIndex = tmp1.length - 1;

        var groupNames = tmp1.substring(startIndex, endIndex).split( "," );

        var groupVals = groupsTaggedValue.split( "," );
        var validGroups = "";
        for ( var i = 0; i < groupVals.length; i++ )
        {
            if ( groupVals[i] == 1 )
            {
                if ( validGroups.length > 0 )
                {
                    validGroups += ",";
                }
                validGroups += groupNames[i];
            }
        }
        if ( validGroups.length > 0 )
        {
            return validGroups;
        }
    }
    return null;
}

function exportTaggedValueGroup( xml, xmlAttribName, element, groupName )
{
    var validGroups = getTaggedValueGroup( element, groupName );
    if ( validGroups != null )
    {
        //Session.Output('valid groups: ' + validGroups );
        xml.setAttribute( xmlAttribName, validGroups );
    }
}

function exportFunctionDeclaration( xmlDoc, xmlParent, _method )
{
    var method as EA.Method;
    method = _method;

    var methodXml = xmlDoc.createNode( 1, method.Stereotype, '' );
    xmlParent.appendChild( methodXml );
    methodXml.setAttribute( 'name', method.Name );
    methodXml.setAttribute( 'returns', method.ReturnType );
    if (method.IsConst)
        methodXml.setAttribute( 'isConst', 1 );
    for( var k = 0; k < method.Parameters.Count; k++ )
    {
        var param as EA.Parameter;
        param = method.Parameters.GetAt( k );
        var paramXml = xmlDoc.createNode( 1, 'parameter', '' );
        paramXml.setAttribute( 'pos', k + 1 );
        paramXml.setAttribute( 'name', param.Name );
        paramXml.setAttribute( 'type', param.Type );
        if (param.Default != "")
            paramXml.setAttribute(  'default', param.Default );
        methodXml.appendChild( paramXml );
    }
    return methodXml;
}

function exportDbStructBase( xmlDoc, dbStructsXml, dbStructXml, connector, exportedTopicTypes )
{
    // only inheritance
    if( connector.Type != "Generalization" )
        return;

    var base as EA.Element;
    base = GetElementByID( connector.SupplierID );
    if( base == null )
    {
        Session.Output( "got unknown element id " + connector.SupplierID );
        return;
    }

    // now generate the base='foo' - part for inheritance
    dbStructXml.setAttribute( 'base', base.Name );

    // check if the base struct is already exported
    for( var i = 0; i < exportedTopicTypes.length; ++i )
    {
        if( exportedTopicTypes[i] == connector.SupplierID )
            return;
    }
    exportedTopicTypes.push( connector.SupplierID );

    // not yet exported -> export
    var dbStructXml = xmlDoc.createNode( 1, 'table', '' );
    dbStructsXml.appendChild( dbStructXml );
    dbStructXml.setAttribute( 'name', base.Name );

    var baseConnectors as EA.Collection;
    baseConnectors = base.Connectors;
    for( var j = 0; j < baseConnectors.Count; j++ )
    {
        var connector as EA.Connector;
        baseConnector = baseConnectors.GetAt( j );
        if( baseConnector == null )
            continue;
        if( baseConnector.ClientID != base.ElementID )
            continue;

        // check if base of base is already exported
        exportDbStructBase( xmlDoc, dbStructsXml, dbStructXml, baseConnector, exportedTopicTypes );
    }
}

function exportDDSBase( xmlDoc, topicTypesXml, topicTypeXml, connector, exportedTopicTypes )
{
    // only inheritance
    if( connector == null || connector.Type != "Generalization" )
        return;

    var supplier as EA.Element;
    supplier = GetElementByID( connector.SupplierID );
    if( supplier == null )
    {
        Session.Output( "got unknown element id " + connector.SupplierID );
        return;
    }

    var supplierPackage as EA.Package;
    var clientPackage as EA.Package;
    supplierPackage = getFrameworkElement( supplier );
    clientPackage = getFrameworkElement( GetElementByID( connector.ClientID ) );

    // now generate the base='foo' - part for inheritance
    if ( supplierPackage.Name != clientPackage.Name )
    {
        topicTypeXml.setAttribute( 'baseValueType', supplierPackage.Name + "::" + supplier.Name );
    } else {
        topicTypeXml.setAttribute( 'baseValueType', supplier.Name );
    }

    if ( supplier.Attributes.Count == 0 )
    {
        // special case - an empty idl struct - modelled for consistency,
        // but rtiddsgen does not like it and it's also useless in codebase
        var grandparentConnector = getConnectorFromElement( supplier, "Generalization" )
        exportDDSBase( xmlDoc, topicTypesXml, topicTypeXml, grandparentConnector, exportedTopicTypes )
    }
    exportedTopicTypes.push( connector.SupplierID );
}



function getDBServiceStructs( _package, xmlDoc, xmlRootNode )
{
    var dbServiceStructsXml = xmlDoc.createNode( 1, 'dbServiceStructs', '' );
    xmlRootNode.appendChild( dbServiceStructsXml );

    var package as EA.Package;
    package = _package;
    var elements as EA.Collection;
    elements = package.Elements;

    var dbstructs = []

    if( elements.Count == 0 ) {
        infoOut("'Database Service Structs' is empty.");
    }
    for( var i = 0; i < elements.Count; i++ )
    {
        var element as EA.Element;
        element = elements.GetAt( i );
        if( element.Stereotype == "implementationClass" )
        {
            var dbClassXml = xmlDoc.createNode( 1, 'serviceStruct', '' );
            dbServiceStructsXml.appendChild( dbClassXml );
            dbClassXml.setAttribute( 'name', element.Name );
            var connectors as EA.Collection;
            connectors = element.Connectors;

            var correspondingTableFound = false;
            for( var j = 0; j < connectors.Count; j++ )
            {
                var connector as EA.Connector;
                connector = connectors.GetAt( j );
                if( connector == null )
                    continue;

                if( connector.Type != "Dependency" && connector.Type != "InformationFlow" )
                    continue;

                var sourceId = (( connector.Type == "Dependency") ? connector.ClientID : connector.SupplierID );
                var destId =   (( connector.Type == "Dependency") ? connector.SupplierID : connector.ClientID );

                if( sourceId != element.ElementID )
                    continue;

                var supplier as EA.Element;
                supplier = GetElementByID( destId );
                if( supplier == null )
                {
                    Session.Output( "got unknown element id " + destId );
                    continue;
                }

                dbClassXml.setAttribute( 'table', supplier.Name );
                correspondingTableFound = true;

                dbstructs.push( destId );

                if( connector.Type == "InformationFlow" )
                {
                    dbClassXml.setAttribute( 'static', 1 );
                }
            }
            if ( !correspondingTableFound )
            {
                warnOut( "Found no corresponding table for Database Service Struct '" + element.Name + "'" );
            }
            var methods as EA.Collection;
            methods = element.MethodsEx;
            for( var j = 0; j < methods.Count; j++ )
            {
                var method as EA.Method;
                method = methods.GetAt( j );
                if( method == null )
                    continue;
                if( method.Stereotype == 'function' || method.Stereotype == 'notification' )
                {
                    var methodXml = exportFunctionDeclaration( xmlDoc, dbClassXml, method );
                    if( method.Stereotype == 'notification' )
                    {
                        exportTaggedValueGroup( methodXml, 'notificationTypes', method, 'Legatus::DatabaseNotificationType' );
                    }
                }
            }
        }
    }

    var exportedTopicTypes = [];
    for( var i = 0; i < dbstructs.length; i++ )
    {
        var element as EA.Element;
        element = GetElementByID( dbstructs[i] );

        if( element == null )
            continue;

        var dbStructXml = xmlDoc.createNode( 1, 'table', '' );
        dbServiceStructsXml.appendChild( dbStructXml );
        dbStructXml.setAttribute( 'name', element.Name );

        exportedTopicTypes.push( element.ElementID );

        var connectors as EA.Collection;
        connectors = element.Connectors;

        for( var j = 0; j < connectors.Count; j++ )
        {
            var connector as EA.Connector;
            connector = connectors.GetAt( j );
            if( connector == null )
                continue;
            if( connector.ClientID != element.ElementID )
                continue;

            exportDbStructBase( xmlDoc, dbServiceStructsXml, dbStructXml, connector, exportedTopicTypes );
        }
    }
}

function exportReferentialIntegrity( _methods, srcFk, xmlOut)
{
    var methods as EA.Collection;
    methods = _methods;

    var method as EA.Method;
    method = null;
    for (m = 0; m < methods.Count(); ++m)
    {
        method = methods.GetAt(m);
        if (method.Name == srcFk)
            break;
        method = null;
    }
    if (method == null)
        return;

    for (var t = 0; t < method.TaggedValues.Count(); ++t)
    {
        var methodTag as EA.MethodTag;
        methodTag = method.TaggedValues.GetAt(t);
        if (methodTag.Name != 'property')
            continue;
        if (methodTag.Value == 'Delete Set Null=1;')
            xmlOut.setAttribute( 'referential_integrity', 'DeleteSetNull')
        else if (methodTag.Value == 'Delete Restrict=1;')
            xmlOut.setAttribute( 'referential_integrity', 'DeleteRestrict')
        else if (methodTag.Value == 'Delete Cascade=1;')
            xmlOut.setAttribute( 'referential_integrity', 'DeleteCascade')
        else if (methodTag.Value == 'Delete No Action=1;')
            xmlOut.setAttribute( 'referential_integrity', 'DeleteNoAction')
        else if (methodTag.Value == 'Delete Set Default=1;')
            xmlOut.setAttribute( 'referential_integrity', 'DeleteSetDefault')
        break;
    }

}
function getDBModel(  _package, xmlDoc, xmlRootNode )
{
    var tablesXml = xmlDoc.createNode( 1, 'tables', '' );
    xmlRootNode.appendChild( tablesXml );

    var package as EA.Package;
    package = _package;
    var elements as EA.Collection;
    elements = package.Elements;

    if( elements.Count == 0 ) {
        infoOut("'Database Model' is empty.");
    }

    for( var i = 0; i < elements.Count; i++ )
    {
        var element as EA.Element;
        element = elements.GetAt( i );
        if( element.Stereotype == "table" )
        {
            var tableXml = xmlDoc.createNode( 1, 'table', '' );
            tablesXml.appendChild( tableXml );
            tableXml.setAttribute( 'name', element.Name );
            if( element.Notes != "" )
            {
                tableXml.setAttribute( 'comment', element.Notes );
            }
            exportTaggedValueGroup( tableXml, 'exerciseDependency', element, 'Legatus::ExerciseDependency' );

            var attributes as EA.Collection;
            attributes = element.Attributes;
            for( var j = 0; j < attributes.Count; j++ )
            {
                var attribute as EA.Attribute;
                attribute = attributes.GetAt( j );
                if( attribute == null )
                    continue;

                var columnXml = xmlDoc.createNode( 1, 'column', '' );
                tableXml.appendChild( columnXml );

                columnXml.setAttribute( 'name', attribute.Name );
                columnXml.setAttribute( 'datatype', attribute.Type );

                if( attribute.Default != "" )
                    if (attribute.Default == "Optional" | attribute.Default == "optional")
                      columnXml.setAttribute( 'isOptional', 1 );
                    else
                      columnXml.setAttribute( 'default', attribute.Default );
                if( attribute.IsOrdered )
                    columnXml.setAttribute( 'isPrimaryKey', 1 );
                if( attribute.IsCollection )
                    columnXml.setAttribute( 'isForeignKey', 1 );

                var attrTag as EA.AttributeTag;
                attrTag = attribute.TaggedValues.GetByName( "AutoNum" );
                if( attrTag != null && attrTag.Value == "True" )
                {
                    var sequenceXml = xmlDoc.createNode( 1, 'sequence', '' );
                    columnXml.appendChild( sequenceXml );

                    attrTag = attribute.TaggedValues.GetByName( "StartNum" );
                    sequenceXml.setAttribute( 'start', (( attrTag == null ) ? "1" : attrTag.Value ) );

                    attrTag = attribute.TaggedValues.GetByName( "Increment" );
                    sequenceXml.setAttribute( 'increment', (( attrTag == null ) ? "1" : attrTag.Value ) );
                }
                if ( attrTag == null && attribute.IsOrdered )
                {
                    warnOut( 'Column ' + element.Name + '.' + attribute.Name + ' is a primary key, but has no sequence (AutoNum) value set!')
                }

                if( attribute.Notes != "" )
                {
                    columnXml.setAttribute( 'comment', attribute.Notes );
                }
            }

            var methods as EA.Collection;
            methods = element.MethodsEx;
            for( var j = 0; j < methods.Count; j++ )
            {
                var method as EA.Method;
                method = methods.GetAt( j );
                if( method == null )
                    continue;
                if( method.Stereotype == 'index' || method.Stereotype == 'unique' )
                {
                    var methodXml = xmlDoc.createNode( 1, 'constraint', '' );
                    tableXml.appendChild( methodXml );
                    methodXml.setAttribute( 'name', method.Name );
                    methodXml.setAttribute( 'type', method.Stereotype );
                    for( var k = 0; k < method.Parameters.Count; k++ )
                    {
                        var param as EA.Parameter;
                        param = method.Parameters.GetAt( k );
                        var paramXml = xmlDoc.createNode( 1, 'column', '' );
                        paramXml.setAttribute( 'name', param.Name );
                        methodXml.appendChild( paramXml );
                    }
                }
            }

            var connectors as EA.Collection;
            connectors = element.Connectors;
            for( var j = 0; j < connectors.Count; j++ )
            {
                var connector as EA.Connector;
                connector = connectors.GetAt( j );
                if( connector == null )
                    continue;
                if( connector.ClientID != element.ElementID )
                    continue;
                if( connector.Direction != "Source -> Destination" )
                    continue;
                if( connector.Type != "Association" )
                    continue;

                var supplier as EA.Element;
                supplier = GetElementByID( connector.SupplierID );
                if( supplier == null )
                {
                    Session.Output( "got unknown element id " + connector.SupplierID );
                    continue;
                }

                // FKINFO=SRC=FK_pdm_equipment_system_event_filter_pdm_hgr_mine_search_filter_type:DST=PK_pdm_hgr_mine_search_filter_type:;    
                s = connector.StyleEx;
                srcFk = s.split( "SRC=" )[1].split(":")[0];
                dstFk = s.split( "DST=" )[1].split(":")[0];
                // Session.Output("srcFk: " + srcFk);
                // Session.Output("dstFk: " + dstFk);
                
                var foreignKeyXml = xmlDoc.createNode( 1, 'foreignKey', '' );
                tableXml.appendChild( foreignKeyXml );
                foreignKeyXml.setAttribute( 'name', srcFk )

                // Default: onDeleteCascade = true
                exportReferentialIntegrity(methods, srcFk, foreignKeyXml);

                var sourceInfo = xmlDoc.createNode( 1, 'source', '' )
                //Session.Output( "Source: " + sourceInfo );
                foreignKeyXml.appendChild( sourceInfo );
                sourceInfo.setAttribute( 'table', element.Name )
                //Session.Output( "table: " + element.Name );
                sourceInfo.setAttribute( 'column', getKeyColumnFromMethod(element, srcFk) )

                var destInfo = xmlDoc.createNode( 1, 'destination', '' )
                foreignKeyXml.appendChild( destInfo );
                exportExternalFk(xmlDoc, destInfo, element, supplier);
                destInfo.setAttribute( 'table', supplier.Name )
                destInfo.setAttribute( 'column',   getKeyColumnFromMethod(supplier, dstFk) )
                //Session.Output( "Destination: " + destInfo );
                //Session.Output( "table: " + supplier.Name );

            }
        }
    }
}

function getDBViews(  _package, xmlDoc, xmlRootNode )
{
        var viewsXml = xmlDoc.createNode( 1, 'views', '' );
    xmlRootNode.appendChild( viewsXml );

    var package as EA.Package;
    package = _package;
    var elements as EA.Collection;
    elements = package.Elements;

    for( var i = 0; i < elements.Count; i++ )
    {
        var element as EA.Element;
        element = elements.GetAt( i );
        if( element.Stereotype == "view" )
        {
            var viewXml = xmlDoc.createNode( 1, 'view', '' );
            viewsXml.appendChild( viewXml );
            viewXml.setAttribute( 'name', element.Name );
            if( element.Notes != "" )
            {
                viewXml.setAttribute( 'comment', element.Notes );
            }
            exportTaggedValueGroup( viewXml, 'exerciseDependency', element, 'Legatus::ExerciseDependency' );

            var attributes as EA.Collection;
            attributes = element.Attributes;
            for( var j = 0; j < attributes.Count; j++ )
            {
                var attribute as EA.Attribute;
                attribute = attributes.GetAt( j );
                if( attribute == null )
                    continue;
                                if( attribute.Stereotype != "filter")
                                        continue;
                                viewXml.setAttribute( "filter", attribute.Name )
            }

            var connectors as EA.Collection;
            connectors = element.Connectors;
            for( var j = 0; j < connectors.Count; j++ )
            {
                var connector as EA.Connector;
                connector = connectors.GetAt( j );
                if( connector == null )
                    continue;
                if( connector.ClientID != element.ElementID )
                    continue;
                if( connector.Direction != "Source -> Destination" )
                    continue;
                if( connector.Type != "Dependency" )
                    continue;

                var supplier as EA.Element;
                supplier = GetElementByID( connector.SupplierID );
                if( supplier == null )
                {
                    Session.Output( "got unknown element id " + connector.SupplierID );
                    continue;
                }
                viewXml.setAttribute( "base", supplier.Name )
            }
        }
    }
}

function getEnumerations( _package, xmlDoc, xmlRootNode )
{
    var rootXml = xmlDoc.createNode( 1, 'enumerations', '' );
    xmlRootNode.appendChild( rootXml );

    var package as EA.Package;
    package = _package;
    var elements as EA.Collection;
    elements = package.Elements;

    if( elements.Count == 0 ) {
        warnOut("'Enumerations' is empty. At least one placeholder enum is needed for generating C++ code.");
    }

    for( var i = 0; i < elements.Count; i++ )
    {
        var element as EA.Element;
        element = elements.GetAt( i );
        //Session.Output("Enum element: " + element.Name);
        if( element.Stereotype == "enumeration" )
        {
            var elementXml = xmlDoc.createNode( 1, 'enumeration', '' );
            rootXml.appendChild( elementXml );
            elementXml.setAttribute( 'name', element.Name );

            var attributes as EA.Collection;
            attributes = element.AttributesEx;
            for( var j = 0; j < attributes.Count; j++ )
            {
                var attribute as EA.Attribute;
                attribute = attributes.GetAt( j );
                if( attribute == null )
                    continue;

                var attr = xmlDoc.createNode( 1, 'attribute', '' );
                elementXml.appendChild( attr );

                attr.setAttribute( 'key', attribute.Name );
                attr.setAttribute( 'value', attribute.Default );
            }

            var tableCount = 0;
            var connectors as EA.Collection;
            connectors = element.Connectors;
            for( var j = 0; j < connectors.Count; j++ )
            {
                var connector as EA.Connector;
                connector = connectors.GetAt( j );
                if( connector == null )
                    continue;
                if( connector.ClientID != element.ElementID )
                    continue;
                if( connector.Direction != "Source -> Destination" )
                    continue;
                if( connector.Type != "Dependency" )
                    continue;
                var supplier as EA.Element;
                supplier = GetElementByID( connector.SupplierID );
                if( supplier == null )
                {
                    Session.Output( "got unknown element id " + connector.SupplierID );
                    continue;
                }
                if( supplier.Stereotype != "table" )
                    continue;

                elementXml.setAttribute( 'table', supplier.Name );
                tableCount += 1;
            }
            if ( tableCount < 1 )
            {
                Session.Output( "Got no information about associated database table for enumeration " + element.Name + " - not creating database entries for this enum" );
            }
            else if ( tableCount > 1 )
            {
                Session.Output( "Got more than one associated database table for enumeration " + element.Name + "!" );
            }
        }
    }
}

function exportDtcCustomFunctions( xmlDoc, xmlParent, _element )
{
    var element as EA.Element;
    element = _element;

    var dtcFunctionsXml = xmlDoc.createNode( 1, 'customDtcFunctions', '' );
    xmlParent.appendChild( dtcFunctionsXml );

    var dtcFunctionXml = xmlDoc.createNode( 1, 'customDtcFunction', '' );
    dtcFunctionsXml.appendChild( dtcFunctionXml );

    var methods as EA.Collection;
    methods = element.MethodsEx;
    for( var j = 0; j < methods.Count; j++ )
    {
        var method as EA.Method;
        method = methods.GetAt( j );
        if( method == null )
            continue;
        if( method.Stereotype == 'function' )
        {
            // export DTC functions
            exportFunctionDeclaration( xmlDoc, dtcFunctionXml, method );
        } else {
            warnOut('Found method ' + method.Name + ' with unhandled Sterotype "' + method.Stereotype + '"');
        }
    }
}

function exportIdlFunctionTopic( xmlDoc, functionTopicsXml, _element )
{
    var element as EA.Element;
    element = _element;

    // we need two connectors:
    // - Reply ( FunctionTopic -> idlStruct )
    // - Request ( idlStruct -> FunctionTopic )
    var replyConnector as EA.Connector;
    var requestConnector as EA.Connector;
    var replyElement as EA.Element;
    var requestElement as EA.Element;

    for( var j = 0; j < element.Connectors.Count; j++ )
    {
        var connector as EA.Connector;
        connector = element.Connectors.GetAt( j );
        if( connector == null )
            continue;
        if( connector.Type != "Dependency" )
            continue;
        // Reply ( FunctionTopic -> idlStruct )
        if( connector.ClientID == element.ElementID )
        {
            replyConnector = connector;
            replyElement = GetElementByID( connector.SupplierID )
        }
        else if( connector.SupplierID == element.ElementID )
        {
            requestConnector = connector;
            requestElement = GetElementByID( connector.ClientID )
        }
    }

    if ( requestElement == null )
    {
        Session.Output( "Could not find request TopicType for FunctionTopic " + element.Name );
        return;
    }
    if ( requestElement == null )
    {
        Session.Output( "Could not find reply TopicType for FunctionTopic " + element.Name );
        return;
    }
    // Session.Output( "RequestTopicType: " + requestElement.Name + ", ReplyTopicType: " + replyElement.Name );
    var functionTopicXml = xmlDoc.createNode( 1, 'functionTopic', '' );
    functionTopicsXml.appendChild( functionTopicXml );
    functionTopicXml.setAttribute( 'name', element.Name );
    functionTopicXml.setAttribute( 'requestTopicType', requestElement.Name );
    functionTopicXml.setAttribute( 'replyTopicType', replyElement.Name );
    functionTopicXml.setAttribute( 'requestTopicName', element.Name + "Request" );
    functionTopicXml.setAttribute( 'replyTopicName', element.Name + "Reply" );
    // def value = False
    var routeInReplay = TVGetElementTaggedValue(element, "Legatus::RouteTopicInReplay");
    functionTopicXml.setAttribute( 'routeInReplay', routeInReplay == 'true' ?  1 : 0 );

    var replyPackage as EA.Package;
    var requestPackage as EA.Package;
    var clientPackage as EA.Package;
    requestPackage = getFrameworkElement( GetElementByID( requestConnector.ClientID ) );
    replyPackage = getFrameworkElement( GetElementByID( replyConnector.SupplierID ) );
    currentPackage = getFrameworkElement( element );

    if ( requestPackage.Name != currentPackage.Name )
    {
        functionTopicXml.setAttribute( 'requestTopicType', requestPackage.Name + "::" + requestElement.Name );
    }
    if ( replyPackage.Name != currentPackage.Name )
    {
        functionTopicXml.setAttribute( 'replyTopicType', replyPackage.Name + "::" + replyElement.Name );
    }

}

function exportExternalFk( xmlDoc, fkXml, source, target )
{
    var sourcePackage as EA.Package;
    sourcePackage = getFrameworkElement( source );

    var targetPackage as EA.Package;
    targetPackage = getFrameworkElement( target );

    if (targetPackage.Name != sourcePackage.Name)
    {
        fkXml.setAttribute( 'service', targetPackage.Name );
        fkXml.setAttribute( 'serviceAbbr', targetPackage.Alias.toLowerCase() );
    }

    //Session.Output("sourcePackage: " + sourcePackage.Alias);
    //Session.Output("targetPackage: " + targetPackage.Alias);

    // try to get out the exercise/global dependency state
    var edTgtTable = getTaggedValueGroup( target, "Legatus::ExerciseDependency" );
    var edSrcTable = getTaggedValueGroup( source, "Legatus::ExerciseDependency" );        
    var edTgtPackage = getTaggedValueGroup( targetPackage, "Legatus::ExerciseDependency" );
    var edSrcPackage = getTaggedValueGroup( sourcePackage, "Legatus::ExerciseDependency" );
    // the four properties above can be inconsistent - we assume the best ...

    var tgtFqnName = targetPackage.Name + '.' + target.Name;
    var srcFqnName = sourcePackage.Name + '.' + source.Name;
    // table always wins, if availble
    if (edTgtTable && edTgtTable != '')
        edTgtPackage = edTgtTable;
    if (edSrcTable && edSrcTable != '')
        edSrcPackage = edSrcTable;
    var isTgtExerciseDependent = (edTgtPackage.indexOf('Exercise') >= 0);
    var isTgtGlobal = (edTgtPackage.indexOf('Global') >= 0);
    var isSrcExerciseDependent = (edSrcPackage.indexOf('Exercise') >= 0);
    var isSrcGlobal = (edSrcPackage.indexOf('Global') >= 0);
    // since global and exercise can both be active we can get into trouble here...
    if ( !isTgtExerciseDependent && !isTgtGlobal)
    {
        warnOut('Legatus::ExerciseDependency property for ' + tgtFqnName +
                ' is neither set for Framework nor Table - this is not allowed!');
        return;
    }
    if ( !isSrcExerciseDependent && !isSrcGlobal)
    {
        warnOut('Legatus::ExerciseDependency property for ' + srcFqnName +
                ' is neither set for Framework nor Table - this is not allowed!');
        return;
    }
    //Session.Output('Src: ' + srcFqnName + ' Global: ' + isSrcGlobal + ', Exercise: ' + isSrcExerciseDependent);
    //Session.Output('Tgt: ' + tgtFqnName + ' Global: ' + isTgtGlobal + ', Exercise: ' + isTgtExerciseDependent);
    // both are exercise dependent - do not export schema (so sqlgenerator generates fk to local table)
    if (isTgtExerciseDependent && isSrcExerciseDependent)
        return;
    // both are global - do not export schema (so sqlgenerator generates fk to local table)
    // but source must not be exerciseDependent because then we need the fqn
    // when src is exercise and tgt is global
    if (isTgtGlobal && isSrcGlobal && !isSrcExerciseDependent)
    {
        if (targetPackage.Name != sourcePackage.Name)
            fkXml.setAttribute( 'schema', targetPackage.Alias.toLowerCase() );
        return;
    }
    if (isSrcGlobal && isTgtExerciseDependent)
    {
        warnOut('Legatus::ExerciseDependency property for ' + srcFqnName +
                ' is global but destination (' + tgtFqnName +
                ' is exercise dependent - this is not allowed / impossible');
        return;
    }
    fkXml.setAttribute( 'schema', targetPackage.Alias.toLowerCase() );
}

function getDDSModel( _package, xmlDoc, xmlRootNode )
{
    var topicTypesXml = xmlDoc.createNode( 1, 'topicTypes', '' );
    xmlRootNode.appendChild( topicTypesXml );
    var functionTopicsXml = xmlDoc.createNode( 1, 'functionTopics', '' );
    xmlRootNode.appendChild( functionTopicsXml );

    var package as EA.Package;
    package = _package;
    var basePackage as EA.Package;
    basePackage = getFrameworkElement( package );
    var exportedTopicTypes = [];

    if( package.Elements.Count == 0 && package.Packages.Count == 0 ) {
        infoOut("'DDS Model' is empty.");
    }

    exportedTopicTypes = exportDDSModelPackage(package,
                                               basePackage,
                                               xmlDoc,
                                               xmlRootNode,
                                               topicTypesXml,
                                               functionTopicsXml,
                                               exportedTopicTypes );
}

function exportDDSModelPackage( _package, basePackage, xmlDoc, xmlRootNode, topicTypesXml, functionTopicsXml, exportedTopicTypes )
{
    var package as EA.Package;
    package = _package;

    // export all elements in this package
    var elements as EA.Collection;
    elements = package.Elements;
    for( var i = 0; i < elements.Count; i++ )
    {
        var element as EA.Element;
        element = elements.GetAt( i );

        //Session.Output("element.Stereotype = " + element.Stereotype + " Name = " + element.Name );
        if ( element.Stereotype == 'implementationClass' && element.Name == 'DTC')
        {
            exportDtcCustomFunctions( xmlDoc, xmlRootNode, element );
        }
        else if ( element.Stereotype == 'FunctionTopic' )
        {
            exportIdlFunctionTopic( xmlDoc, functionTopicsXml, element );
        }
        else if ( element.Stereotype == 'idlStruct'  || element.Stereotype == 'valueType' )
        {
            // do not export empty structs (see exportDDSBase() )
            if ( element.Attributes.Count == 0 )
            {
                infoOut('Not exporting dds struct ' + element.Name + ' - no attributes (not allowed by rtiddsgen)');
                continue;
            }
            
            if (element.Stereotype == 'valueType')
            {
                warnOut('Stereotype "valueType" is deprecated, please replace with "idlStruct" in struct ' + element.Name);
            }

            var topicTypeXml = xmlDoc.createNode( 1, 'topicType', '' );
            topicTypesXml.appendChild( topicTypeXml );
            topicTypeXml.setAttribute( 'name', element.Name );

            var ddsExtensibility = TVGetElementTaggedValue(element, "IDL::Extensibility");
            if ( ddsExtensibility )
                topicTypeXml.setAttribute( 'extensibility', ddsExtensibility);

            var ddsIsDataObject = TVGetElementTaggedValueEx(element, "IDL::IsDataObject") == 'true';
            if ( ddsIsDataObject ) {
                topicTypeXml.setAttribute( 'isDataObject', 1 );

                // def value = True
                var autosubscribe = TVGetElementTaggedValueEx(element, "Legatus::AutoSubscribe");
                topicTypeXml.setAttribute( 'autosubscribe', autosubscribe == 'false' ?  0 : 1 );

                // def value = True
                var routeToClient = TVGetElementTaggedValueEx(element, "Legatus::RouteTopicToClient");
                topicTypeXml.setAttribute( 'routeToClient', routeToClient == 'false' ?  0 : 1 );

                // def value = False
                var routeToServer = TVGetElementTaggedValueEx(element, "Legatus::RouteTopicToServer");
                topicTypeXml.setAttribute( 'routeToServer', routeToServer == 'true' ?  1 : 0 );

                // def value = False
                var routeInReplay = TVGetElementTaggedValueEx(element, "Legatus::RouteTopicInReplay");
                topicTypeXml.setAttribute( 'routeInReplay', routeInReplay == 'true' ?  1 : 0 );
            }

            var dtsAutogen = TVGetElementTaggedValue(element, "Legatus::AutogenDTS");
            if ( dtsAutogen == 'false' || dtsAutogen == 0 )
                topicTypeXml.setAttribute( 'autogenDTS', 0 );

            var dtcAutogen = TVGetElementTaggedValue(element, "Legatus::AutogenDTC");
            if ( dtcAutogen == 'false' || dtcAutogen == 0 )
                topicTypeXml.setAttribute( 'autogenDTC', 0 );

            // Attributes
            var attributes as EA.Collection;
            attributes = element.AttributesEx;    // we need to investigate all, but only export our own
            for( var j = 0; j < attributes.Count; j++ )
            {
                var attribute as EA.Attribute;
                attribute = attributes.GetAt( j );
                if( attribute == null )
                    continue;

                if( ddsIsDataObject && attribute.Name == 'sampleTime' && attribute.Notes != 'no_record' )
                    topicTypeXml.setAttribute( 'recordTopic', 1 );
                // only export our own attributes - isDerived does not work as expected
                if( attribute.ParentID != element.ElementID )
                    continue;

                var columnXml = xmlDoc.createNode( 1, 'column', '' );
                topicTypeXml.appendChild( columnXml );

                columnXml.setAttribute( 'name', attribute.Name );
                columnXml.setAttribute( 'idlType', attribute.Type );
                //infoOut("attribute.Name: " + element.Name + ":" + attribute.Name);
                if ( attribute.ClassifierID != 0 )
                {
                    var attributeTypePackage as EA.Package;
                    attributeTypePackage = getFrameworkElement( GetElementByID( attribute.ClassifierID ) );
                    if ( attributeTypePackage != null && attributeTypePackage.Name != basePackage.Name )
                    {
                        columnXml.setAttribute( 'idlType', attributeTypePackage.Name + "::" + attribute.Type );
                    }
                }

                //Session.Output("StereoType:" + attribute.Stereotype);
                if( attribute.Stereotype == "key" )
                    columnXml.setAttribute( 'isKey', 1 );
                if( attribute.Stereotype == "Optional" | attribute.Stereotype == "optional" )
                    columnXml.setAttribute( 'isOptional', 1 );
                if ( attribute.Stereotype == "translatable" )
                    columnXml.setAttribute( 'isTranslatable', 1);

                if( attribute.Notes != "" )
                    columnXml.setAttribute( 'comment', attribute.Notes );
            }

            var supplierCon = getConnectorFromElement( element, "Generalization" )
            exportDDSBase( xmlDoc, topicTypesXml, topicTypeXml, supplierCon, exportedTopicTypes );
        }
    }
    // now handle subpackages
    var packages as EA.Collection;
    packages = package.Packages;
    for( var i = 0; i < packages.Count; ++i )
    {
        exportedTopicTypes = exportDDSModelPackage(packages.GetAt(i),
                                                    basePackage,
                                                    xmlDoc,
                                                    xmlRootNode,
                                                    topicTypesXml,
                                                    functionTopicsXml,
                                                    exportedTopicTypes );
    }
    return exportedTopicTypes
}

function ExportServiceInformation( _package, xmlDoc, xmlRootNode )
{
    var servicePackage as EA.Package;
    var serviceCollection as EA.Collection;
    var hasDbServiceStructs = false;
    var hasDataBaseModel     = false;
    var hasEnumerations     = false;
    var hasDdsModel         = false;

    servicePackage = _package;
    serviceCollection = servicePackage.Packages;
    for( var i = 0; i < serviceCollection.Count; i++ )
    {
        var obj = serviceCollection.GetAt( i );
        if( obj.ObjectType == otPackage )
        {
            var package as EA.Package
            package = obj
            if( package.Name == "Database Service Structs") {
                infoOut('Handling Database Service Structs ...');
                getDBServiceStructs( package, xmlDoc, xmlRootNode )
                hasDbServiceStructs = true;
                infoOut('... ready');
            } else
            if( package.Name == "Database Model") {
                infoOut('Handling Database Model ...');
                getDBModel( package, xmlDoc, xmlRootNode )
                getDBViews( package, xmlDoc, xmlRootNode )
                hasDataBaseModel = true;
                infoOut('... ready');
            } else
            if( package.Name == "Enumerations") {
                infoOut('Handling Enumerations ...');
                getEnumerations( package, xmlDoc, xmlRootNode )
                hasEnumerations = true;
                infoOut('... ready');
            } else
            if( package.Name == "DDS Model") {
                infoOut('Handling DDS Model ...');
                getDDSModel( package, xmlDoc, xmlRootNode)
                hasDdsModel = true;
                infoOut('... ready');
            }
        }
    }

    if( !hasDbServiceStructs) {
        warnOut("'Database Service Structs' not found!");
    }
    if( !hasDataBaseModel) {
        warnOut("'Database Model' not found!");
    }
    if( !hasEnumerations) {
        warnOut("'Enumerations' not found!");
    }
    if( !hasDdsModel) {
        warnOut("'DDS Model' not found!");
    }
}

function ExportOperatorRights( _frameworkElement, _package, xmlDoc, xmlRootNode )
{
    infoOut('Handling Operator Rights ...');
    var frameworkElement as EA.Element;
    frameworkElement = _frameworkElement;
    var package as EA.Package;    // 'Plugin'
    package = _package;

    var svcRightsOfs = TVGetElementTaggedValue( frameworkElement, "Legatus::OperatorRightsServiceOffset" );
    if( svcRightsOfs == null || svcRightsOfs == "" )
    {
        warnOut( 'Legatus::OperatorRightsServiceOffset is not defined for framework ' + frameworkElement.Name );
        return;
    }
    var rightsRootNode = xmlDoc.createNode( 1, 'operatorRights', '' );
    xmlRootNode.appendChild( rightsRootNode );
    rightsRootNode.setAttribute( 'offset', svcRightsOfs);
    if (!package)
        return;
    
    var pluginPackages as EA.Collection;
    pluginPackages = package.Packages;
    for( var i = 0; i < pluginPackages.Count; i++ )
    {
        var pluginPackage as EA.Package;
        pluginPackage = pluginPackages.GetAt( i );
        var plgRightsOfs = TVGetElementTaggedValue( pluginPackage.Element, "Legatus::OperatorRightsGuiPluginOffset" );
        if( plgRightsOfs == null || plgRightsOfs == "" )
        {
            warnOut( 'Legatus::OperatorRightsGuiPluginOffset is not defined for Gui Plugin1 ' + pluginPackage.Name );
            continue;
        }
        var pluginRightsNode = xmlDoc.createNode( 1, 'guiPlugin', '' );
        rightsRootNode.appendChild( pluginRightsNode );
        pluginRightsNode.setAttribute( 'name', pluginPackage.Name );
        pluginRightsNode.setAttribute( 'offset', plgRightsOfs );
        
        //warnOut('name: ' + pluginPackage.Name)
        var elements = pluginPackage.Elements;
        for (var j = 0; j < elements.Count; j++)
        {
            var element as EA.Element;
            var element = elements.GetAt( j );
            if (element.Stereotype != 'enumeration')
                continue;

            var attributes as EA.Collection;
            attributes = element.Attributes;
            
            if (attributes.Count == 0)
                continue;

            var group = xmlDoc.createNode( 1, 'operatorRightGroup', '' );
            pluginRightsNode.appendChild( group );
            group.setAttribute( 'name', element.Name )
            if( element.Notes != "" )
                group.setAttribute( 'description', element.Notes )
            

            for (var k = 0; k < attributes.Count; k++)
            {
                var attribute as EA.Attribute;
                attribute = attributes.GetAt( k );

                var attributeNode = xmlDoc.createNode( 1, 'operatorRight', '' );
                group.appendChild( attributeNode );
                attributeNode.setAttribute( 'right', attribute.Name );
                attributeNode.setAttribute( 'value', attribute.Default );
                if( attribute.Notes != "" )
                    attributeNode.setAttribute( 'description', attribute.Notes );
            }
        }
    }
}

function DoSomething()
{
    // Show the script output window
    Repository.EnsureOutputVisible( "Script" );

    // Get the set of selected items as a collection
    var selPkg  = Repository.GetTreeSelectedPackage();

    var frameworkPackage as EA.Package;
    frameworkPackage = getFrameworkPackage( selPkg );
    if( frameworkPackage != null )
    {
        Session.Output( "Export Service information data for " + frameworkPackage.Name );
        Session.Output( "===============================" );
        var xmlDoc = new ActiveXObject( 'Msxml2.DOMDocument' );
        var xmlRootNode = xmlDoc.createNode( 1, 'service', '' );
        xmlDoc.appendChild( xmlRootNode );
        var xmlSvnNode = xmlDoc.createNode( 1, 'rcs', '' );
        xmlRootNode.appendChild( xmlSvnNode );
        var xmlSvnNodeId = xmlDoc.createNode( 1, 'Id', '' );
        xmlSvnNode.appendChild( xmlSvnNodeId );
        xmlSvnNodeId.setAttribute( 'Id', '$Id$' )
        var xmlSvnNodeUrl = xmlDoc.createNode( 1, 'HeadURL', '' );
        xmlSvnNode.appendChild( xmlSvnNodeUrl );
        xmlSvnNodeUrl.setAttribute( 'HeadURL', '$HeadURL$' )
        var xmlSvnNodeAuthor = xmlDoc.createNode( 1, 'Author', '' );
        xmlSvnNode.appendChild( xmlSvnNodeAuthor );
        xmlSvnNodeAuthor.setAttribute( 'Author', '$Author$' )

        var frameworkElement as EA.Element;
        frameworkElement = frameworkPackage.Element;

        var frameworkCollection as EA.Collection;
        frameworkCollection = frameworkPackage.Packages;

        // now search 'Service' Package inside frameworkCollection
        var opRightsExported = false;
        for( var i = 0; i < frameworkCollection.Count; i++ )
        {
            var obj = frameworkCollection.GetAt( i );
            if( obj.ObjectType == otPackage )
            {
                var package as EA.Package;
                package = obj;
                if( package.Name == "Service" || package.Name == "Proxy" ) {
                    ExportServiceInformation( package, xmlDoc, xmlRootNode );
                }
                if( package.Name == "OperatorRights" ) {
                    ExportOperatorRights( frameworkElement, package, xmlDoc, xmlRootNode );
                    opRightsExported = true;
                }
            }
        }
        
        if (!opRightsExported) {
            ExportOperatorRights( frameworkElement, null, xmlDoc, xmlRootNode );
        }

        xmlRootNode.setAttribute( 'namespace', frameworkPackage.Name );
        xmlRootNode.setAttribute( 'abbreviation', frameworkPackage.Alias.toUpperCase() );
        var procNames = TVGetElementTaggedValue( frameworkElement, "Legatus::ProcNames" );
        if( procNames == null || procNames == "" )
            procNames = frameworkPackage.Name;
        xmlRootNode.setAttribute( 'procNames', procNames );
        var customRecordReplay = TVGetElementTaggedValue( frameworkElement, "Legatus::CustomRecordReplayPlugin" );
        if( customRecordReplay == 'true' )
            xmlRootNode.setAttribute( 'customRecordReplay', 1 );

        exportTaggedValueGroup( xmlRootNode, 'exerciseDependency', frameworkElement, 'Legatus::ExerciseDependency' );
        exportTaggedValueGroup( xmlRootNode, 'groups', frameworkElement, 'Legatus::Groups' );

        var writer =  new ActiveXObject( "MSXML2.MXXMLWriter" );
        writer.indent = true;
        writer.encoding = "UTF-8";    // for files only
        writer.omitXMLDeclaration = false;
        writer.standalone = true;
        var reader = new ActiveXObject( "MSXML2.SAXXMLReader" );
        reader.contentHandler = writer;
        reader.parse(xmlDoc);

        var fso = new ActiveXObject("Scripting.FileSystemObject");
        var outputFile = "C:\\TDS\\" + frameworkElement.Alias.toLowerCase() + "_service.xml";
        Session.Output("OutputFile: " + outputFile );
        var textStream = fso.CreateTextFile(outputFile, true);
        // Writer always uses utf-16 as output ecoding - whyever
        // also replace tab with 2 spaces
        textStream.Write(writer.output.replace("encoding=\"UTF-16\"", "encoding=\"UTF-8\"").replace(/\t/g, "  "));
        textStream.Write("\n");
        textStream.Close();

        //Session.Prompt( "Wrote framework '" + frameworkPackage.Name + "' to " + outputFile , promptOk );
    } else {
        Session.Prompt( "This script requires the current context item to be a framework package.\n" +
            "Please select a framework package and try again.", promptOK );
    }
}

DoSomething();


function getPackageByName( element_, requestedName )
{
    var element as EA.Element;
    element = element_;
    if ( element.Name == requestedName )
        return element;

    var elementId = element.PackageID;
    if ( element.ObjectType == otPackage )
    {
        var package as EA.Package;
        package = element;
        var packageElement as EA.Element;
        packageElement = package.Element;
        if ( packageElement == null )
            return null;
        if ( packageElement.Name == requestedName )
            return package;
        elementId = element.ParentID;
    }
    element = Repository.GetPackageByID( elementId );

    return getPackageByName( element, requestedName )
}

function isFrameworkPackage( element )
{
    if( element.ObjectType != otPackage )
        return false;
    var package as EA.Package;
    package = element;
    return ( package.StereotypeEx == 'framework' )
}

function getOperatorRightsEnum( element )
{
    var package as EA.Package;
    package = element;
    var elements = package.Elements;

    for (var i = 0; i < elements.Count; i++ )
    {
        var element as EA.Element;
        var element = elements.GetAt( i );
        if ( element.Stereotype == 'enumeration' && element.Name == 'OperatorRights' )
            return element;
    }
    return null;
}

function ExportOperatorRightsTest()
{
    // Show the script output window
    Repository.EnsureOutputVisible( "Script" );

    Session.Output( "Export Operator Rights" );
    Session.Output( "======================" );
    // Get the set of selected items as a collection
    var selPkg  = Repository.GetTreeSelectedPackage();

    var scPackage as EA.Package;
    if( selPkg != null )
    {
        scPackage = getPackageByName( selPkg, 'Software Components' );
    }
    if ( scPackage == null )
    {
        Session.Prompt( "This script requires the current context item to be inside the 'Software Components' package\n" +
            "Please select this package and try again.", promptOK );
        return;
    }
    // now walk every leaf and search for an element named 'OperatorRights'
    // with the stereotype 'enumeration'
    // the path should be <<framework>> <Foo> / Plugin / <Bar> / <<enumeration>> OperatorRights

    var frameworkPackages as EA.Collection;
    frameworkPackages = scPackage.Packages;
    for( var i = 0; i < frameworkPackages.Count; i++ )
    {
        var obj = frameworkPackages.GetAt( i );
        if ( !isFrameworkPackage( obj ) )
            continue;
        var package as EA.Package;
        package = obj;
        var subPackages = package.Packages;
        for( var j = 0; j < subPackages.Count; j++ )
        {
            var subObj = subPackages.GetAt( j );
            if ( subObj.Name != 'Plugin' )
                continue;
            var subPackage as EA.Package;
            subPackage = subObj;
            var pluginPackages = subPackage.Packages;
            for ( var k = 0; k < pluginPackages.Count; k++ )
            {
                var element as EA.Element;
                element = getOperatorRightsEnum( pluginPackages.GetAt( k ) );
                if ( element == null )
                    continue;
                var attributes as EA.Collection;
                attributes = element.Attributes;
                for( var j = 0; j < attributes.Count; j++ )
                {
                    var attribute as EA.Attribute;
                    attribute = attributes.GetAt( j );
                    Session.Output('found attribute: ' + attribute.Name + ' - ' + attribute.Default );
                }
            }
        }
    }
}

//ExportOperatorRightsTest();

