#include "xgfxworld.h"
#include "xstring.h"

XGfxWorld::XGfxWorld()
    : XAsset()
    , mName()
    , mBaseName()
    , mPlaneCount(0)
    , mNodeCount(0)
    , mIndexCount(0)
    , mIndices(0)
    , mIndexBuffer()
    , mSurfaceCount(0)
    , mStreamInfo()
    , mSkySurfCount(0)
    , mSkyStartSurfs()
    , mSkyImage()
    , mSkySamplerState(0)
    , mVertexCount(0)
    , mVertexData()
    , mVertexLayerDataSize(0)
    , mVertexLayerData()
    , mSunParse()
    , mSunLight()
    , mSunColorFromBsp()
    , mSunPrimaryLightIndex(0)
    , mPrimaryLightCount(0)
    , mCullGroupCount(0)
    , mReflectionProbeCount(0)
    , mReflectionProbes()
    , mReflectionProbeTextures()
    , mDpvsPlanes()
    , mCellBitsCount(0)
    , mCells()
    , mLightmapCount(0)
    , mLightmaps()
    , mLightGrid()
    , mLightmapPrimaryTextures()
    , mLightmapSecondaryTextures()
    , mModelCount(0)
    , mModels()
    , mMins()
    , mMaxs()
    , mChecksum(0)
    , mMaterialMemoryCount(0)
    , mMaterialMemory()
    , mSun()
    , mOutdoorLookupMatrix()
    , mOutdoorImage()
    , mCellCasterBits()
    , mSceneDynModel()
    , mSceneDynBrush()
    , mPrimaryLightEntityShadowVis()
    , mPrimaryLightDynEntShadowVis()
    , mNonSunPrimaryLightForModelDynEnt()
    , mShadowGeom()
    , mLightRegion()
    , mDpvs()
    , mDpvsDyn()
{
    SetType(ASSET_TYPE_GFXWORLD);
    SetName("GFX World");
}

XGfxWorld::~XGfxWorld()
{

}

