'''Noesis import plugin. Written by Tsukihime'''

from inc_noesis import *
import noesis
import rapi
import os

MODE = 1

def registerNoesisTypes():
    '''Register the plugin. Just change the Game name and extension.'''
    
    handle = noesis.register("Rusty Hearts", ".mgm")
    noesis.setHandlerTypeCheck(handle, noepyCheckType)
    noesis.setHandlerLoadModel(handle, noepyLoadModel)
    return 1

def noepyCheckType(data):
    '''Verify that the format is supported by this plugin. Default yes'''
    
    return 1

def load_all_models(mdlList):
    '''Load all models'''

    #carry over from previous models
    matList = []
    texList = []

    dirPath = rapi.getDirForFilePath(rapi.getInputName())
    fileList = [file for file in os.listdir(dirPath) if file.lower().endswith(".mgm")]
    for filename in fileList:
        f = open(dirPath + filename, 'rb')
        data2 = f.read()
        parser = SanaeParser(data2)
        parser.parse_file(filename)
        matList.extend(parser.matList)
        texList.extend(parser.texList)
        mdl = rapi.rpgConstructModel()
    mdl.setModelMaterials(NoeModelMaterials(texList, matList))
    mdlList.append(mdl)    
    
def load_single_model(data, mdlList):
    '''Loads a single model. For testing purposes'''
    
    inputName = rapi.getLocalFileName(rapi.getInputName())
    filename, ext = os.path.splitext(inputName)
    parser = SanaeParser(data)
    parser.parse_file(filename)
    mdl = rapi.rpgConstructModel()
    mdl.setModelMaterials(NoeModelMaterials(parser.texList, parser.matList))
    mdlList.append(mdl)       

def noepyLoadModel(data, mdlList):
    '''Load the model'''
    
    ctx = rapi.rpgCreateContext()
    if MODE == 1:
        load_all_models(mdlList)
    else:
        load_single_model(data, mdlList)
    return 1

class SanaeParser(object):
    
    def __init__(self, data):    
        '''Initialize some data. Refer to Sanae.py to see what is already
        initialized'''
        
        self.inFile = NoeBitStream(data)
        self.animList = []
        self.texList = []
        self.matList = []
        self.boneList = []
        
    def read_name(self, n):
        
        string = bytes()
        for i in range(n):
            string += self.inFile.readBytes(1)
            self.inFile.readBytes(1)
        return noeStrFromBytes(string)
    
    def read_ustring(self):
        
        string = bytes()
        char = self.inFile.readBytes(1)
        while char != b'\x00':
            string += char
            self.inFile.readBytes(1)
            char = self.inFile.readBytes(1)
        return noeStrFromBytes(string)
            
    def parse_vertices(self, numVerts):
        
        vertBuff = self.inFile.readBytes(32*numVerts)
        rapi.rpgBindPositionBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 32, 0)
        rapi.rpgBindNormalBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 32, 12)
        rapi.rpgBindUV1BufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 32, 24)
    
    def parse_faces(self, numIdx):
    
        return self.inFile.readBytes(numIdx*2)
        
    def parse_skinned_mesh(self):
        
        len1, len2, unk1, unk2 = self.inFile.read('4L')
        meshName = self.read_name(len1)
        name = self.read_name(len2)
        
        matNum = self.inFile.readUInt() - 1
        matName = self.read_name(self.inFile.readUInt())
        numVerts = self.inFile.readUInt()
        numIdx = self.inFile.readUInt() * 3
        self.inFile.seek(0xF, 1)
        meshType = self.inFile.readUInt()
        
        self.parse_vertices(numVerts)
        idxBuff = self.parse_faces(numIdx)
        try:
            matName = self.matList[matNum].name
            rapi.rpgSetMaterial(matName)
        except:
            pass
        rapi.rpgSetOption(noesis.RPGOPT_TRIWINDBACKWARD, 1)
        rapi.rpgCommitTriangles(idxBuff, noesis.RPGEODATA_USHORT, numIdx, noesis.RPGEO_TRIANGLE, 1)
    
    def parse_static_mesh(self):
        
        len1, unk1, unk2, unk3 = self.inFile.read('4L')
        name1 = self.read_name(len1)
        numMesh = self.inFile.readUInt()
        
        for i in range(numMesh):
            len2 = self.inFile.readUInt()
            name2 = self.read_name(len2)
            numVerts = self.inFile.readUInt()
            numIdx = self.inFile.readUInt() * 3
            matNum = self.inFile.readUInt()
            self.inFile.seek(51, 1)
            self.parse_vertices(numVerts)
            idxBuff = self.parse_faces(numIdx)
            
            matName = self.matList[matNum].name
            rapi.rpgSetMaterial(matName)
            rapi.rpgSetOption(noesis.RPGOPT_TRIWINDBACKWARD, 1)
            rapi.rpgCommitTriangles(idxBuff, noesis.RPGEODATA_USHORT, numIdx, noesis.RPGEO_TRIANGLE, 1)
            
    def parse_mat_property(self, numProps):
        
        for i in range(numProps):
            #propName = self.inFile.readString()
            #self.inFile.readString()
            #self.inFile.seek(36, 1)
            #print(propName)
            self.inFile.seek(52, 1)
    
    def parse_materials(self, filename):
        
        dirPath = rapi.getDirForFilePath(rapi.getInputName())
        unk, numMat = self.inFile.read('2L')
        for i in range(numMat):
            unk1, len1, len2, = self.inFile.read('3L')
            name1 = self.read_name(len1)
            matName = self.read_name(len2)
            matName = "%s[%d]" %(filename, i)
            
            self.inFile.seek(5, 1)
            numProps, unk, unk = self.inFile.read('3L')
            self.parse_mat_property(numProps)
            self.inFile.readString()
            self.inFile.seek(21, 1)
            
            self.inFile.seek(4, 1) #skip curdir
            texName = self.read_ustring()
            texPath = dirPath + texName
            material = NoeMaterial(matName, texPath)
            self.matList.append(material)
        
    def parse_file(self, filename):
        '''Main parser method'''
        
        idstring = self.inFile.readBytes(5)
        count1, count2 = self.inFile.read('2L')
        
        offsets = self.inFile.read('%dL' %count2)
        sizes = self.inFile.read('%dL' %count2)
        types = self.inFile.read('%dL' %count2)
        
        for i in range(count2):
            offset = offsets[i]
            self.inFile.seek(offset)
            type = types[i]
            
            if type == 1:
                self.parse_materials(filename)
            elif type == 5:
                self.parse_static_mesh()
            elif type == 6:
                self.parse_skinned_mesh()