#!/usr/bin/env python
############################################################################
#  
#  Copyright (c)2000 Fourthought, Inc.
#  http://ftsuite.com/4ODS
#
############################################################################
#
# File Name: 		4odb_dig.py
#
# Documentation:	http://docs.ftsuite.com/4ODS/Tools/4odb_dig.py.html
#

import Ft, sys
try:
    import readline
except ImportError:
    pass
__doc__ = """View Metadata information about a 4ODS database"""

import os, code, string
import sys
from Ft.Ods import Database, Exception


from Ft.Ods.MetaData import PrimitiveType
from Ft.Ods.MetaData import Class
from Ft.Ods.MetaData import Structure
from Ft.Ods.MetaData import Attribute
from Ft.Ods.MetaData import Repository
from Ft.Ods.MetaData import Member
from Ft.Ods.MetaData import Module
from Ft.Ods.MetaData import Relationship
from Ft.Ods.MetaData import Enumeration
from Ft.Ods.MetaData import Collection
from Ft.Ods.MetaData import Constant
from Ft.Ods.MetaData import PrimitiveType


def ShowUnknownMetaObject(mo,indent):
    if isinstance(mo,Class.Class):
        ShowClass(mo,indent)
    elif isinstance(mo,Structure.Structure):
        ShowStructure(mo,indent)
    elif isinstance(mo,Attribute.Attribute):
        ShowAttribute(mo,indent)
    elif isinstance(mo,Repository.Repository):
        ShowRepository(mo,0)
    elif isinstance(mo,Member.Member):
        ShowMember(mo,indent)
    elif isinstance(mo,Module.Module):
        ShowModule(mo,indent)
    elif isinstance(mo,Relationship.Relationship):
        ShowRelationship(mo,indent)
    elif isinstance(mo,Enumeration.Enumeration):
        ShowEnumeration(mo,indent)
    elif isinstance(mo,Constant.Constant):
        ShowConstant(mo,indent)
    elif isinstance(mo,PrimitiveType.PrimitiveType):
        ShowPrimitiveType(mo,indent)
    else:
        raise mo


def ShowModule(mod,indent):
    print '  ' * indent + "Module: ", mod.absolute_name()
    indent = indent + 1
    ShowMetaObject(mod,indent)
    ShowDefiningScope(mod,indent)
ShowRepository = ShowModule

def ShowStructure(struct,indent):
    print '  ' * indent + "Structure: ", struct.absolute_name()
    indent = indent + 1
    print '  ' * indent + 'Fields:'
    for m in struct.fields:
        ShowMember(m,indent+1)
    if struct.exceptionResult:
        raise "Exception Result"
    ShowScopedType(struct,indent)

def ShowClass(klass,indent):
    print '  ' * indent + "Class: ", klass.absolute_name()
    indent = indent + 1
    exts = klass.extents
    if len(exts):
        ext = exts[0]
    else:
        ext = None
    print '  ' * indent + "Extent: ", ext
    print '  ' * indent + "Keys: None"
    if klass.extender:
        print '  ' * indent + "Extender: ",klass.extender.absolute_name()
    else:
        print '  ' * indent + "Extender: None"
    print '  ' * indent + "Extensions:"
    ShowCollection(klass.extensions,indent+1)
    ShowInterface(klass,indent)


def ShowEnumeration(enum,indent):
    print '  ' * indent + "Enumeration: ", enum.absolute_name()
    indent = indent + 1
    print '  ' * indent + 'Elements:'
    for e in enum.elements:
        ShowConstant(e,indent+1)
    ShowScopedType(enum,indent)

def ShowConstant(const,indent):
    print '  ' * indent + "Constant: ", const.absolute_name()
    indent = indent + 1    
    if const.the_Value:
        print '  ' * indent + 'the_Value: ',const.the_Value.value()
    else:
        print '  ' * indent + 'the_Value: None'
    print '  ' * indent + 'type: ', const.type.absolute_name()
    print '  ' * indent + 'referenced_by:'
    ShowCollection(const.referenced_by,indent+1)
    if const.enumeration:
        print '  ' * indent + 'enumeration: ',const.enumeration.absolute_name()
    else:
        print '  ' * indent + 'enumeration: None'
    print '  ' * indent + 'value: ',const.value()
    ShowMetaObject(const,indent)

    
def ShowInterface(interface,indent):
    print '  ' * indent + "Inherits: None"
    print '  ' * indent + "Derives: None"
    ShowType(interface,indent)
    ShowDefiningScope(interface,indent)


