/**********************************************************************
 *
 *    FILE:            Geometry.cpp
 *
 *    DESCRIPTION:    Read/Write osg::Geometry in binary format to disk.
 *
 *    CREATED BY:        Auto generated by iveGenerated
 *                    and later modified by Rune Schmidt Jensen.
 *
 *    HISTORY:        Created 18.3.2003
 *
 *    Copyright 2003 VR-C
 **********************************************************************/

#include "Exception.h"
#include "Geometry.h"
#include "Drawable.h"
#include "DrawArrays.h"
#include "DrawArrayLengths.h"
#include "DrawElementsUByte.h"
#include "DrawElementsUShort.h"
#include "DrawElementsUInt.h"

using namespace ive;

void Geometry::write(DataOutputStream* out){
    // Write Geometry's identification.
    out->writeInt(IVEGEOMETRY);

    // If the osg class is inherited by any other class we should also write this to file.
    osg::Drawable*  drawable = dynamic_cast<osg::Drawable*>(this);
    if(drawable){
        ((ive::Drawable*)(drawable))->write(out);
    }
    else
        out_THROW_EXCEPTION("Geometry::write(): Could not cast this osg::Geometry to an osg::Drawable.");


    // Write Geometry's properties.

    // Write primitiveset list.
    int size = getNumPrimitiveSets();
    out->writeInt(size);
    for(int i=0;i<size;i++){
        if(dynamic_cast<osg::DrawArrays*>(getPrimitiveSet(i)))
            ((ive::DrawArrays*)(getPrimitiveSet(i)))->write(out);
        else if(dynamic_cast<osg::DrawArrayLengths*>(getPrimitiveSet(i)))
            ((ive::DrawArrayLengths*)(getPrimitiveSet(i)))->write(out);
        else if(dynamic_cast<osg::DrawElementsUByte*>(getPrimitiveSet(i)))
            ((ive::DrawElementsUByte*)(getPrimitiveSet(i)))->write(out);
        else if(dynamic_cast<osg::DrawElementsUShort*>(getPrimitiveSet(i)))
            ((ive::DrawElementsUShort*)(getPrimitiveSet(i)))->write(out);
        else if(dynamic_cast<osg::DrawElementsUInt*>(getPrimitiveSet(i)))
            ((ive::DrawElementsUInt*)(getPrimitiveSet(i)))->write(out);
        else
            out_THROW_EXCEPTION("Unknown PrimitivSet in Geometry::write()");
    }

    // Write vertex array if any
    out->writeBool(getVertexArray()!=0);
    if (getVertexArray())
    {
        out->writeArray(getVertexArray());
    }
    // Write vertex indices if any
    out->writeBool(getVertexIndices()!=0);
    if (getVertexIndices())
    {
        out->writeArray(getVertexIndices());
    }
    
    // Write normal array if any
    if ( out->getVersion() < VERSION_0013 )
    {
        osg::Vec3Array* normals = dynamic_cast<osg::Vec3Array*>(getNormalArray());
        out->writeBool(normals!=0);
        if (normals)
        {
            out->writeBinding(getNormalBinding());
            out->writeVec3Array(normals);
        }
    }
    else
    {
        out->writeBool(getNormalArray()!=0);
        if (getNormalArray()!=0)
        {
            out->writeBinding(getNormalBinding());
            out->writeArray(getNormalArray());
        }
    }
    
    // Write normal indices if any
    out->writeBool(getNormalIndices()!=0);
    if (getNormalIndices()){
        out->writeArray(getNormalIndices());        
    }
    // Write color array if any.
    out->writeBool(getColorArray()!=0);
    if (getColorArray()){
        out->writeBinding(getColorBinding());
        out->writeArray(getColorArray());
    }
    // Write color indices if any
    out->writeBool(getColorIndices()!=0);
    if (getColorIndices()){
        out->writeArray(getColorIndices());        
    }
    // Write secondary color array if any
    out->writeBool(getSecondaryColorArray()!=0);
    if (getSecondaryColorArray()){
        out->writeBinding(getSecondaryColorBinding());
        out->writeArray(getSecondaryColorArray());
    }
    // Write second color indices if any
    out->writeBool(getSecondaryColorIndices()!=0);
    if (getSecondaryColorIndices()){
        out->writeArray(getSecondaryColorIndices());
    }
    // Write fog coord array if any
    out->writeBool(getFogCoordArray()!=0);
    if (getFogCoordArray()){
        out->writeBinding(getFogCoordBinding());
        out->writeArray(getFogCoordArray());
    }
    // Write fog coord indices if any
    out->writeBool(getFogCoordIndices()!=0);
    if (getFogCoordIndices()){
        out->writeArray(getFogCoordIndices());
    }
    // Write texture coord arrays
    Geometry::ArrayDataList& tcal = getTexCoordArrayList();
    out->writeInt(tcal.size());
    unsigned int j;
    for(j=0;j<tcal.size();j++)
    {
        // Write coords if valid
        out->writeBool(tcal[j].array.valid());
        if (tcal[j].array.valid()){
            out->writeArray(tcal[j].array.get());
        }
        // Write indices if valid
        out->writeBool(tcal[j].indices.valid());
        if (tcal[j].indices.valid()){
            out->writeArray(tcal[j].indices.get());
        }
    }

    // Write vertex attributes
    Geometry::ArrayDataList& vaal = getVertexAttribArrayList();
    out->writeInt(vaal.size());
    for(j=0;j<vaal.size();j++)
    {
        // Write coords if valid
        const osg::Geometry::ArrayData& arrayData = vaal[j];
        out->writeBinding(arrayData.binding);
        out->writeBool(arrayData.normalize==GL_TRUE);
        out->writeBool(arrayData.array.valid());
        if (arrayData.array.valid()){
            out->writeArray(arrayData.array.get());
        }
        // Write indices if valid
        out->writeBool(arrayData.indices.valid());
        if (arrayData.indices.valid()){
            out->writeArray(arrayData.indices.get());
        }
    }
}

