#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
//#include <direct.h>

FILE *infile;
FILE *index_file;

int cd;

int file_position, i;

//unsigned long cd1_size = 718738272; // english version
unsigned long cd1_size = 718199664; // japanese version
unsigned long cd2_size = 688700880; // english version
//unsigned long cd2_size = 729929088; // japanese version

char strindex[44] = {82,73,70,70,0, 0, 0, 0, 67,68,88,65,0, 0, 0, 0,
                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};



void parse_file(unsigned long start_sector, unsigned long file_size, int id, char *file_name)
{



    unsigned char arfile[2352];
    unsigned char type[4];
    const char* extention;
    unsigned int file_type;

    char number[10];

    int size_to_skip, size_to_read;

    int i;

    int ultimo;

    FILE *file;


    // find file start sector
    file_position = fseek(infile, 2352L * start_sector, 0);
    // skip sector header
    file_position = fseek(infile, 24L, 1);
    // read type
    file_position = fread(type, 1, 4, infile);
    // move back to start of sector
    file_position = fseek(infile, -28L, 1);

    // reverse byte order
    file_type = type[3] | (type[2] << 8) | (type[1] << 16) | (type[0] << 24);
    printf("file_type = 0x%x\n", file_type);

    // by default we skip sector header
    size_to_skip = 24;
    size_to_read = 2048;
    extention = "";

    // TIM
    if (file_type == 0x10000000)
    {
        extention = ".tim";
    }
    // SND
    if (file_type == 0x77647320)
    {
        extention = ".snd";
    }
    // SMD
    if (file_type == 0x736d6473)
    {
        extention = ".smd";
    }
    // SED
    if (file_type == 0x73656473)
    {
        extention = ".sed";
    }
    // DUMMY (Stringhe generate dal programma che ha creato il CD originale.)
    if (file_type == 0x49742773)
    {
        extention = ".dummy";
    }
    // UNK1
    if (file_type == 0x01000000)
    {
        extention = ".unk1";
    }
    // UNK2
    if (file_type == 0x02000000)
    {
        extention = ".unk2";
    }
    // UNK3
    if (file_type == 0x03000000)
    {
        extention = ".unk3";
    }
    // UNK4
    if (file_type == 0x04000000)
    {
        extention = ".unk4";
    }
    // UNK5
    if (file_type == 0x05000000)
    {
        extention = ".unk5";
    }
    // UNK6
    if (file_type == 0x06000000)
    {
        extention = ".unk6";
    }
    // UNK7
    if (file_type == 0x07000000)
    {
        extention = ".unk7";
    }
    // UNK8
    if (file_type == 0x08000000)
    {
        extention = ".unk8";
    }
    // STR
    if (file_type == 0x60010180)
    {
        // if we have str format we read with file sector
        size_to_skip = 0;
        size_to_read = 2352;
        extention = ".str";
    }
    // RAW
    if (file_type == 0x00120000)
    {
        extention = ".raw1";
    }
    // RAW
    if (file_type == 0x01120000)
    {
        extention = ".raw2";
    }



    // add zeros to file name 0000.xxx
    if (id < 1000)
    {
        strcat(file_name, "0");
    }
    if (id < 100)
    {
        strcat(file_name, "0");
    }
    if (id < 10)
    {
        strcat(file_name, "0");
    }

    // add number to filepath/filename
    sprintf(number, "%d", id);
    strcat(file_name, number);
    strcat(file_name, extention);



    FILE* desc_file = fopen("description.txt", "a+");
    char desc[ 255 ];
    sprintf(desc, "%s - 0x%04x, 0x%04x\n", file_name, static_cast<unsigned int>(start_sector), static_cast<unsigned int>(file_size));
    fputs (desc, desc_file);
    fclose(desc_file);



    printf("File name: \\%s\n\n", file_name);

    file = fopen(file_name, "wb");

    // if this is str then write str index
    if (size_to_read == 2352)
    {
        file_position = fwrite(strindex, 1, 44, file);
    }

    while ((file_size / (long)size_to_read) >= 1)
    {
        file_position = fseek(infile, (long)size_to_skip, 1);
        file_position = fread(arfile, 1, size_to_read, infile);
        file_position = fwrite(arfile, 1, size_to_read, file);
        file_position = fseek(infile, 2352L - (((long)size_to_read) + ((long)size_to_skip)), 1);
        file_size = file_size - (long)size_to_read;
    }

    if (size_to_read == 2048)
    {
        file_position = fseek(infile, (long)size_to_skip, 1);
        file_position = fread(arfile, 1, file_size, infile);
        file_position = fwrite(arfile, 1, file_size, file);
    }

    for(i = 0; ; i++)
    {
        if (file_name[i] == 0)
        {
            break;
        }
        if (file_name[i] == '\\')
        {
            ultimo = i;
        }
    }
    file_name[ultimo + 1] = 0;

    fclose(file);
}



