#
# $Id: alc_AbsClasses.py 455 2006-04-21 20:18:42Z AdamJohnso $
#
#    Copyright (C) 2005-2006  Alcugs pyprp Project Team
#    See the file AUTHORS for more info about the team
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#    Please see the file COPYING for the full license.
#    Please see the file DISCLAIMER for more details, before doing nothing.
#

try:
    import Blender
    try:
        from Blender import NMesh
    except Exception, detail:
        print detail
except ImportError:
    pass

import math, struct
from enum import Enum
from alcurugeom import *
from alchexdump import *
from alcurutypes import *
import alcconfig, alchexdump
from alc_Messages import *

class plBitmap(hsKeyedObject):                              #Type 0x03   
    def __init__(self,parent,name="unnamed",type=0x0003):
        hsKeyedObject.__init__(self,parent,name,type)
        #format
        self.version=2 #Byte
        self.bpp=0x20 #Byte (bits per pixel)
        self.cpb=0 # 0/1 Byte (colors per byte)
        self.flags=0 #U16 (0x01, 0x02, 0x42...)
        self.type=0x02 #Byte
        # type
        # 0x00 - RGBA
        # 0x01 - DXT
        # 0x02 - JPEG
        #if type==1
        self.texel_size=0 #Byte
        self.subtype=0
        # subtype
        # 0x00 - none
        # 0x01 - DXT1
        # 0x05 - DXT5
        self.uk1=0 #Byte
        self.uk2=0 #U16
        self.uk3=0 #float (seems)
        self.uk4=0 #Byte - 0 (type 0) or 1 (other types)

        # for internal handling
        self.isCubEvMapPart = 0 

    def read(self,buf,really=1):
        hsKeyedObject.read(self,buf,really)
        self.version = buf.ReadByte()
        self.bpp = buf.ReadByte()
        self.cpb = buf.ReadByte()
        assert(self.version==2)
        assert(self.bpp==0x20)
        self.flags = buf.Read16()
        self.type = buf.ReadByte()
        if not self.type in (0x00,0x01,0x02):
            raise RuntimeError, "Unknown Bitmap type %02X" % self.type
        if self.type==1:
            self.texel_size = buf.ReadByte()
        else:
            self.texel_size=0
        self.subtype = buf.ReadByte()
        if self.type==1 and not self.subtype in (0x01,0x05):
            raise RuntimeError, "Unknown Bitmap subtype %02X" % self.subtype
        elif self.type!=1 and self.subtype!=0:
            raise RuntimeError, "Unknown Bitmap subtype %02X,%02X" % \
                  (self.type,self.subtype)
        self.uk1 = buf.ReadByte()
        self.uk2 = buf.Read16()
        self.uk3 = buf.Read32()
        self.uk4 = buf.ReadByte()
        if self.type==0:
            assert(self.uk4==0 or self.uk4==1)
        if self.type==1:
            if self.subtype==1:
                assert(self.texel_size==8)
            else:
                assert(self.texel_size==16)


    def write(self,buf,really=1):
        hsKeyedObject.write(self,buf,really)
        if 1:
            self.uk1=0
            self.uk2=0
            self.uk3=0
            if self.type==0 or self.isCubEvMapPart == 1:
                self.uk4=0
            else:
                self.uk4=1
            if self.type==1:
                if self.subtype==1:
                    self.texel_size=8
                else:
                    self.texel_size=16
            if self.type==2:
                self.cpb=0
            else:
                self.cpb=1
            self.flags=0
        buf.WriteByte(self.version)
        buf.WriteByte(self.bpp)
        buf.WriteByte(self.cpb)
        buf.Write16(self.flags)
        buf.WriteByte(self.type)
        if self.type==1:
            buf.WriteByte(self.texel_size)
        buf.WriteByte(self.subtype)
        buf.WriteByte(self.uk1)
        buf.Write16(self.uk2)
        buf.Write32(self.uk3)
        buf.WriteByte(self.uk4)


    def dump(self):
        print "Bitmap Header"
        print "cpb: %i, flags: %04X, type: %i, subtype: %i" %\
              (self.cpb,self.flags,self.type,self.subtype)
        print "uk1: %02X, uk2: %04X, uk3: %08X, uk4: %02X" % (self.uk1,self.uk2,self.uk3,self.uk4)
        print "--"


