#include "xclipmap.h"

XClipMap::XClipMap()
    : XAsset()
    , mName()
    , mIsInUse(false)
    , mPlaneCount(0)
    , mPlanes()
    , mNumStaticModels(0)
    , mStaticModelList()
    , mNumMaterials(0)
    , mMaterials()
    , mNumBrushSides(0)
    , mBrushsides()
    , mNumBrushEdges(0)
    , mBrushEdges()
    , mNumNodes(0)
    , mNodes()
    , mNumLeafs(0)
    , mLeafs()
    , mLeafBrushNodesCount(0)
    , mLeafBrushNodes()
    , mNumLeafBrushes(0)
    , mLeafBrushes()
    , mNumLeafSurfaces(0)
    , mLeafSurfaces()
    , mVertCount(0)
    , mVerts()
    , mTriCount(0)
    , mTriIndices()
    , mTriEdgeIsWalkable()
    , mBorderCount(0)
    , mBorders()
    , mPartitionCount(0)
    , mPartitions()
    , mAabbTreeCount(0)
    , mAabbTrees()
    , mNumSubModels(0)
    , mCModels()
    , mNumBrushes(0)
    , mBrushes()
    , mNumClusters(0)
    , mClusterBytes(0)
    , mVisibility()
    , mVised(0)
    , mMapEnts()
    , mBoxBrush()
    , mBoxModel()
    , mDynEntCounts(0)
    , mDynEntDefList(2)
    , mDynEntPoseList(2)
    , mDynEntClientList(2)
    , mDynEntCollList(2)
    , mChecksum(0)
{
    SetType(ASSET_TYPE_CLIPMAP);
    SetName("Clip Map");
}

