from inc_noesis import *
import noesis
import rapi
import os

def registerNoesisTypes():
    '''Register the plugin'''
    
    handle = noesis.register("Zu Online", ".ltb")
    noesis.setHandlerTypeCheck(handle, noepyCheckType)
    noesis.setHandlerLoadModel(handle, noepyLoadModel) #see also noepyLoadModelRPG
    return 1

def noepyCheckType(data):
    '''Verify that the format is supported by this plugin.'''
    
    if len(data) < 9:
        return 0
    try:
        bs = NoeBitStream(data)
        ver1 = bs.readShort()
        ver2 = bs.readShort()
        if ver1 != 1 or ver2 != 9:
            return 0
        return 1
    except:
        return 0

def noepyLoadModel(data, mdlList):
    '''Load the model'''
    
    ctx = rapi.rpgCreateContext()
    parser = ZuOnline_LTB(data)
    parser.parse_file()
    mdl = rapi.rpgConstructModel()
    mdlList.append(mdl)
    mdl.setModelMaterials(NoeModelMaterials(parser.texList, parser.matList))
    mdlList.append(mdl)
    return 1

class ZuOnline_LTB(object):
    
    def __init__(self, data):    
        self.inFile = NoeBitStream(data)
        self.animList = []
        self.texList = []
        self.matList = []
        self.boneList = []
        self.dirpath = rapi.getDirForFilePath(rapi.getInputName())
        self.texpath = self.dirpath + "texture\\"
        
    def basename(self):
        '''Returns the filename without extension'''
        
        filename = rapi.getLocalFileName(rapi.getInputName())
        basename, ext = os.path.splitext(filename)
        return basename    
        
    def read_name(self):
        
        string = self.inFile.readBytes(self.inFile.readUShort())
        try:
            return noeStrFromBytes(string)
        except:
            return string
            
    def parse_vertices(self, numVerts, meshType):
        
        print (self.inFile.tell())
        if meshType == 1:
            vertBuff = self.inFile.readBytes(numVerts * 32)
            rapi.rpgBindPositionBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 32, 0)
            rapi.rpgBindNormalBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 32, 12)
            rapi.rpgBindUV1BufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 32, 24)
        elif meshType == 2:
            vertBuff = self.inFile.readBytes(numVerts * 36)
            rapi.rpgBindPositionBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 36, 0)
            rapi.rpgBindNormalBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 36, 16)
            rapi.rpgBindUV1BufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 36, 28)
        elif meshType == 3:
            vertBuff = self.inFile.readBytes(numVerts * 40)
            rapi.rpgBindPositionBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 40, 0)
            rapi.rpgBindNormalBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 40, 20)
            rapi.rpgBindUV1BufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 40, 32)
        elif meshType == 4:
            vertBuff = self.inFile.readBytes(numVerts * 44)
            rapi.rpgBindPositionBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 44, 0)
            rapi.rpgBindNormalBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 44, 24)
            rapi.rpgBindUV1BufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 44, 36)
        else:
            print("unknown meshType: %d" %meshType)        

    def parse_faces(self, numIdx):
        
        return self.inFile.readBytes(numIdx * 2)
    
    def parse_unk(self):
        
        count = self.inFile.readUInt()
        self.inFile.seek(count*12, 1)
        
    def create_material(self, matNum):
        
        matName = "material[%d]" %matNum
        if matNum == 1:
            texName = self.texpath + self.basename() + ".dtx"
        elif matNum == 2:
            texName = self.texpath + self.basename() + "_a.dtx" 
        elif matNum == 3:
            texName = self.texpath + self.basename() + "_b.dtx"
        elif matNum == 4:
            texName = self.texpath + self.basename() + "_c.dtx"
        elif matNum == 5:
            texName = self.texpath + self.basename() + "_a.dtx"
        elif matNum == 6:
            texName = self.texpath + self.basename() + "_a.dtx"
        else:
            print(matNum)
            texName = ""
        
        material = NoeMaterial(matName, texName)
        self.matList.append(material)
        return matName
    
    def parse_submesh(self, numSubmesh):
        
        print (self.inFile.tell())
        for i in range(numSubmesh):
            self.inFile.readUInt()
            matNum = self.inFile.readUInt()
            self.inFile.read('4L')
            self.inFile.readByte()
            unk1 = self.inFile.readUInt()
            sectionSize = self.inFile.readUInt()
            
            #sectionSize could be 0
            if sectionSize:
                start = self.inFile.tell()
                numVerts = self.inFile.readUInt()
                numIdx = self.inFile.readUInt() * 3
                meshType = self.inFile.readUInt()
                self.inFile.read('5L')
       
                if unk1 == 4:
                    self.inFile.readUInt()
                elif unk1 == 5:
                    self.inFile.readUShort()
                
                self.parse_vertices(numVerts, meshType)
                idxBuff = self.parse_faces(numIdx)
                
                #just seeking past unknowns rather than parse the unknown
                curr = self.inFile.tell() - start
                remain = sectionSize - curr
                self.inFile.seek(remain, 1)
    
                unk2 = self.inFile.readByte()
                self.inFile.seek(unk2, 1)
                
                
                matName = self.create_material(matNum)
                #rapi.rpgSetMaterial(matName)
                #rapi.rpgCommitTriangles(idxBuff, noesis.RPGEODATA_USHORT, numIdx, noesis.RPGEO_TRIANGLE, 1)
    
    def parse_mesh(self, numMesh):
        
        for i in range(numMesh):
            meshName = self.read_name()
            numSubmesh = self.inFile.readUInt()
            for j in range(numSubmesh):
                self.inFile.readFloat()
            self.inFile.read('2L')
            self.parse_submesh(numSubmesh)
            
    def parse_file(self):
        
        self.inFile.read('2H')
        self.inFile.read('4L')
        version = self.inFile.readUInt()
        self.inFile.read('2L')
        numBones = self.inFile.readUInt()
        self.inFile.read('10L')
        self.inFile.read('2H') #large number
        self.inFile.readUInt()
        self.read_name()
        self.inFile.readFloat()
        self.inFile.readUInt()
        numMesh = self.inFile.readUInt()
        self.parse_mesh(numMesh)