class plSynchedObject(hsKeyedObject):                       #Type 0x28
    def __init__(self,parent,name="unnamed",type=0x28):
        hsKeyedObject.__init__(self,parent,name,type)
        self.Flags=0
        self.Count=0
        self.SDLLinks=[]
    

    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.Flags = buf.Read32()
        if not self.Flags in (0x00,0x04,0x10,0x20,0x28,0x38,0x80):
            raise RuntimeError, "plSynchedObject contains unknown Flag %04X" % self.Flags
        if (self.getVersion()==5 and self.Flags & 0x10) or (self.getVersion()==6 and not self.Flags & 0x04): #We need to document these flags
            self.Count = buf.Read16()
            for i in range(self.Count):
                #s = buf.ReadSafeString(self.getVersion())
                s = Ustr()
                s.setType(self.getVersion())
                s.read(buf)
                self.SDLLinks.append(s)
                if not str(s) in ("Physical","AGMaster","Responder","Clothing","Avatar","Layer","Sound","XRegion","MorphSequence","ParticleSystem"):
                    raise RuntimeError, "Unknown %s sdl link in sceneobject" % str(s)


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        if len(self.SDLLinks)!=0:
            self.Flags |= 0x10
        buf.Write32(self.Flags)
        if self.Flags & 0x10:
            buf.Write16(len(self.SDLLinks))
            for s in self.SDLLinks:
                # Commented out WriteSafeString; use Ustr.write instead
                #s.WriteSafeString(s, self.getVersion())
                s.setType(self.getVersion())
                s.write(buf,1)


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)

    def dump(self):
        hsKeyedObject.dump(self)
        print "Synchronized Object:"
        print "Flag %08X" % self.Flags
        print "SDL Links: ",
        for i in self.SDLLinks:
            print str(i),


class plObjInterface(plSynchedObject):                      #Type 0x10
    def __init__(self,parent,name="unnamed",type=0x10):
        plSynchedObject.__init__(self,parent,name,type)
        self.parentref=UruObjectRef(self.getVersion())
        self.BitFlags=hsBitVector()

    def read(self,buf):
        plSynchedObject.read(self,buf)
        self.parentref.read(buf)
        self.BitFlags.read(buf)


    def write(self,buf):
        plSynchedObject.write(self,buf)
        self.parentref.write(buf)
        self.BitFlags.write(buf)

    def changePageRaw(self,sid,did,stype,dtype):
        plSynchedObject.changePageRaw(self,sid,did,stype,dtype)
        self.parentref.changePageRaw(sid,did,stype,dtype)

    def dump(self):
        plSynchedObject.dump(self)
        print "Parent Object: %s" % self.parentref


class plModifier(plSynchedObject):                          #Type 0x1E
    def __init__(self,parent,name="unnamed",type=None):
        plSynchedObject.__init__(self,parent,name,type)


class plSingleModifier(plModifier):                    #Type 0x1F
    def __init__(self,parent,name="unnamed",type=None):
        plModifier.__init__(self,parent,name,type)
        self.bitVector = hsBitVector()


    def read(self,buf):
        plModifier.read(self,buf)
        self.bitVector.read(buf)
    
    
    def write(self,buf):
        plModifier.write(self,buf)
        self.bitVector.write(buf)


class plDetectorModifier(plSingleModifier):                 #Type 0x24
    def __init__(self,parent,name="unnamed",type=None):
        plSingleModifier.__init__(self,parent,name,type)
        #Format
        if (self.getVersion()==6):
            self.logic = hsTArray([0x2C],6)
        else:
            self.logic = hsTArray([0x2D,0xA6],5,True)
        self.null = UruObjectRef(self.getVersion())
        self.objref2 = UruObjectRef(self.getVersion())
    
    
    def read(self,buf):
        plSingleModifier.read(self,buf)
        self.logic.ReadVector(buf)
        self.null.read(buf)
        self.objref2.read(buf)
    
    
    def write(self,buf):
        plSingleModifier.write(self,buf)
        self.logic.update(self.Key)
        self.logic.WriteVector(buf)
        self.null.write(buf)
        self.objref2.write(buf)

    
    def dump(self):
        plSingleModifier.dump(self)
        print "Detector Modifier"
        print self.logic.size + " LogicModifer refs in hsTArray"
        print "ObjRef2: " + self.objref2.Key.name


    def changePageRaw(self,sid,did,stype,dtype):
        plSingleModifier.changePageRaw(self,sid,did,stype,dtype)
        self.logic.changePageRaw(sid,did,stype,dtype)
        self.null.changePageRaw(sid,did,stype,dtype)
        self.objref2.changePageRaw(sid,did,stype,dtype)


class plMultiModifier(plModifier):                          #Type 0x27
    def __init__(self,parent,name="unnamed",type=None):
        plModifier.__init__(self,parent,name,type)
        self.BitVector=hsBitVector()


    def read(self,buf):
        plModifier.read(self,buf)
        self.BitVector.read(buf)


    def write(self,buf):
        plModifier.write(self,buf)
        self.BitVector.write(buf)


class plCollisionDetector(plDetectorModifier):              #Type 0x2C
    def __init__(self,parent,name="unnamed",type=None):
        plDetectorModifier.__init__(self,parent,name,type)
        self.c70 = 0x00 # either 0 or 4


    def read(self,buf):
        plDetectorModifier.read(self,buf)
        self.c70 = buf.ReadByte()


    def write(self,buf):
        plDetectorModifier.write(self,buf)
        buf.WriteByte(self.c70)


