#include "md2_model.h"
#include "md2_file.h"
#include <string>
#include <cstdio>
#include <algorithm>
#include <fstream>

md2_model_t::md2_model_t( const char * dirname, const char * filename )
        : isOk( false ),
          _filename( 0 ),
          numFrames( 0 ),
          numVerts( 0 ),
          numGLCommands( 0 ),
          frames( 0 ),
          gl_cmds( 0 )

{
        
        _filename = strdup( filename );
        
        char full_filename[ 1024 ];
        
        sprintf( full_filename,  "%s/%s.md2", dirname, filename );
        
        ifstream ifs( full_filename, ios::binary | ios::in );

        if ( ! ifs ) {
                cout << " :: md2_model: no file " << full_filename << endl;
                return;
        }

        md2_file::model_t md;
        ifs.read( &md, sizeof( md2_file::model_t ) );

        numFrames     = md.numFrames;
        numVerts      = md.numVertices;
        numGLCommands = md.numGLCommands;
        
        frames = new md2_frame_t[ numFrames ];
        
        for ( int i = 0; i < numFrames; ++i ) {
                frames[i].verts = new float[ numVerts * 3 ];
        }

        md2_file::loadFrames( ifs, md, frames );

        //        gl_cmds = new md2_gl_cmd_t[ numGLCommands ];
        
        numGLCommands = md2_file::loadGLCmds( ifs, md, &gl_cmds );

        ifs.close();
        
        isOk = true;

        cout << " :: new " << *this << endl;
}

md2_model_t::~md2_model_t() {
        if ( frames ) {
                for ( int i = 0; i < numFrames; ++i ) {
                        if ( frames[i].verts )
                                delete[] frames[i].verts;
                }
                delete[] frames;
        }
        if ( gl_cmds ) {
                for ( int i = 0; i < numGLCommands; ++i ) {
                        if ( gl_cmds[i].verts_i )
                                delete[] gl_cmds[i].verts_i;
                        if ( gl_cmds[i].texcoords )
                                delete[] gl_cmds[i].texcoords;
                }
                delete[] gl_cmds;
        }
}

float md2_model_t::getZTrans( int frame ) const {
        if ( frame < 0 || frame >= numFrames )
                return 0;
        
        return frames[frame].trans[2];
}

const float * md2_model_t::getTrans( int frame ) const {

        static const float def_trans[3] = { 0, 0, 0 };
        
        if ( frame < 0 || frame >= numFrames )
                return def_trans;
        
        return frames[frame].trans;
}

void md2_model_t::getBoundingInfo( int frame_num, int * rad, int * height, int * x, int * y, int * z ) const {

        md2_frame_t & frame = frames[ frame_num ];
        
        float z_vals[2] = { 999999, -999999 };
        float x_vals[2] = { 999999, -999999 };
        float y_vals[2] = { 999999, -999999 };
        
        int index = 0;
        for ( int i = 0; i < numVerts; ++i ) {
                if ( frame.verts[ index ] < x_vals[0] )
                        x_vals[0] = frame.verts[ index ];
                if ( frame.verts[ index ] > x_vals[1] )
                        x_vals[1] = frame.verts[ index ];
                ++index;
                if ( frame.verts[ index ] < y_vals[0] )
                        y_vals[0] = frame.verts[ index ];
                if ( frame.verts[ index ] > y_vals[1] )
                        y_vals[1] = frame.verts[ index ];
                ++index;
                if ( frame.verts[ index ] < z_vals[0] )
                        z_vals[0] = frame.verts[ index ];
                if ( frame.verts[ index ] > z_vals[1] )
                        z_vals[1] = frame.verts[ index ];
                ++index;
        }

        *height = (int) ( z_vals[1] - z_vals[0] );
        
        float dx = ( x_vals[1] - x_vals[0] ) / 2;
        float dy = ( y_vals[1] - y_vals[0] ) / 2;
        
        *rad = (int) max( dx, dy );
        
        *x = (int) ( x_vals[0] + dx );
        *y = (int) ( y_vals[0] + dy );
        *z = (int) z_vals[0];
}

md2_gl_cmd_t::md2_gl_cmd_t() :
        num_verts(0),
        verts_i(0),
        texcoords(0) {
        
}

ostream & operator<<( ostream & os, const md2_model_t & m ) {
        os << "Model:[ " << m._filename 
           << ", frames=" << m.numFrames
           << ", verts=" << m.numVerts
           << ", gl=" << m.numGLCommands
           << " ]";
        return os;
}

