#include "xentax.h"
#include "stdres.h"
#include "x_pssg.h"

// GAMES (PS3)
#include "ps3_touchshot.h"
#include "ps3_one_piece.h"
#include "ps3_neptunia_mk2.h"

// GAMES (XBOX360)
#include "xb360_onechanbara2.h"

#include "x_stream.h"
#include "x_smc.h"
#include "x_lwo.h"

//bool TestG1M_0034(const char* filename);
//bool TestG1MG0044(const binary_stream& bs);

#include "x_file.h"

int main()
{
 //XB360::Onechanbara2::extract();
 PSSG::extract();

 //PS3::OnePiece::extract();
 //PS3::TOUCHSHOT::extract();
 //PS3::NEPTUNIA_MK2::extract();

 //TestG1M_0034("test.g1m");
 return 0;
}

/*
bool TestG1M_0034(const char* filename)
{
 using namespace std;

 // open file
 ifstream ifile(filename, ios::binary);
 if(!ifile) return error("Failed to open file.");

 // compute filesize
 ifile.seekg(0, ios::end);
 uint32 filesize = (uint32)ifile.tellg();
 ifile.seekg(0, ios::beg);

 // read file
 boost::shared_array<char> data(new char[filesize]);
 ifile.read(data.get(), filesize);

 // create binary stream
 binary_stream bs(data, filesize);

 // read header
 uint32 head01 = bs.BE_read_uint32(); // magic
 uint32 head02 = bs.BE_read_uint32(); // version
 uint32 head03 = bs.BE_read_uint32(); // total section size
 uint32 head04 = bs.BE_read_uint32(); // start offset
 uint32 head05 = bs.BE_read_uint32(); // 0x00
 uint32 head06 = bs.BE_read_uint32(); // number of chunks to read

 // validate header
 if(head01 != 0x47314D5F) return error("Expecting G1M_ section.");
 if(head02 != 0x30303334) return error("Invalid G1M_ version.");
 if(head03 == 0) return error("Invalid G1M_.");
 if(head04 == 0) return error("Invalid G1M_.");

 // move to start
 bs.seek(head04);
 if(bs.fail()) return error("processG1M: Seek failure.");

 // read chunks
 for(uint32 i = 0; i < head06; i++)
    {
     // read first chunk
     uint32 chunkname = bs.BE_read_uint32(); // chunk name
     uint32 chunkvers = bs.BE_read_uint32(); // chunk version
     uint32 chunksize = bs.BE_read_uint32(); // chunk size

     // process chunk
     switch(chunkname) {
       case(0x47314D46) : { // G1MF
            bs.move(chunksize - 0x0C);
            break;
           }
       case(0x47314D53) : { // G1MS
            bs.move(chunksize - 0x0C);
            break;
           }
       case(0x47314D4D) : { // G1MM
            bs.move(chunksize - 0x0C);
            break;
           }
       case(0x47314D47) : { // G1MG
            if(!TestG1MG0044(bs)) return false;
            bs.move(chunksize - 0x0C);
            break;
           }
       case(0x45585452) : { // EXTR
            bs.move(chunksize - 0x0C);
            break;
           }
       default : {
            stringstream ss;
            ss << "processG1M: Unknown chunk 0x" << std::hex << chunkname << std::dec << ".";
            return error(ss.str().c_str());
           }
      }
    }

 return true;
}

bool TestG1MG0044(const binary_stream& bs)
{
 using namespace std;

 // copy stream
 binary_stream stream(bs);
 if(stream.fail()) return error("Cannot copy binary stream.");

 // read header
 uint32 platform = stream.BE_read_uint32();
 uint32 unknown1 = stream.BE_read_uint32();
 real32 min_x = stream.BE_read_real32();
 real32 min_y = stream.BE_read_real32();
 real32 min_z = stream.BE_read_real32();
 real32 max_x = stream.BE_read_real32();
 real32 max_y = stream.BE_read_real32();
 real32 max_z = stream.BE_read_real32();
 uint32 sections = stream.BE_read_uint32();

 // validate header
 if(platform != 0x50533300) return error("Only PS3 version of game is supported.");
 if(sections == 0) return error("Invalid number of sections.");

 cout << "HEADER:" << endl;
 cout << " Number of sections: " << sections << endl;
 cout << endl;

 // section information
 struct G1MG0044_ITEM {
  uint32 type;
  uint32 size;
  uint32 elem;
  boost::shared_array<char> data;
 };

 // read section information
 deque<G1MG0044_ITEM> items;
 for(size_t i = 0; i < sections; i++) {
     G1MG0044_ITEM item;
     item.type = stream.BE_read_uint32();
     item.size = stream.BE_read_uint32();
     item.elem = stream.BE_read_uint32();
     item.data.reset(new char[item.size - 0xC]);
     stream.read(item.data.get(), item.size - 0xC);
     items.push_back(item);
    }

 // test OBJ
 ofstream ofile("test.obj");
 ofile << "o test.obj" << endl;

 // for each section
 for(size_t i = 0; i < items.size(); i++)
    {
     // 
     if(items[i].type == 0x00010001)
       {
        cout << "0x00010001: " << items[i].elem << endl;
       }
     // 
     else if(items[i].type == 0x00010002)
       {
        cout << "0x00010002: " << items[i].elem << endl;
       }
     // 
     else if(items[i].type == 0x00010003)
       {
        cout << "0x00010003: " << items[i].elem << endl;
       }
     // vertex section
     else if(items[i].type == 0x00010004)
       {
        cout << "0x00010004: " << items[i].elem << endl;

        // binary stream from data
        binary_stream ss(items[i].data, items[i].size - 0x8);
        ss.seek(0);

        // read vertex sections
        uint32 n_meshes = items[i].elem;
        cout << "Meshes = " << n_meshes << endl;

        for(size_t j = 0; j < n_meshes; j++)
           {
            // read mesh vertex info
            uint32 unknown1 = ss.BE_read_uint32();
            uint32 vertsize = ss.BE_read_uint32();
            uint32 vertices = ss.BE_read_uint32();
            uint32 unknown2 = ss.BE_read_uint32();

            cout << "Mesh #" << j << endl;
            cout << " vertsize = " << vertsize << endl;
            cout << " vertices = " << vertices << endl;

            // buffer name
            stringstream name;
            name << "vb_" << setfill('0') << setw(2) << i;

            // set vertex buffer properties
            VTX_BUFFER vb;
            vb.flags = 0;
            vb.name = name.str();
            vb.elem = vertices;
            vb.data.reset(new VERTEX[vertices]);

            // set vertex buffer flags
            if(vertsize == 0x10) {
               vb.flags |= VERTEX_POSITION;
               vb.flags |= VERTEX_NORMAL;
               vb.flags |= VERTEX_UV;
              }
            else if(vertsize == 0x14) {
               vb.flags |= VERTEX_POSITION;
               vb.flags |= VERTEX_NORMAL;
               vb.flags |= VERTEX_UV;
              }
            else if(vertsize == 0x18) {
               vb.flags |= VERTEX_POSITION;
               vb.flags |= VERTEX_NORMAL;
              }
            else if(vertsize == 0x1C) {
               vb.flags |= VERTEX_POSITION;
               vb.flags |= VERTEX_NORMAL;
               vb.flags |= VERTEX_UV;
              }
            else if(vertsize == 0x20) {
               vb.flags |= VERTEX_POSITION;
               vb.flags |= VERTEX_NORMAL;
               vb.flags |= VERTEX_UV;
              }
            else if(vertsize == 0x24) {
               vb.flags |= VERTEX_POSITION;
               vb.flags |= VERTEX_NORMAL;
               vb.flags |= VERTEX_UV;
              }
            else if(vertsize == 0x28) {
              }
            else if(vertsize == 0x38) {
               vb.flags |= VERTEX_POSITION;
               vb.flags |= VERTEX_NORMAL;
               vb.flags |= VERTEX_UV;
              }
            else
               return error("Unknown vertex format.");

            // read vertices
            for(size_t k = 0; k < vertices; k++)
               {
                VERTEX vertex;
                if(vertsize == 0x10) {
                   vertex.vx = ss.BE_read_real16();
                   vertex.vy = ss.BE_read_real16();
                   vertex.vz = ss.BE_read_real16();
                   ss.BE_read_real16();
                   vertex.nx = ss.BE_read_real16();
                   vertex.ny = ss.BE_read_real16();
                   vertex.nz = ss.BE_read_real16();
                   ss.BE_read_real16();
                  }
                else if(vertsize == 0x14) {
                   vertex.vx = ss.BE_read_real16();
                   vertex.vy = ss.BE_read_real16();
                   vertex.vz = ss.BE_read_real16();
                   ss.BE_read_real16();
                   vertex.nx = ss.BE_read_real16();
                   vertex.ny = ss.BE_read_real16();
                   vertex.nz = ss.BE_read_real16();
                   ss.BE_read_real16();
                   vertex.tu = ss.BE_read_real16();
                   vertex.tv = ss.BE_read_real16();
                  }
                else if(vertsize == 0x18) {
                   vertex.vx = ss.BE_read_real32();
                   vertex.vy = ss.BE_read_real32();
                   vertex.vz = ss.BE_read_real32();
                   vertex.nx = ss.BE_read_real16();
                   vertex.ny = ss.BE_read_real16();
                   vertex.nz = ss.BE_read_real16();
                   ss.BE_read_real16();
                   ss.BE_read_real32();
                  }
                else if(vertsize == 0x1C) {
                   vertex.vx = ss.BE_read_real32();
                   vertex.vy = ss.BE_read_real32();
                   vertex.vz = ss.BE_read_real32();
                   vertex.nx = ss.BE_read_real16();
                   vertex.ny = ss.BE_read_real16();
                   vertex.nz = ss.BE_read_real16();
                   ss.BE_read_real16();
                   ss.BE_read_real32();
                   vertex.tu = ss.BE_read_real16();
                   vertex.tv = ss.BE_read_real16();
                  }
                else if(vertsize == 0x20) {
                   vertex.vx = ss.BE_read_real32();
                   vertex.vy = ss.BE_read_real32();
                   vertex.vz = ss.BE_read_real32();
                   vertex.nx = ss.BE_read_real16();
                   vertex.ny = ss.BE_read_real16();
                   vertex.nz = ss.BE_read_real16();
                   ss.BE_read_real16();
                   ss.BE_read_real32();
                   ss.BE_read_real16();
                   ss.BE_read_real16();
                   vertex.tu = ss.BE_read_real16();
                   vertex.tv = ss.BE_read_real16();
                  }
                else if(vertsize == 0x24) {
                   vertex.vx = ss.BE_read_real32();
                   vertex.vy = ss.BE_read_real32();
                   vertex.vz = ss.BE_read_real32();
                   vertex.nx = ss.BE_read_real32();
                   vertex.ny = ss.BE_read_real32();
                   vertex.nz = ss.BE_read_real32();
                   ss.BE_read_real32();
                   vertex.tu = ss.BE_read_real32();
                   vertex.tv = ss.BE_read_real32();
                  }
                else if(vertsize == 0x28) {
                   ss.BE_read_real32(); // TODO
                   ss.BE_read_real32();
                   ss.BE_read_real32();
                   ss.BE_read_real32();
                   ss.BE_read_real32();
                   ss.BE_read_real32();
                   ss.BE_read_real32();
                   ss.BE_read_real32();
                   ss.BE_read_real32();
                   ss.BE_read_real32();
                  }
                else if(vertsize == 0x38) {
                   vertex.vx = ss.BE_read_real32(); // x
                   vertex.vy = ss.BE_read_real32(); // y
                   vertex.vz = ss.BE_read_real32(); // z
                   ss.BE_read_real32(); // 1.0
                   ss.BE_read_real32(); // w1
                   ss.BE_read_real32(); // w2
                   ss.BE_read_real32(); // w3
                   (uint32)ss.BE_read_uint08();
                   (uint32)ss.BE_read_uint08();
                   (uint32)ss.BE_read_uint08();
                   (uint32)ss.BE_read_uint08();
                   ss.BE_read_real16();
                   ss.BE_read_real16();
                   ss.BE_read_real16();
                   ss.BE_read_real16();
                   vertex.tu = ss.BE_read_real32(); // u
                   vertex.tv = ss.BE_read_real32(); // v
                   ss.BE_read_real32();
                   ss.BE_read_real32();

                   ofile << "v " << vertex.vx << " " << vertex.vy << " " << vertex.vz << endl;
                  }

                // save vertex
                vb.data[k] = vertex;
               }
           }
       }
     // 
     else if(items[i].type == 0x00010005)
       {
        cout << "0x00010005: " << items[i].elem << endl;
       }
     // 
     else if(items[i].type == 0x00010006)
       {
        cout << "0x00010006: " << items[i].elem << endl;
       }
     // index buffer section
     else if(items[i].type == 0x00010007)
       {
        cout << "0x00010007: " << items[i].elem << endl;

        // binary stream from data
        binary_stream ss(items[i].data, items[i].size - 0x8);
        ss.seek(0);

        // read face sections
        uint32 n_meshes = items[i].elem;
        uint32 vb_index = 0;
        for(size_t j = 0; j < n_meshes; j++)
           {
            // read face data
            uint32 numindex = ss.BE_read_uint32();
            uint32 datatype = ss.BE_read_uint32();
            uint32 unknown1 = ss.BE_read_uint32();

            // set index buffer properties
            IDX_BUFFER ib;
            ib.type = FACE_TYPE_TRISTRIP;
            ib.elem = numindex;
            if(datatype == 0x10) ib.format = FACE_FORMAT_UINT_16;
            else if(datatype == 0x20) ib.format = FACE_FORMAT_UINT_32;
            else return error("Unknown index buffer data format.");

            // set index buffer name
            stringstream surface;
            surface << "surface_" << setfill('0') << setw(3) << j << ends;
            ib.name = surface.str();

            // determine index buffer data type size
            unsigned int typesize = 0;
            if(datatype == 0x10) typesize = sizeof(uint16);
            else if(datatype == 0x20) typesize = sizeof(uint32);
            else return error("Unknown index buffer data type.");

            // read face data
            unsigned int total_bytes = ib.elem*typesize;
            ib.data.reset(new char[total_bytes]);
            if(ib.format == FACE_FORMAT_UINT_16) ss.BE_read_array(reinterpret_cast<uint16*>(ib.data.get()), ib.elem);
            else if(ib.format == FACE_FORMAT_UINT_32) ss.BE_read_array(reinterpret_cast<uint32*>(ib.data.get()), ib.elem);

            // test face data
            uint32 min_index = 0;
            uint32 max_index = 0;
            if(ib.format == FACE_FORMAT_UINT_16) {
               //uint16 a; minimum(reinterpret_cast<uint16*>(ib.data.get()), ib.elem, a);
               //uint16 b; maximum(reinterpret_cast<uint16*>(ib.data.get()), ib.elem, b);
               //min_index = a;
               //max_index = b;
              }
            else if(ib.format == FACE_FORMAT_UINT_32) {
               //uint32 a; minimum(reinterpret_cast<uint32*>(ib.data.get()), ib.elem, a);
               //uint32 b; maximum(reinterpret_cast<uint32*>(ib.data.get()), ib.elem, b);
               //min_index = a;
               //max_index = b;
              }
            cout << " min index = " << min_index << endl;
            cout << " max index = " << max_index << endl;

            // set vertex buffer reference
            //if(min_index == 0) vb_index++; // there has got to be a better way
            //if(vb_index > 0) ib.reference = vb_index - 1;
            //else return error("Unexpected vertex buffer reference.");

            // save face data
            //fdlist.push_back(ib);
           }
       }
     // 
     else if(items[i].type == 0x00010008)
       {
        cout << "0x00010008: " << items[i].elem << endl;

        // binary stream from data
        binary_stream ss(items[i].data, items[i].size - 0x8);
        ss.seek(0);

        struct G10008 {
         uint32 p01; // C0 00 00 D0
         uint32 p02; // 00 00 00 00
         uint32 p03; // 00 00 00 00
         uint32 p04; // 00 00 00 00
         uint32 p05; // 00 00 00 00
         uint32 p06; // 00 00 00 00
         uint32 p07; // 00 00 00 00
         uint32 p08; // 00 00 00 00
         uint32 p09; // 00 00 00 01
         uint32 p10; // 00 00 00 04
         uint32 p11; // 00 00 00 00
         uint32 p12; // 00 00 00 42
         uint32 p13; // 00 00 00 00
         uint32 p14; // 00 00 00 BE
        };
        deque<G10008> infolist;
        for(uint32 j = 0; j < items[i].elem; j++) {
            G10008 info;
            info.p01 = ss.BE_read_uint32();
            info.p02 = ss.BE_read_uint32();
            info.p03 = ss.BE_read_uint32();
            info.p04 = ss.BE_read_uint32();
            info.p05 = ss.BE_read_uint32();
            info.p06 = ss.BE_read_uint32();
            info.p07 = ss.BE_read_uint32();
            info.p08 = ss.BE_read_uint32();
            info.p09 = ss.BE_read_uint32();
            info.p10 = ss.BE_read_uint32();
            info.p11 = ss.BE_read_uint32();
            info.p12 = ss.BE_read_uint32();
            info.p13 = ss.BE_read_uint32();
            info.p14 = ss.BE_read_uint32();
            infolist.push_back(info);
            cout << "info" << endl;
            cout << " " << info.p01 << endl;
            cout << " " << info.p02 << endl;
            cout << " " << info.p03 << endl;
            cout << " " << info.p04 << endl;
            cout << " " << info.p05 << endl;
            cout << " " << info.p06 << endl;
            cout << " " << info.p07 << endl;
            cout << " " << info.p08 << endl;
            cout << " " << info.p09 << endl;
            cout << " " << info.p10 << endl;
            cout << " " << info.p11 << endl;
            cout << " " << info.p12 << endl;
            cout << " " << info.p13 << endl;
            cout << " " << info.p14 << endl;
           }
       }
    }

 return true;
}
*/