import config, vector, mystring, util, code

class Algo2Sample:
    char *name
    # Vector *features
    BitCode *bitcode # None if features should be used instead

class Algo2Class:
    char *name

    Vector *training_samples
    Vector *test_samples

    V *per_feature_means
    V *per_feature_vars

    int intra_total, intra_n, intra_min, intra_max
    int inter_total, inter_n

class Algo2Set:
    Vector *classes

    V *per_feature_means
    V *per_feature_vars

    # We divide the matching score (0..1) into 512 bins and count the number
    # of inter-class and intra-class matches falling within.
    int bins_count
    int intra_bins[512]
    int inter_bins[512]

    # used by algo1 matching
    int rotation_offsets

Algo2Sample *def data_get_first_sample(Algo2Set *self):
    Algo2Class *c = *((Algo2Class **)vector_get(self->classes, 0))
    return *((Algo2Sample **)vector_get(c->test_samples, 0))

Algo2Set *def data_load_sets(char const *filename):
    """
    The internal file format is line based as follows:
    <classname 1>:
    <filename of training feature vector 1>
    ...
    -
    <filename of test feature vector 1>
    ...
    <classname 2>:
    ...
    
    """
    printf("Loading %s\n", filename)
    Algo2Set *set = ALLOCATE0(sizeof *set)
    set->classes = vector_new(sizeof(Algo2Class *))
    Algo2Class *cla = None
    bool training = True

    int stats_c = 0, stats_fv = 0

    FILE *f = fopen(filename, "rb")
    String *line = string_new()
    while 1:
        int c = fgetc(f)
        if c == '\r': continue
        if c == '\n' or c < 0:
            string_strip(line)
            if string_char(line, -1) == ':':
                cla = ALLOCATE0(sizeof *cla)
                cla->training_samples = vector_new(sizeof(Algo2Sample *))
                cla->test_samples = vector_new(sizeof(Algo2Sample *))
                cla->name = strdup(string_c(line))
                cla->name[strlen(cla->name) - 1] = '\0' # remove:
                vector_add(set->classes, &cla)
                training = True
                stats_c++
            elif string_is_same_c(line, "-"):
                training = False
            elif not string_is_empty(line):
                Algo2Sample *sam = ALLOCATE0(sizeof *sam)
                sam->name = strdup(string_c(line))
                if training:
                    vector_add(cla->training_samples, &sam)
                else:
                    vector_add(cla->test_samples, &sam)
                    
                Vector *features = readfile_datasize(string_c(line), 1)
                sam->bitcode = bitcode_decode(features)
                vector_del(features)

                #for int i = 0; i < 26; i++:
                #    V v = *(V *)vector_get(sam->features, i)
                #    printf(" %f", v)
                #printf("\n")
                
                #generate a random feature vector
                #sam->features = vector_new(sizeof(V))
                #for int ir = 0; ir < 26; ir++:
                #    V v = (double)rand() / (double)RAND_MAX
                #    vector_cat(sam->features, &v, 1)

                #generate a blank feature vector
                #sam->features = vector_new(sizeof(V))
                #for int ir = 0; ir < 26; ir++:
                #    V v = 0
                #    vector_cat(sam->features, &v, 1)

                stats_fv++
            string_clear(line)
            if c < 0: break
            continue
        string_add(line, c)
    printf("%d classes and %d feature vectors loaded.\n", stats_c, stats_fv)

    return set

int def data_test_samples_count(Algo2Set *set):
    int n = 0
    for int i = 0; i < set->classes->count; i++:
        Algo2Class *c = *((Algo2Class **)vector_get(set->classes, i))
        n += c->test_samples->count
    return n

int def data_training_samples_count(Algo2Set *set):
    int n = 0
    for int i = 0; i < set->classes->count; i++:
        Algo2Class *c = *((Algo2Class **)vector_get(set->classes, i))
        n += c->training_samples->count
    return n