// create file with cd file index
void create_index_file()
{
    // array for one sector
    unsigned char arfile[2048];

    printf("Creating index_file file list\n");
    if (cd == 1)
    {
        index_file = fopen("index_cd1.bin", "wb");
    }
    else if (cd == 2)
    {
        index_file = fopen("index_cd2.bin", "wb");
    }

    // find start of game files (the first file in the 24 sector)
    file_position = fseek(infile, 24L * 2352L, 0);

    // the size of index - 16 sectors
    for (i = 0; i < 16; i++)
    {
        printf("Sector %d\n", 24 + i);
        // pass sector header
        file_position = fseek(infile, 24L, 1);
        // read and write sector data
        file_position = fread(arfile, 1, 2048, infile);
        file_position = fwrite(arfile, 1, 2048, index_file);
        // go to next sector
        file_position = fseek(infile, 280L, 1);
    }

    fclose(index_file);
}



void extract(char *filename)
{
    signed long start_sector, file_size;
    unsigned char start[3], size[4];
    char numero[10];
    // first directory number 0
    int directory_number = 0;

    // create file with cd file index
    create_index_file();

    if (cd == 1)
    {
        index_file = fopen("index_cd1.bin", "rb");
    }
    else if (cd == 2)
    {
        index_file = fopen("index_cd2.bin", "rb");
    }

    for (i = 0; ; i++)
    {
        file_position = fread(start, 1, 3, index_file);
        file_position = fread(size, 1, 4, index_file);

        // reverse bytes order (low endian)
        start_sector = start[0] | (start[1] << 8) | (start[2] << 16);
        file_size = size[0] | (size[1] << 8) | (size[2] << 16) | (size[3] << 24);

        // end of file
        if (file_size == 0x00ffffff)
        {
            break;
        }
        if (start_sector == 0 && file_size > 0)
        {
            filename[9] = 0;
        }
        // directory
        if (file_size > 0xff000000)
        {
            // create directory name (name - number of directory)
            filename[9] = 0;
            sprintf(numero, "%d", directory_number++);
            strcat(filename, numero);
            strcat(filename, "\\");

            // TODO FIX ME
            //mkdir(filename);
            abort();

            printf("number of file %d, in dir %d", static_cast<int>(-file_size), directory_number);
        }
        // file
        if (start_sector != 0 && file_size < 0xff000000 && file_size > 0)
        {
            printf("file number %d, size: 0x%x byte - ", i, static_cast<unsigned int>(file_size));
            parse_file(start_sector, file_size, i, filename);
        }
    }
}



int verify_iso()
{
    unsigned long position, size;

    position = ftell(infile);
    // set cursor to end of file
    fseek(infile, 0L, SEEK_END);
    size = ftell(infile);
    // set cursor to beginning of file
    fseek(infile, position, SEEK_SET);
    if (size == cd1_size)
    {
        printf("Found a valid Xenogears CD1 image (size: %ld bytes)\n", size);
        return 1;
    }   
    if (size == cd2_size)
    {
        printf("Found a valid Xenogears CD2 image (size: %ld bytes)\n", size);
        return 2;
    }
    else
    {
        printf("Found image (size: %ld bytes)\n", size);
        printf("ERROR: Selected file is not a valid Xenogears image.\n       Check if you are using the correct file or if the CD/ISO is damaged.\n");
        return 0;
    }
}



int
main(int argc, char *argv[])
{
    char filename[20] = "STRIPCD";

    printf("Xenogears Main Disk Dumper v0.9.67\n  Created by Graph and _Ombra_\n\n");

    if (argc != 2)
    {
        printf("USAGE:'extract.exe isofile' extract files from xeno cd image.\n");
        return EXIT_FAILURE;
    }

    if ((infile = fopen(argv[1], "rb")) == NULL)
    {
        printf("The file %s does not exist, Please check the file name.\n", argv[1]);
        return EXIT_FAILURE;
    }

    cd = verify_iso();
    if (cd == 0)
    {
        return EXIT_FAILURE;
    }
    else if (cd == 1)
    {
        strcat(filename, "1\\");
    }
    else if (cd == 2)
    {
        strcat(filename, "2\\");
    }

    // TODO FIX ME
    //mkdir(filename);
    abort();

    extract(filename);
    fclose(infile);
    return EXIT_SUCCESS;
}