void XClipMap::ParseData(XDataStream *aStream)
{
    if (GetPtr() == -1)
    {
        // name / header
        mName.ParsePtr(aStream, false);

        mIsInUse = aStream->ParseUInt32(QString("%1 is in use").arg(GetName()));
        mPlaneCount = aStream->ParseInt32 (QString("%1 plane count").arg(GetName()));
        qint32 planePtr = aStream->ParseInt32(QString("%1 plane ptr").arg(GetName()));

        // static models / materials / brushes
        mNumStaticModels = aStream->ParseUInt32(QString("%1 num static models").arg(GetName()));
        qint32 staticModelPtr = aStream->ParseInt32(QString("%1 static model ptr").arg(GetName()));

        mNumMaterials = aStream->ParseUInt32(QString("%1 num materials").arg(GetName()));
        qint32 materialsPtr = aStream->ParseInt32(QString("%1 materials ptr").arg(GetName()));

        mNumBrushSides = aStream->ParseUInt32(QString("%1 num brush sides").arg(GetName()));
        qint32 brushSidesPtr = aStream->ParseInt32(QString("%1 brush sides ptr").arg(GetName()));

        mNumBrushEdges = aStream->ParseUInt32(QString("%1 num brush edges").arg(GetName()));
        qint32 brushEdgesPtr = aStream->ParseInt32(QString("%1 brush edges ptr").arg(GetName()));

        mNumNodes = aStream->ParseUInt32(QString("%1 num nodes").arg(GetName()));
        qint32 nodesPtr = aStream->ParseInt32(QString("%1 nodes ptr").arg(GetName()));

        mNumLeafs = aStream->ParseUInt32(QString("%1 num leafs").arg(GetName()));
        qint32 leafsPtr = aStream->ParseInt32(QString("%1 leafs ptr").arg(GetName()));

        mLeafBrushNodesCount = aStream->ParseUInt32(QString("%1 leaf brush nodes count").arg(GetName()));
        qint32 leafsBrushNodesPtr= aStream->ParseInt32(QString("%1 leaf brush nodes ptr").arg(GetName()));

        mNumLeafBrushes = aStream->ParseUInt32(QString("%1 num leaf brushes").arg(GetName()));
        qint32 leafBrushesPtr = aStream->ParseInt32(QString("%1 leaf brushes ptr").arg(GetName()));

        mNumLeafSurfaces = aStream->ParseUInt32(QString("%1 num leaf surfaces").arg(GetName()));
        qint32 leafSurfacesPtr = aStream->ParseInt32(QString("%1 leaf surfaces ptr").arg(GetName()));

        mVertCount = aStream->ParseUInt32(QString("%1 vert count").arg(GetName()));
        qint32 vertPtr = aStream->ParseInt32(QString("%1 vert ptr").arg(GetName()));

        mTriCount = aStream->ParseInt32(QString("%1 tri count").arg(GetName()));
        qint32 triIndicesPtr = aStream->ParseInt32(QString("%1 tri indices ptr").arg(GetName()));
        qint32 triEdgeWalkablePtr= aStream->ParseInt32(QString("%1 tri edge walkable ptr").arg(GetName()));

        mBorderCount = aStream->ParseInt32(QString("%1 border count").arg(GetName()));
        qint32 bordersPtr = aStream->ParseInt32(QString("%1 borders ptr").arg(GetName()));

        mPartitionCount = aStream->ParseInt32(QString("%1 partition count").arg(GetName()));
        qint32 partitionsPtr = aStream->ParseInt32(QString("%1 partitions ptr").arg(GetName()));

        mAabbTreeCount = aStream->ParseInt32(QString("%1 aabb tree count").arg(GetName()));
        qint32 aabbTreesPtr = aStream->ParseInt32(QString("%1 aabb trees ptr").arg(GetName()));

        mNumSubModels = aStream->ParseUInt32(QString("%1 num sub models").arg(GetName()));
        qint32 cModelsPtr = aStream->ParseInt32(QString("%1 c models ptr").arg(GetName()));

        mNumBrushes = aStream->ParseUInt32(QString("%1 num brushes").arg(GetName()));

        // skip padding
        aStream->skipRawData(2);

        // visibility + ents
        qint32 brushesPtr = aStream->ParseInt32(QString("%1 brushes ptr").arg(GetName()));
        mNumClusters = aStream->ParseInt32(QString("%1 num clusters").arg(GetName()));
        mClusterBytes = aStream->ParseInt32(QString("%1 cluster bytes").arg(GetName()));
        qint32 visibilityPtr = aStream->ParseInt32(QString("%1 visibility ptr").arg(GetName()));
        mVised = aStream->ParseInt32(QString("%1 vised").arg(GetName()));
        qint32 mapEntsPtr = aStream->ParseInt32(QString("%1 map ents ptr").arg(GetName()));

        mMapEnts.ParsePtr(aStream, false);
        mBoxBrush.ParsePtr(aStream, false);
        mBoxModel.ParseData(aStream);

        // dynEnt counts
        quint16 dynEntCount;
        dynEntCount = aStream->ParseUInt16(QString("%1 dyn ent count [0]").arg(GetName()));
        mDynEntCounts.append(dynEntCount);
        dynEntCount = aStream->ParseUInt16(QString("%1 dyn ent count [1]").arg(GetName()));
        mDynEntCounts.append(dynEntCount);

        // dynEnt lists (ParsePtr once each)
        mDynEntDefList[0].ParsePtr(aStream, false);
        mDynEntDefList[1].ParsePtr(aStream, false);

        mDynEntPoseList[0].ParsePtr(aStream, false);
        mDynEntPoseList[1].ParsePtr(aStream, false);

        mDynEntClientList[0].ParsePtr(aStream, false);
        mDynEntClientList[1].ParsePtr(aStream, false);

        mDynEntCollList[0].ParsePtr(aStream, false);
        mDynEntCollList[1].ParsePtr(aStream, false);

        mChecksum = aStream->ParseUInt32(QString("%1 checksum").arg(GetName()));

        // =====================
        // Sectioned data blocks
        // =====================
        if (planePtr) {
            for (int i = 0; i < mPlaneCount; i++) {
                XCPlane newCPlane;
                newCPlane.ParseData(aStream);
                mPlanes.append(newCPlane);
            }
        }

        if (staticModelPtr) {
            for (quint32 i = 0; i < mNumStaticModels; i++) {
                XCStaticModel newModel;
                newModel.ParseData(aStream);
                mStaticModelList.append(newModel);
            }
        }

        if (materialsPtr) {
            for (quint32 i = 0; i < mNumMaterials; i++) {
                XDMaterial newMat;
                newMat.ParseData(aStream);
                mMaterials.append(newMat);
            }
        }

        if (brushSidesPtr) {
            for (quint32 i = 0; i < mNumBrushSides; i++) {
                XCBrushSide newSide;
                newSide.ParseData(aStream);
                mBrushsides.append(newSide);
            }
        }

        if (brushEdgesPtr) {
            for (quint32 i = 0; i < mNumBrushEdges; i++) {
                quint8 edge = aStream->ParseUInt8(QString("%1 edge %2").arg(GetName()).arg(i));
                mBrushEdges.append(edge);
            }
        }

        if (nodesPtr) {
            for (quint32 i = 0; i < mNumNodes; i++) {
                XCNode newNode;
                newNode.ParseData(aStream);
                mNodes.append(newNode);
            }
        }

        if (leafsPtr) {
            for (quint32 i = 0; i < mNumLeafs; i++) {
                XCLeaf newLeaf;
                newLeaf.ParseData(aStream);
                mLeafs.append(newLeaf);
            }
        }

        if (leafBrushesPtr) {
            for (quint32 i = 0; i < mNumLeafBrushes; i++) {
                quint32 brush = aStream->ParseUInt32(QString("%1 brush %2").arg(GetName()).arg(i));
                mLeafBrushes.append(brush);
            }
        }

        if (leafsBrushNodesPtr) {
            for (quint32 i = 0; i < mLeafBrushNodesCount; i++) {
                XCLeafBrushNode newNode;
                newNode.ParseData(aStream);
                mLeafBrushNodes.append(newNode);
            }
        }

        if (leafSurfacesPtr) {
            for (quint32 i = 0; i < mNumLeafSurfaces; i++) {
                quint32 surf = aStream->ParseUInt32(QString("%1 surf %2").arg(GetName()).arg(i));
                mLeafSurfaces.append(surf);
            }
        }

        if (vertPtr) {
            for (quint32 i = 0; i < mVertCount; i++) {
                for (int j = 0; j < 3; j++) {
                    QVector3D v;
                    v[j] = aStream->ParseSingle(QString("%1 vert (%2, %3)").arg(GetName()).arg(i).arg(j));
                    mVerts.append(v);
                }
            }
        }

        if (triIndicesPtr) {
            for (int i = 0; i < mTriCount; i++) {
                quint32 tri = aStream->ParseUInt32(QString("%1 tri %2").arg(GetName()).arg(i));
                mTriIndices.append(tri);
            }
        }

        if (triEdgeWalkablePtr) {
            aStream->readRawData(mTriEdgeIsWalkable.data(),
                                 ((3 * mTriCount + 31) >> 3) & 0xFFFFFFFC);
        }

        if (bordersPtr) {
            for (int i = 0; i < mBorderCount; i++) {
                XCollisionBorder b;
                b.ParseData(aStream);
                mBorders.append(b);
            }
        }

        if (partitionsPtr) {
            for (int i = 0; i < mPartitionCount; i++) {
                XCollisionPartition p;
                p.ParseData(aStream);
                mPartitions.append(p);
            }
        }

        if (aabbTreesPtr) {
            for (int i = 0; i < mAabbTreeCount; i++) {
                XCollisionAabbTree t;
                t.ParseData(aStream);
                mAabbTrees.append(t);
            }
        }

        if (cModelsPtr) {
            for (quint32 i = 0; i < mNumSubModels; i++) {
                XCModel m;
                m.ParseData(aStream);
                mCModels.append(m);
            }
        }

        if (brushesPtr) {
            for (quint32 i = 0; i < mNumBrushes; i++) {
                XCBrush b;
                b.ParseData(aStream);
                mBrushes.append(b);
            }
        }

        if (visibilityPtr) {
            aStream->readRawData(mVisibility.data(), mClusterBytes * mNumClusters);
        }

        if (mapEntsPtr) {
            mMapEnts.ParseData(aStream);
        }

        // box brush / dynEnt blocks
        mBoxBrush.ParseData(aStream);

        mDynEntDefList[0].ParseData(aStream);
        mDynEntDefList[1].ParseData(aStream);

        mDynEntPoseList[0].ParseData(aStream);
        mDynEntPoseList[1].ParseData(aStream);

        mDynEntClientList[0].ParseData(aStream);
        mDynEntClientList[1].ParseData(aStream);

        mDynEntCollList[0].ParseData(aStream);
        mDynEntCollList[1].ParseData(aStream);
    }
}


void XClipMap::Clear()
{

}
