import struct, string
from math import *
from rwutils import *

TID_STATIC  = 0x0553c98
TID_DYNAMIC = 0x5463c98

def str_hex(s):
    res = ''
    for c in s:
        res = res + ('%02x' % struct.unpack('=B', c)[0]) + ' '
    return res

def fmtw(s, i):
    return struct.unpack('<l', s[i:i + 4])[0]
        
def fmtf(s, i):
    return struct.unpack('<f', s[i:i + 4])[0]


######################################################################
class OHole:
    """Hole info"""

    fmt = "lost chunk?"

    def __init__(self, file):
        self.data = read_word(file)

    def __str__(self):
        return "%08X(%d)\n" % (self.data, self.data)

######################################################################    
class OVertData:
    """Vertexes"""
    
    fmt = "float x, y, z, =0?"
    
    def __init__(self, file):
        self.data = []; n = read_word(file)
        for i in range(n):
            self.data.append((read_float(file), read_float(file),
                              read_float(file), read_float(file)))

    def __str__(self):
        res = '%d vertexes\n' % len(self.data)
        for x, y, z, n in self.data:
            res = res + ('x:% 11f, y: % 11f, z: % 11f, 0: % 11f\n' % (x,
                                                                      y, z, n))
        return res

######################################################################
class OTriData:
    """Triangles"""

    fmt = "half a b c, char?=[0,1]?, char material?"
    
    def __init__(self, file):
        self.data = []; n = read_word(file)
        for i in range(n):
            self.data.append((read_half(file), read_half(file),
                              read_half(file), read_char(file),
                              read_char(file)))

    def __str__(self):
        res = '%d triangles\n' % len(self.data)
        i = 0
        for a, b, c, f, texture in self.data:
            res = res + ('%-4d: ' % i)
            res = res + ('a: %4d, b: %4d, c: %4d, texture: %4d, ?: %d\n' % \
                         (a, b, c, f, texture))
            i = i + 1
        return res


######################################################################
class OTriInfoData:
    """Triangle (per edge) information"""

    fmt = "half? half? half?"
    
    def __init__(self, file):
        self.data = []; n = read_word(file)
        for i in range(n):
            self.data.append((read_half(file), read_half(file),
                              read_half(file)))

    def __str__(self):
        res = '%d tri info\n' % len(self.data)
        for e in self.data:
            res = res + ('a:% 4d, b:% 4d, c:% 4d\n' % (e[0], e[1], e[2]))
        return res

######################################################################    
class OVertNormalsData:
    """Vertex normals"""

    fmt = "float x, y, z"
    
    def __init__(self, file):
        self.data = []; n = read_word(file)
        for i in range(n):
            self.data.append((read_float(file), read_float(file),
                              read_float(file)))

    def __str__(self):
        res = '%d vertex normals\n' % len(self.data)
        for x, y, z in self.data:
            res = res + ('x: % 11f, y: % 11f, z: % 11f\n' % (x, y, z))
        return res

######################################################################
class OTriNormalsData:
    """Triangle normals"""

    fmt = "float x, y, z"
    
    def __init__(self, file):
        self.data = []; n = read_word(file)
        for i in range(n):
            self.data.append((read_float(file), read_float(file),
                              read_float(file)))

    def __str__(self):
        res = '%d triangle normals\n' % len(self.data)
        for x, y, z in self.data:
            res = res + ('x: % 11f, y: % 11f, z: % 11f\n' % (x, y, z))
        return res

######################################################################
class OTexData:
    """Texture coordinates"""

    fmt = "float (un, vn)[3]"
    
    def __init__(self, file):
        self.data = []; n = read_word(file)
        for i in range(n):
            self.data.append(((read_word(file), read_word(file)),
                              (read_word(file), read_word(file)),
                              (read_word(file), read_word(file))))

    def __str__(self):
        res = '%d texture coordinates\n' % len(self.data)
        for e in self.data:
            res = res + ('(u0, v0) (%d, %d)\n' % (e[0][0], e[0][1]))
            res = res + ('(u1, v1) (%d, %d)\n' % (e[1][0], e[1][1]))
            res = res + ('(u2, v2) (%d, %d)\n\n' % (e[2][0], e[2][1]))
        return res

######################################################################
class OMatData:
    """Materials"""

    fmt = "word ?=2?, name[word len, char[len]][4]?, char[12]?"
    
    def __init__(self, file):
        self.data = []; n = read_word(file)
        for i in range(n):
            cnt = read_word(file) * 2
            names = []
            for j in range(cnt):
                len = read_word(file)
                names.append(file.read(len))
            self.data.append((names, file.read(12)))

    def __str__(self):
        res = '%d materials\n' % len(self.data)
        for e in self.data:
            for name in e[0]:
                res = res + ('"%s" ' % name)
            res = res + 'data: ' + str_hex(e[1]) + '\n'
        return res

######################################################################
class OUnk1:
    """Poly, vertex, limb common information(?) (.amh only)"""

    fmt = "word npolys, word poly, word nverts, word vertex, float ?=(0, 1)?"
    
    def __init__(self, file):
        self.data = []; n = read_word(file)
        for i in range(n):
            self.data.append(read_word(file), read_word(file),
                             read_word(file), read_word(file),
                             read_float(file))
    def __str__(self):
        sum = 0.0
        res = '%d something\n' % len(self.data)
        for e in self.data:
            res = res + ("npoly %5d poly %5d nverts %5d vertex %5d % 11f\n" %\
                         (e[0], e[1], e[2], e[3], e[4]))
            sum = sum + e[4]
        return res + ("5th field sum = % 11f\n" % sum)