void XGfxWorld::ParseData(XDataStream *aStream) {
    if (GetPtr() == -1) {
        mName.ParsePtr(aStream, false);
        mBaseName.ParsePtr(aStream, false);

        qint32 indicesPtr;
        mPlaneCount = aStream->ParseInt32(QString("%1 plane count").arg(GetName()));
        mNodeCount = aStream->ParseInt32(QString("%1 node count").arg(GetName()));
        mIndexCount = aStream->ParseInt32(QString("%1 index count").arg(GetName()));
        indicesPtr = aStream->ParseInt32(QString("%1 indices ptr").arg(GetName()));

        mIndexBuffer.ParseData(aStream);

        mSurfaceCount = aStream->ParseInt32(QString("%1 surface count").arg(GetName()));

        mStreamInfo.SetPtr(-1);
        mStreamInfo.ParseData(aStream);

        qint32 skyStartSurfPtr, skyImagePtr;
        mSkySurfCount = aStream->ParseInt32(QString("%1 sky surf count").arg(GetName()));
        skyStartSurfPtr = aStream->ParseInt32(QString("%1 sky start surf ptr").arg(GetName()));
        skyImagePtr = aStream->ParseInt32(QString("%1 sky image ptr").arg(GetName()));
        mSkySamplerState = aStream->ParseUInt8(QString("%1 sky sampler state").arg(GetName()));

        aStream->skipRawData(3);

        mVertexCount = aStream->ParseUInt32(QString("%1 vertex count").arg(GetName()));

        mVertexData.ParseData(aStream);

        mVertexLayerDataSize = aStream->ParseUInt32(QString("%1 vertex layer data size").arg(GetName()));

        mVertexLayerData.ParseData(aStream);
        mSunParse.ParseData(aStream);

        mSunLight.ParsePtr(aStream, false);

        float r = aStream->ParseSingle(QString("%1 sun color r").arg(GetName()));
        float g = aStream->ParseSingle(QString("%1 sun color g").arg(GetName()));
        float b = aStream->ParseSingle(QString("%1 sun color b").arg(GetName()));
        mSunColorFromBsp = QColor::fromRgbF(r, g, b);

        qint32 reflectionProbesPtr, reflectionProbeTexturesPtr;
        mSunPrimaryLightIndex = aStream->ParseUInt32(QString("%1 sun primary light index").arg(GetName()));
        mPrimaryLightCount = aStream->ParseUInt32(QString("%1 primary light count").arg(GetName()));
        mCullGroupCount = aStream->ParseInt32(QString("%1 cull group count").arg(GetName()));
        mReflectionProbeCount = aStream->ParseUInt32(QString("%1 reflection probe count").arg(GetName()));
        reflectionProbesPtr = aStream->ParseInt32(QString("%1 reflection probes ptr").arg(GetName()));
        reflectionProbeTexturesPtr = aStream->ParseInt32(QString("%1 reflection probe textures ptr").arg(GetName()));

        mDpvsPlanes.ParseData(aStream);

        qint32 cellsPtr, lightmapsPtr;
        mCellBitsCount = aStream->ParseInt32(QString("%1 cell bits count").arg(GetName()));
        cellsPtr = aStream->ParseInt32(QString("%1 cells ptr").arg(GetName()));
        mLightmapCount = aStream->ParseInt32(QString("%1 lightmap count").arg(GetName()));
        lightmapsPtr = aStream->ParseInt32(QString("%1 lightmaps ptr").arg(GetName()));

        mLightGrid.ParseData(aStream);

        qint32 lightMapsPrimaryPtr, lightmapSecondaryPtr, modelsPtr, materialMemoryPtr;
        lightMapsPrimaryPtr = aStream->ParseInt32(QString("%1 lightmaps primary ptr").arg(GetName()));
        lightmapSecondaryPtr = aStream->ParseInt32(QString("%1 lightmaps secondary ptr").arg(GetName()));
        mModelCount = aStream->ParseInt32(QString("%1 model count").arg(GetName()));
        modelsPtr = aStream->ParseInt32(QString("%1 models ptr").arg(GetName()));

        mMins.setX(aStream->ParseSingle(QString("%1 mins x").arg(GetName())));
        mMins.setY(aStream->ParseSingle(QString("%1 mins y").arg(GetName())));
        mMins.setZ(aStream->ParseSingle(QString("%1 mins z").arg(GetName())));

        mMaxs.setX(aStream->ParseSingle(QString("%1 maxs x").arg(GetName())));
        mMaxs.setY(aStream->ParseSingle(QString("%1 maxs y").arg(GetName())));
        mMaxs.setZ(aStream->ParseSingle(QString("%1 maxs z").arg(GetName())));

        mChecksum = aStream->ParseUInt32(QString("%1 checksum").arg(GetName()));
        mMaterialMemoryCount = aStream->ParseInt32(QString("%1 material memory count").arg(GetName()));
        materialMemoryPtr = aStream->ParseInt32(QString("%1 material memory ptr").arg(GetName()));

        mSun.ParseData(aStream);

        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                mOutdoorLookupMatrix[i][j] = aStream->ParseSingle(QString("%1 outdoor lookup matrix[%2][%3]").arg(GetName()).arg(i).arg(j));
            }
        }

        qint32 outdoorImagePtr, cellCasterBitsPtr, sceneDynModelPtr, sceneDynBrushPtr,
            primaryLightEntPtr, primaryLightDynPtr, nonSunPrimaryPtr, shadowGeomPtr, lightRegionPtr;
        outdoorImagePtr = aStream->ParseInt32(QString("%1 outdoor image ptr").arg(GetName()));
        cellCasterBitsPtr = aStream->ParseInt32(QString("%1 cell caster bits ptr").arg(GetName()));
        sceneDynModelPtr = aStream->ParseInt32(QString("%1 scene dyn model ptr").arg(GetName()));
        sceneDynBrushPtr = aStream->ParseInt32(QString("%1 scene dyn brush ptr").arg(GetName()));
        primaryLightEntPtr = aStream->ParseInt32(QString("%1 primary light entity shadow vis ptr").arg(GetName()));
        primaryLightDynPtr = aStream->ParseInt32(QString("%1 primary light dyn ent shadow vis ptr").arg(GetName()));
        nonSunPrimaryPtr = aStream->ParseInt32(QString("%1 non sun primary light dyn ent ptr").arg(GetName()));
        shadowGeomPtr = aStream->ParseInt32(QString("%1 shadow geom ptr").arg(GetName()));
        lightRegionPtr = aStream->ParseInt32(QString("%1 light region ptr").arg(GetName()));

        mDpvs.ParseData(aStream);
        mDpvsDyn.ParseData(aStream);

        mName.ParseData(aStream);
        mBaseName.ParseData(aStream);

        if (indicesPtr) {
            aStream->readRawData(mIndices.data(), 2 * mIndexCount);
        }

        if (skyStartSurfPtr) {
            for (int i = 0; i < mSkySurfCount; i++) {
                qint32 newSurface = aStream->ParseInt32(QString("%1 sky start surf %2").arg(GetName()).arg(i));
                mSkyStartSurfs.append(newSurface);
            }
        }

        mSkyImage.ParseData(aStream);
        mSunLight.ParseData(aStream);

        if (reflectionProbesPtr) {
            for (quint32 i = 0; i < mReflectionProbeCount; i++) {
                XGfxReflectionProbe newProbe;
                newProbe.ParseData(aStream);
                mReflectionProbes.append(newProbe);
            }
        }

        if (reflectionProbeTexturesPtr) {
            for (quint32 i = 0; i < mReflectionProbeCount; i++) {
                XGfxTexture newProbeTexture;
                newProbeTexture.ParseData(aStream);
                mReflectionProbeTextures.append(newProbeTexture);
            }
        }

        mDpvsPlanes.ParseData(aStream);

        if (cellsPtr) {
            for (int i = 0; i < mDpvsPlanes.GetCellCount(); i++) {
                XGfxCell newCell;
                newCell.ParseData(aStream);
                mCells.append(newCell);
            }
        }

        if (lightmapsPtr) {
            for (int i = 0; i < mLightmapCount; i++) {
                XGfxLightmapArray lightMapArray;
                lightMapArray.ParseData(aStream);
                mLightmaps.append(lightMapArray);
            }
        }

        mLightGrid.ParseData(aStream);

        if (lightMapsPrimaryPtr) {
            for (int i = 0; i < mLightmapCount; i++) {
                XGfxTexture primaryTexture;
                primaryTexture.ParseData(aStream);
                mLightmapPrimaryTextures.append(primaryTexture);
            }
        }

        if (lightmapSecondaryPtr) {
            for (int i = 0; i < mLightmapCount; i++) {
                XGfxTexture secondaryTexture;
                secondaryTexture.ParseData(aStream);
                mLightmapSecondaryTextures.append(secondaryTexture);
            }
        }

        if (modelsPtr) {
            for (int i = 0; i < mModelCount; i++) {
                XGfxBrushModel newModel;
                newModel.ParseData(aStream);
                mModels.append(newModel);
            }
        }

        if (materialMemoryPtr) {
            for (int i = 0; i < mMaterialMemoryCount; i++) {
                XMaterialMemory newMaterialMemory;
                newMaterialMemory.ParseData(aStream);
                mMaterialMemory.append(newMaterialMemory);
            }
        }

        mSun.ParseData(aStream);
        mOutdoorImage.ParseData(aStream);

        if (cellCasterBitsPtr) {
            for (int i = 0; i < ((mDpvsPlanes.GetCellCount() + 31) >> 5) * mDpvsPlanes.GetCellCount(); i++) {
                quint32 casterBit = aStream->ParseUInt32(QString("%1 cell caster bit %2").arg(GetName()).arg(i));
                mCellCasterBits.append(casterBit);
            }
        }

        if (sceneDynModelPtr) {
            for (quint32 i = 0; i < mDpvsDyn.GetClientCount(1); i++) {
                XGfxSceneDynModel dynModel;
                dynModel.ParseData(aStream);
                mSceneDynModel.append(dynModel);
            }
        }

        if (sceneDynBrushPtr) {
            for (quint32 i = 0; i < mDpvsDyn.GetClientCount(1); i++) {
                XGfxSceneDynBrush dynBrush;
                dynBrush.ParseData(aStream);
                mSceneDynBrush.append(dynBrush);
            }
        }
    }
    // TODO: Finish this... Double ugh
}

void XGfxWorld::Clear()
{

}