void Geometry::read(DataInputStream* in){
    // Read Geometry's identification.
    int id = in->peekInt();
    if(id == IVEGEOMETRY){
        // Code to read Geometry's properties.
        id = in->readInt();
        // If the osg class is inherited by any other class we should also read this from file.
        osg::Drawable*  drawable = dynamic_cast<osg::Drawable*>(this);
        if(drawable){
            ((ive::Drawable*)(drawable))->read(in);
        }
        else
            in_THROW_EXCEPTION("Geometry::read(): Could not cast this osg::Geometry to an osg::Drawable.");


        // Read geoemtry properties

        // Read primitiveset list.
        int size = in->readInt();
        int i;
        for(i=0;i<size;i++){
            osg::PrimitiveSet* prim;
            int primID = in->peekInt();
            if(primID==IVEDRAWARRAYS){
                prim = new osg::DrawArrays();
                ((ive::DrawArrays*)(prim))->read(in);
                addPrimitiveSet(prim);
            }
            else if(primID==IVEDRAWARRAYLENGTHS){
                prim = new osg::DrawArrayLengths();
                ((ive::DrawArrayLengths*)(prim))->read(in);
                addPrimitiveSet(prim);
            }
            else if(primID==IVEDRAWELEMENTSUBYTE){
                prim = new osg::DrawElementsUByte();
                ((ive::DrawElementsUByte*)(prim))->read(in);
                addPrimitiveSet(prim);
            }
            else if(primID==IVEDRAWELEMENTSUSHORT){
                prim = new osg::DrawElementsUShort();
                ((ive::DrawElementsUShort*)(prim))->read(in);
                addPrimitiveSet(prim);
            }
            else if(primID==IVEDRAWELEMENTSUINT){
                prim = new osg::DrawElementsUInt();
                ((ive::DrawElementsUInt*)(prim))->read(in);
                addPrimitiveSet(prim);
            }
            else{
                in_THROW_EXCEPTION("Unknown PrimitiveSet in Geometry::read()");
            }
        }
    
        // Read vertex array if any
        bool va=in->readBool();
        if (va){
            setVertexArray(in->readArray());
        }
        // Read vertex indices if any
        bool vi = in->readBool();
        if (vi){
            setVertexIndices(static_cast<osg::IndexArray*>(in->readArray()));
        }

        // Read normal array if any
        if ( in->getVersion() < VERSION_0013 )
        {
            bool na =in->readBool();
            if(na){
                setNormalBinding(in->readBinding());
                setNormalArray(in->readVec3Array());
            }
        }
        else
        {
            bool na =in->readBool();
            if(na){
                setNormalBinding(in->readBinding());
                setNormalArray(in->readArray());
            }
        }

        // Read normal indices if any
        bool ni = in->readBool();
        if(ni){
            setNormalIndices(static_cast<osg::IndexArray*>(in->readArray()));
        }
        // Read color array if any.
        if(in->readBool()){
            setColorBinding(in->readBinding());
            setColorArray(in->readArray());
        }
        // Read color indices if any
        if(in->readBool()){
            setColorIndices(static_cast<osg::IndexArray*>(in->readArray()));
        }
        // Read secondary color array if any
        if(in->readBool()){
            setSecondaryColorBinding(in->readBinding());
            setSecondaryColorArray(in->readArray());
        }
        // Read second color indices if any
        if(in->readBool()){
            setSecondaryColorIndices(static_cast<osg::IndexArray*>(in->readArray()));
        }
        // Read fog coord array if any
        if(in->readBool()){
            setFogCoordBinding(in->readBinding());
            setFogCoordArray(in->readArray());
        }
        // Read fog coord indices if any
        if(in->readBool()){
            setFogCoordIndices(static_cast<osg::IndexArray*>(in->readArray()));
        }
        // Read texture coord arrays
        size = in->readInt();
        for(i =0;i<size;i++)
        {
            // Read coords if valid
            bool coords_valid = in->readBool();
            if(coords_valid)
                setTexCoordArray(i, in->readArray());
            // Read Indices if valid
            bool indices_valid = in->readBool();
            if(indices_valid)
                setTexCoordIndices(i, static_cast<osg::IndexArray*>(in->readArray()));
        }

        // Read vertex attrib arrays
        size = in->readInt();
        for(i =0;i<size;i++)
        {
            setVertexAttribBinding(i,in->readBinding());
            setVertexAttribNormalize(i,in->readBool()?GL_TRUE:GL_FALSE);
            
            // Read coords if valid
            bool coords_valid = in->readBool();
            if(coords_valid)
                setVertexAttribArray(i, in->readArray());
                
            // Read Indices if valid
            bool indices_valid = in->readBool();
            if(indices_valid)
                setVertexAttribIndices(i, static_cast<osg::IndexArray*>(in->readArray()));
        }

    }
    else{
        in_THROW_EXCEPTION("Geometry::read(): Expected Geometry identification.");
    }
}
