import time
from Ft.Ods.MetaData import MetaKind

from Ft.Ods.Exception import FtodsUnknownError
from Ft.Ods.Exception import FtodsUnsupportedError

from Ft.Ods import Constants

def NormalizeTypeDefinition(typ):
    #Note, the rel_type might be a typedef

    orig = typ
    found = []
    while typ.meta_kind == MetaKind.mk_type_definition:
        if type in found:
            raise FtodsUnknownError(msg="Recursive Type Definition: %s" % orig._4ods_getOdl())
        found.append(typ)
        typ = typ.alias
    return typ



def WriteFileHeader(stream,repoName):
    stream.write('#'*80 + '\n')
    stream.write('# DO NOT EDIT THIS FILE!\n')
    stream.write('#\n')
    stream.write("# Python module %s generated by 4ODS's OdlParse\n" % repoName)
    stream.write("# Module Generated on %s\n" % time.asctime(time.localtime(time.time())))
    stream.write('#\n')
    stream.write('#\n')
    stream.write('#\n')
    stream.write('#'*80 + '\n')
    


def BuildNameAndTypeList(defines):
    names = []
    types = []
    for define in defines:
        if define.meta_kind in [MetaKind.mk_attribute,
                                MetaKind.mk_relationship,
                                MetaKind.mk_member,
                                MetaKind.mk_union_case]:
            name = define.name
            odmgType = define._4ods_getOdmgType()
            dType = NormalizeTypeDefinition(define.type)
            if not Constants.g_literalTypes[dType._4ods_getOdmgType()]:
                #Literals append thier values later
                names.append((name,))
                types.append((dType,))
            else:
                #Add out types and names to the list
                schema = define._db.schema()
                if dType._4ods_getOdmgType() == Constants.Types.DATE:
                    names.append((name,(("year",),
                                        ("month",),
                                        ("day",))))
                    types.append((dType,(((schema.resolve('pk_short'),),
                                        (schema.resolve('pk_short'),),
                                        (schema.resolve('pk_short'),)))))
                elif dType._4ods_getOdmgType() == Constants.Types.INTERVAL:
                    names.append((name,))
                    types.append((dType,))
                elif dType._4ods_getOdmgType() == Constants.Types.TIME:
                    schema = define._db.schema()
                    names.append((name,((("hour",),
                                         ("minute",),
                                         ("second",),
                                         ("millisecond",),
                                         ("tz_hour",),
                                         ("tz_minute",)))))
                    types.append((dType,(((schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),)))))
                elif dType._4ods_getOdmgType() == Constants.Types.TIMESTAMP:
                    schema = define._db.schema()
                    names.append((name,((("year",),
                                         ("day",),
                                         ("month",),
                                         ("hour",),
                                         ("minute",),
                                         ("second",),
                                         ("millisecond",),
                                         ("tz_hour",),
                                         ("tz_minute")))))
                    types.append((dType,(((schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),),
                                          (schema.resolve('pk_short'),)))))
                elif dType._4ods_getOdmgType() == Constants.Types.ENUMERATION:
                    names.append((name,))
                    types.append((dType,))
                elif dType._4ods_getOdmgType() == Constants.Types.STRUCTURE:
                    sn,st = BuildNameAndTypeList(dType.fields)
                    names.append((name,sn))
                    types.append((dType,st))
                elif dType._4ods_getOdmgType() == Constants.Types.FIXEDSTRING:
                    schema = define._db.schema()
                    names.append((name,))
                    types.append((dType,))
                elif dType._4ods_getOdmgType() == Constants.Types.UNION:
                    sn,st = BuildNameAndTypeList(dType.cases)
                    sn = list(sn)
                    st = list(st)
                    sn.insert(0,('ftods_discriminate',))
                    st.insert(0,(dType.switch_type,))
                    sn = tuple(sn)
                    st = tuple(st)
                    names.append((name,sn))
                    types.append((dType,st))
                else:
                    raise FtodsUnsupportedError("Nested Types of %s" % Constants.g_odmgTypeToString[dType._4ods_getOdmgType()])
                    

    return tuple(names),tuple(types)




def PrintNamesTypesValues(names,types,values=None,indent=''):

    for ctr in range(len(names)):
        name = names[ctr]
        t = types[ctr]
        if values:
            v = values[ctr]
        else:
            v = "Unknown"


        if type(name) == type(()) and len(name) == 2:
            print "Nested name %s of %s" % (name[0],t[0])
            if len(t) != 2:
                raise "Types of %s are wrong: %s" % (name[0],str(types))
            if values and v is not None and (type(v) != type(()) or len(v) != 2):
                raise "Values of %s are wrong: %s" % (name[0],str(values))

            if values and v is not None:
                PrintNamesTypesValues(name[1],t[1],v[1],indent = indent + '  ')
            else:
                PrintNamesTypesValues(name[1],t[1],indent = indent + '  ')
        elif type(name) == type(()):
            name = name[0]
            t = t[0]
            if values:
                v = v[0]

        print "%s%s of %s = %s" % (indent,name,t,v)

            
        