######################################################################
prev = ''
class OUnk2:
    """Skeleton data(?) (.amh only)"""

    fmt = """word type, word count of chunk#9 entries, word index into chunk#9,
    word poly, float x, y, z [, float m[9], float x, y, z]"""
    
    sizes = [24, 24, 72, 72]
    
    def __init__(self, file):
        def cmp(str):
            global prev
            for i in range(len(str)):
                a, b = struct.unpack('=B', str[i])[0], \
                       struct.unpack('=B', prev[i])[0]
                if a != b:
                    print 'different %02x, %02x at %d' % (a, b, i)
                    return 0
            return 1

        def prt(str):
            global prev
            x = len(str) / 12
            for i in range(x):
                print 'prv(%4d): %s' % (i * 12, str_hex(prev[i * 12:i * 12 + 12]))
                print 'str(%4d): %s' % (i * 12, str_hex(str[i * 12:i * 12 + 12]))
                print
            
        self.data = []; n = read_word(file)
        str = ''
        for i in range(n):
            x = read_word(file)
            s = file.read(self.sizes[x])
            str = str + s[12:24]
            self.data.append(x, s)

        if 0:
            global prev
            if prev == '':
                prev = str
            else:
                if not cmp(str):
                    prt(str)
                    prev = str
            
    def __str__(self):
        def wrd3(s, i):
            return fmtw(s, i), fmtw(s, i + 4), fmtw(s, i + 8)

        def flt3(s, i):
            return fmtf(s, i), fmtf(s, i + 4), fmtf(s, i + 8)
        
        res = '%d something\n' % len(self.data)
        for n, s in self.data:
            res = res + '-' * 40
            res = res + ('\ntype: %d,  count: %d, index: %d, poly: %d\n' %\
                         ((n,) + wrd3(s, 0)))
            res = res + ('x: % 11f, y: % 11f, z: % 11f\n\n' % flt3(s, 12))
            if n >> 1: # in [2,3]
                res = res + ('a: % 11f, b: % 11f, c: % 11f\n' % flt3(s, 24))
                res = res + ('d: % 11f, e: % 11f, f: % 11f\n' % flt3(s, 36))
                res = res + ('g: % 11f, h: % 11f, i: % 11f\n' % flt3(s, 48))
                x, y, z = flt3(s, 60)
                res = res + ('x: % 11f, y: % 11f, z: % 11f\n' % (x, y, z))
                res = res + ('norm = % 11f\n\n' % (sqrt(x * x + y * y + z * z)))
                
        return res

######################################################################    
class OUnkPathData:
    """Path to materials (editor leftover)"""

    fmt = "char"
    
    def __init__(self, file):
        n = read_word(file)
        self.data = file.read(n)

    def __str__(self):
        return 'path "' + self.data + '"\n'

######################################################################
class OObjData:
    """Object data"""

    fmt = "float, 10th(if any) = max elt in next chunk (DUH!)"
    
    def __init__(self, file):
        self.data = []; n = read_word(file)
        for i in range(n):
            self.data.append(read_float(file))

    def __str__(self):
        res = '%d floats\n' % len(self.data)
        for e in self.data:
            res = res + ("% 11f\n" % e)
        return res

######################################################################
class OTriXData:
    """Some Triangle data (not in multipart .msh?)"""

    fmt = "word ?, word ?, word ?"
    
    def __init__(self, file):
        self.data = []; n = read_word(file)
        for i in range(n):
            self.data.append((read_word(file), read_word(file),
                              read_word(file)))
        
    def __str__(self):
        res = '%d something\n' % len(self.data)
        elt1 = map(lambda e: e[0], self.data)
        elt2 = map(lambda e: e[1], self.data)
        elt3 = map(lambda e: e[2], self.data)
        min1 = min(elt1)
        min2 = min(elt2)
        min3 = min(elt3)
        max1 = max(elt1)
        max2 = max(elt2)
        max3 = max(elt3)
        for e in self.data:
            res = res + ('a: %d, b: %d, c: %d\n' % (e[0], e[1], e[2]))
        return res + ('%d, %d, %d\n' % (min1, min2, min3)) +\
               ('%d, %d, %d\n' % (max1, max2, max3))

######################################################################
class O98Gran:
    """Something with 98 granularity"""

    fmt = "char[98]?"
    
    def __init__(self, file):
        self.data = []; n = read_word(file)
        for i in range(n):
            self.data.append(file.read(98))
        
    def __str__(self):
        res = '%d something\n' % len(self.data)
        return res

######################################################################
class OSkelData:
    """Skeleton data (.amh only)"""

    fmt = """name[word len, char[len]], word branch,
    float x, y, z, char[14]?, word?"""
       
    def __init__(self, file):
        self.data = []; n = read_word(file)
        for i in range(n):
            len = read_word(file)
            name = file.read(len)
            nsomething = read_half(file)
            a, b, g = read_float(file), read_float(file), read_float(file)
            s = file.read(14)
            some = file.read(4)
            self.data.append((name, nsomething, (a, b, g), s, some))
            
    def __str__(self):
        res = '%d limbs\n' % len(self.data)
        for (name, nsomething, angles, s, some) in self.data:
            a, b, g = angles
            w = struct.unpack('<l', some)[0]
            f = struct.unpack('>f', some)[0]
            res = res +\
                  ('name: %s, branch: %d\n\ta: % 11f, b: % 11f, g: % 11f, ?: %08X(%d)\n' % \
                   (name, nsomething, a, b, g, w, w)) +\
                   '\tdata: ' + str_hex(s) + '\n'
        return res

