/*
 * binary.c
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BINARY_FILE    "myfile.bin"

typedef struct {
    char  str[4];
    int   num;
} t_data;

void generate_string(char * s, int len)
{
    while (len > 0) {
        *s = rand() % 24 + 64;
        s++;
        len--;
    }
    *s = 0;
}


t_data * generate(int size)
{
    int i;
    t_data * array;

    srand(time(NULL));
    array = (t_data *)malloc(size * sizeof(t_data));
    for (i = 0;i < size;i++) {
        generate_string(array[i].str, 3);
        array[i].num = rand() % 128;
    }
    return array;
}


void write_file(t_data * array, int n)
{
    FILE * f;
    f = fopen(BINARY_FILE, "wb");
    if (f == NULL) {
        printf("Cannot create binary file\n");
        exit(1);
    }
    fwrite(array, sizeof(t_data), n, f);
    fclose(f);
}


t_data * read_file(int * n)
{
    FILE * f;
    t_data * data;
    int num_of_elements;

    f = fopen(BINARY_FILE, "rb");
    if (f == NULL) {
        printf("Cannot read binary file\n");
        exit(1);
    }

    fseek(f, 0, SEEK_END); /* let's go to the end of file */
    num_of_elements = ftell(f) / sizeof(t_data); /* read current file position and divide it per data size */
    data = (t_data *)malloc(num_of_elements * sizeof(t_data)); /* allocate memory */

    fseek(f, 0, SEEK_SET); /* rewind the file */
    fread(data, sizeof(t_data), num_of_elements, f); /* read all data */
    fclose(f);
    *n = num_of_elements;
    return data;
}


void read_and_print_file(void)
{
    FILE * f;
    t_data rec;

    f = fopen(BINARY_FILE, "rb");
    if (f == NULL) {
        printf("Cannot read binary file\n");
        exit(1);
    }
    while (fread(&rec, sizeof(t_data), 1, f) == 1) {
        printf("%s, %d\n", rec.str, rec.num);
    }
    fclose(f);
}


void insert_sort(t_data * v,int n)
{
    int i, j;
    t_data a;

    for (i = 0; i < n - 1; i++) {

        for (j = i+1; j >= 1; j--) {

            if (strcmp(v[j-1].str,v[j].str)  > 0) {
                a = v[j];
                v[j] = v[j-1];
                v[j-1] = a;
            }
            else
                break;
        }
    }
}


void read_and_sort_file(void)
{
    t_data * data;
    int size;

    data = read_file(&size);
    insert_sort(data, size);
    write_file(data, size);
    free(data);
}


int find (char * key)
{
    FILE * f;
    t_data data;
    int num_of_elements, low, high, mid;
    f = fopen(BINARY_FILE, "rb");
    if (f == NULL) {
        printf("Cannot read binary file\n");
        exit(1);
    }
    fseek(f, 0, SEEK_END);
    num_of_elements = ftell(f) / sizeof(t_data);

    low = 0;
    high = num_of_elements - 1;

    while (high >= low) {
        int comparison;
        mid = (low + high) / 2;
        fseek(f, mid * sizeof(t_data), SEEK_SET);
        fread(&data, sizeof(t_data), 1, f);
        comparison = strcmp(data.str, key);
        if (comparison == 0) /* item found! */
            return mid;
        if (comparison < 0) /* item could be found at right */
            low = mid + 1;
        else /* item could be found at left */
            high = mid - 1;
    }
    return -1;
}


int main(int argc, char **argv)
{
    int size;
    t_data * data;
    if (argc < 2) {
        printf("missing command\n");
        return 1;
    }
    if (!strcmp(argv[1], "generate")) {
        /* syntax: binary generate file-size */
        if (argc < 3) {
            printf("missing file size\n");
            return 1;
        }
        size = atoi(argv[2]);
        data = generate(size);
        write_file(data, size);
        return 0;
    }
    if (!strcmp(argv[1], "show")) {
        /* syntax: binary show */
        read_and_print_file();
        return 0;
    }
    if (!strcmp(argv[1], "sort")) {
        /* syntax: binary sort */
        read_and_sort_file();
        return 0;
    }
    if (!strcmp(argv[1], "find")) {
        int pos;
        /* syntax: binary find string */
        if (argc < 3) {
            printf("missing string to find\n");
            return 1;
        }
        pos = find(argv[2]);
        if (pos >= 0)
            printf("Item found at position %d\n", pos);
        else
            printf("Item not found\n");
        return 0;
    }
}