def ShowAttribute(attr,indent):
    print '  ' * indent + "Attribute: ",attr.absolute_name()
    indent = indent + 1
    print '  ' * indent + "is_read_only: %s" % str(attr.is_read_only)
    ShowProperty(attr,indent)


def ShowRelationship(rel,indent):
    print '  ' * indent + "Relationship: ",rel.absolute_name()
    indent = indent + 1
    print '  ' * indent + 'traversal: ',rel.traversal.absolute_name()
    ShowProperty(rel,indent)

def ShowProperty(property,indent):
    print '  ' * indent + "type: ", property.type.absolute_name()
    ShowMetaObject(property,indent)

def ShowMember(member,indent):
    print '  ' * indent + "Member: ", member.absolute_name()
    indent = indent + 1
    print '  ' * indent + 'Structure Type to: ', member.structure_type.absolute_name()
    ShowSpecifier(member,indent)



def ShowMetaObject(mo,indent):
    print '  ' * indent + 'Name: ', mo.name
    print '  ' * indent + 'Comment: ', mo.comment
    if mo.definedIn:
        print '  ' * indent + 'Defined In: %s id(%i)' %(mo.definedIn.absolute_name(),mo._4ods_getId())
    else:
        print '  ' * indent + 'Defined In: GLOBAL'


def ShowScopedType(st,indent):
    ShowType(st,indent)
    ShowScope(st,indent)

def ShowDefiningScope(ds,indent):
    print '  ' * indent + "Defines:"
    if len(ds.defines) == 0:
        print '  '*(indent + 1) + 'None'
        return
    for d in ds.defines:
         ShowUnknownMetaObject(d,indent+1)  
    ShowScope(ds,indent)

def ShowSpecifier(spec,indent):
    print "  " * indent + "name: ", spec.name
    print "  " * indent + "type: ", spec.type.name
    print "  " * indent + "metaId: ", spec.metaId
    

def ShowPrimitiveType(pt,indent):
    print '  ' * indent + "PrimitiveType: ",pt.absolute_name()
    print '  ' * (indent+1) + "primitive_kind: ",str(pt.primitive_kind)
    ShowType(pt,indent+1)
    

def ShowType(t,indent):
    #indent = indent + 1
    print "  " * indent + "Of Collection:"
    ShowCollection(t.collections,indent + 1)
    print "  " * indent + "Of Specifier:"
    ShowCollection(t.specifiers,indent + 1)
    print "  " * indent + "Of Union:"
    ShowCollection(t.unions,indent + 1)
    print "  " * indent + "Of Operation:"
    ShowCollection(t.operations,indent + 1)
    print "  " * indent + "Of Property:"
    ShowCollection(t.properties,indent + 1)
    print "  " * indent + "Of constant:"
    ShowCollection(t.constants,indent + 1)
    print "  " * indent + "Of TypeDefs:"
    ShowCollection(t.type_defs,indent + 1)


def ShowScope(sc,indent):
    pass

def ShowCollection(coll,indent):
    if len(coll) == 0:
        print '  ' * indent + "None"
        return
    for e in coll:
        print '  ' * indent + ((e and e.absolute_name()) or '??None??')


def ResolveName(name):
    global db
    if not string.strip(name):
        return db.schema()
    try:
        return db.schema().resolve(name)
    except:
        print "Unknown Object %s" % name
        return None

def Run(options,args):

    from Ft.Ods.StorageManager import Adapters
    dbName = args['dbName']
    Adapters.g_driverName = options.get('adapter')
    
    global db
    db = Database.Database()
    db.open(dbName)

    console = code.InteractiveConsole({})


    tx = db.new()
    tx.begin()
    try:
        while 1:
            cmd = console.raw_input(">>> ")

            lcmd = string.strip(string.lower(cmd))

            
            if lcmd == 'quit':
                break
            elif lcmd[:4] == 'odl(':
                name = string.strip(cmd)[4:-1]
                obj = ResolveName(name)
                if obj:
                    print obj._4ods_getOdl()
            else:
                #Resolve a name
                obj = ResolveName(cmd)
                if obj:
                    ShowUnknownMetaObject(obj,0)

    finally:
        tx.abort()

    db.close()

    return



def Register():

    from Ft.Lib.CommandLine import Options, Command, Arguments

    cmd = Command.Command('metadig',
                          'View metadata in a 4ODS database',
                          'test',                          
                          __doc__,
                          function = Run,
                          arguments = [Arguments.RequiredArgument('dbName',
                                                                  'The name of the database.',
                                                                  str),
                                       ],
                                                               
                          heading = """4ODS MetaDig Tool
Version %s Copyright Fourthought, Inc 2001""" % Ft.__version__,

                          )
    return cmd