class plConditionalObject(hsKeyedObject):                   #Type 0x2E
    def __init__(self,parent,name="unnamed",type=None):
        hsKeyedObject.__init__(self,parent,name,type)
        self.i10 = 0x00 #BYTE
        self.i14 = 0x00 #byte
    
    
    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.i10 = buf.ReadByte()
        self.i14 = buf.ReadByte()
    
    
    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.WriteByte(self.i10)
        buf.WriteByte(self.i14)
    
    
    def dump(self):
        print "Conditional Object"
        print "i10: " + self.i10
        print "i14: " + self.i14


class plLayerInterface(plSynchedObject):                    #Type 0x41 (Uru)
    def __init__(self,parent,name="unnamed",type=None):
        plSynchedObject.__init__(self,parent,name,type)
        self.Unknown = UruObjectRef()
    
    
    def read(self,buf):
        plSynchedObject.read(self,buf)
        if self.getVersion() == 5:
            self.Unknown.read(buf)
    
    
    def write(self,buf):
        plSynchedObject.write(self,buf)
        if self.getVersion() == 5:
            self.Unknown.write(buf)


class plLightInfo(plObjInterface):                          #Type 0x54 (Uru)
    def __init__(self,parent,name="unnamed",type=None):
        plObjInterface.__init__(self,parent,name,type)
        self.color1 = [] #FLOAT
        self.color2 = [] #FLOAT
        self.color3 = [] #FLOAT
        self.M120 = hsMatrix44()
        self.M164 = hsMatrix44()
        self.M230 = hsMatrix44()
        self.M274 = hsMatrix44()
        self.softvol = UruObjectRef() #plSoftVolume
        self.layerint = UruObjectRef() #plLayerInterface
        self.ref = UruObjectRef() #Dunno
        self.f2C4 = 0 #FLOAT
        self.f2C8 = 0 #FLOAT
        self.f2CC = 0 #FLOAT
        self.visregs = hsTArray() #plVisRegion[]
    
    
    def read(self,buf):
        plObjInterface.read(self,buf)
        for i in range(4):
            self.color1[i] = plLightInfo()
            self.color1[1].read(buf)
            self.color2[i] = plLightInfo()
            self.color2[i].read(buf)
            self.color3[i] = plLightInfo()
            self.color3[i].read(buf)
        self.M120.read(buf)
        self.M164.read(buf)
        self.M230.read(buf)
        self.M270.read(buf)
        self.layerint.read(buf)
        self.softvol.read(buf)
        self.ref.read(buf)
        if(self.BitFlags.Data[4]):
            self.f2C4 = buf.ReadFloat()
            self.f2C8 = buf.ReadFloat()
            self.f2CC = buf.ReadFloat()
        self.visregs.read(buf)

class plLogicModBase(plSingleModifier):                   #Type 0x4F
    def __init__(self,parent,name="unnamed",type=None):
        plSingleModifier.__init__(self,parent,name,type)
        self.MsgCount = 0x00000000
        self.Messages = [] # plMessages
        self.Notify = PrpMessage(0x02E8,self.getVersion())
        self.DWords = []
        self.t8C = 0x00

    def read(self,buf):
        plSingleModifier.read(self,buf)
        self.MsgCount = buf.Read32()
        assert(self.MsgCount == 0)
        localType = buf.Read16()
        assert(localType == 0x02E8) # plNotifyMsg type
        self.Notify.read(buf)
        DWCount = buf.Read32()
        for i in range(DWCount):
            dword = buf.Read32()
            self.DWords.append(dword)
        self.t8C = buf.ReadByte()

    def write(self,buf):
        plSingleModifier.write(self,buf)
        buf.Write32(self.MsgCount)
        buf.Write16(self.Notify.msgtype)
        self.Notify.update(self.Key)
        self.Notify.write(buf)
        buf.Write32(len(self.DWords))
        for i in self.DWords:
            buf.Write32(i)
        buf.WriteByte(self.t8C)


class plAGAnim(plSynchedObject):                #Type 0x6B
    def __init(self,parent,name="unnamed",type=None):
        plSynchedObject.__init__(self,parent,name,type)
        self.AnimName = 0
        self.StartTime = 0
        self.EndTime = 0
        self.AGApp = []
    
    def read(self,buf):
        plSynchedObject.read(self,buf)
        self.AnimName = buf.ReadSafeString()
        self.StartTime = buf.ReadFloat()
        self.StopTime = buf.ReadFloat()
        i = buf.Read32()
        for j in range(i):
            self.AGApp[j] = plAGApplicator()
            self.AGApp[j].read(buf)
    
    def write(self,buf):
        plSynchedObject.write(self,buf)
        buf.WriteSafeString(self.AnimName)
        buf.WriteFloat(self.StartTime)
        buf.WriteFloat(self.StopTime)
        buf.Write32(len(self.AGApp))
        for i in range(len(self.AGApp)):
            self.AGApp[i].write(buf)
    
    def dump(self):
        print "Animation: " + self.AnimName