#include "life.h"
//constants
const int num_types = 100;
static int* types;//filled with numbers

const int MAX_HP = 1024;

//for display pourposes
const int GENE_COLOR_R = 0;
const int GENE_COLOR_G = 1;
const int GENE_COLOR_B = 2;

//determines health
const int GENE_HP = 3;
const int GENE_BREED_METHOD = 4;
const int GENE_WATER_NEEDS = 5;
const int GENE_LIGHT_NEEDS = 6;
const int GENE_HP_USE = 7;
const int GENE_WATER_EFF = 7;
const int GENE_LIGHT_EFF = 8;
const int GENE_FOOD_TYPE = 9;
const int GENE_FOOD_SIZE = 10;
const int GENE_BREED_HP = 11;
const int GENE_BREED_COUNT = 12;
const int GENE_MOVE = 13;
const int GENE_NO_WATER = 14;
const int GENE_WATER_USE = 15;
const int GENE_ELEMENT = 16;
const int GENE_ELEMENT_HARM = 17;

static struct random_data rand_buf;

static int get_key(life_list_t* l);

static int get_key(life_list_t* l){
    return get_element(&l->life_stats, 0, rand_int());
}
int rand_int(void){
    int32_t rand_int;
    random_r(&rand_buf, &rand_int);
    return (int)(rand_int >> 8);
    
}

static pthread_t* workers;
//returns the new object after a full copy and adding it
static life_list_t* life_copy(life_list_t* instance);

//finds food and adds HP when found
static void life_feed(world_cell_t* cell, life_list_t* instance);

//looks at the known elements in the cell and reacts with them
static void life_react(world_cell_t* cell, life_list_t* instance);

//age it, and kill it if HP drops below zero, return next instance on the list before its removed
static int life_age(world_cell_t* cell, life_list_t* instance);

//spawn if possible
static void life_spawn(world_cell_t* cell, life_list_t* instance);

//move if you want, return next instance on list before it was moved
static void life_move(world_cell_t* cell, life_list_t* instance);

//move the instance to a new list
static void life_move_l(life_list_head_t* dst_list, life_list_t* instance);

//remove the element from the list (does not destroy it)
static void remove_from_list(life_list_t* instance);


typedef struct {
    int x0;
    int x1;
    int y0;
    int y1;
} life_compete_job_t;

typedef struct {
    life_compete_job_t* jobs;
    int number_jobs;
} life_compete_job_list_t;

static pthread_barrier_t compete_start, compete_end;



static void lock_cell(world_cell_t* cell);
static void unlock_cell(world_cell_t* cell);

//executes all the blocks on the job list
static void* worker_compete(void* job_list);

static void* worker_compete(void* job_list){
    life_compete_job_list_t* jobs = (life_compete_job_list_t*)job_list;
    unsigned int cur_update = 0;
    while (1){
        cur_update++;
        //wait to be signaled
        pthread_barrier_wait(&compete_start);
        //run the jobs
        int i, x, y;
        //pthread_t us = pthread_self();
        for (i = 0; i < jobs->number_jobs; i++){
            
            //printf("Running Job %dx%d-%dx%d (%d)\n", jobs->jobs[i].x0, jobs->jobs[i].y0, jobs->jobs[i].x1, jobs->jobs[i].y1, (int)us);
            for (x = jobs->jobs[i].x0; x < jobs->jobs[i].x1; x++){
                for (y = jobs->jobs[i].y0; y < jobs->jobs[i].y1; y++){
                    world_cell_t* cell = get_cell(x, y);
                    //if (rand_int() % 2 == 0){
                    cell->light = rand_int() % 20;
                    
                    cell->water = 1;
                        //}
                    //cell->water = 0;
                    //go through all life forms and compete!
                    //printf("S: %dx%d\n", x, y);
                    life_compete(cell, cur_update);
                    //printf("F: %dx%d\n", x, y);
                }
            }
        }
       
        //signal that we are done
        pthread_barrier_wait(&compete_end);
    }
    
    //free the job
    free(jobs->jobs);
    free(jobs);
    return NULL;
}

//debugging function displays information about an instance
static void display_life(life_list_t* instance);

static void display_life(life_list_t* instance){

    printf("===Life Instance===\n");
    printf("\tSpecies: %p\n", instance);
    int key = get_key(instance);
    printf("\tName: %X\n", key);
    printf("\tHP: %d\n", get_element(&instance->instance_state, key ^ types[GENE_HP], rand_int() % MAX_HP));
    printf("\tMaxHP: %d\n", get_life_value_mod(instance, GENE_FOOD_SIZE, MAX_HP));
    printf("\tSpawn Fanout: %d\n", get_life_value_mod(instance, GENE_BREED_COUNT, 16));
    printf("\tSpawn Required HP: %d\n", get_life_value_mod(instance, GENE_BREED_HP, MAX_HP));
    printf("\tFood Type: %d\n", get_life_value_mod(instance, GENE_FOOD_TYPE, 4));
}
//create an instance on the life list
static life_list_t* init_instance(life_list_head_t* life_list){
    life_list_t* l = malloc(sizeof(life_list_t));
    l->parent_list = life_list;
    l->next = NULL;
    life_list->tail = l;
    life_list->list_size = 1;
    init_elements(&l->life_stats, 0);
    init_elements(&l->instance_state, 0);
    l->last_update = 0;
    assert(l->parent_list->tail != NULL);

    return l;
}

void init_life(world_cell_t* cell){
    //printf("%d, %d, %d\n", rand_int(), rand_int(), rand_int());
    static int count = 0;
    count++;
    life_list_head_t* life = &cell->life;
    if (0 == 0 || (cell->x == (WINDOW_WIDTH/8) && cell->y == (WINDOW_HEIGHT/8))){
        life->head = init_instance(life);
        cell->life.parent_cell = cell;
    } else {
        life->head = NULL;
        life->list_size = 0;
        life->tail = NULL;
    }

}

void init_global_life(void){
    char* rand_state = malloc(sizeof(char)*16);
    
    //init the random number generator
    FILE* fp = fopen("/dev/random", "r");
    int seed;
    fread(&seed, sizeof(int), 1, fp);
    initstate_r(seed, rand_state, 16, &rand_buf);
    fclose(fp);

    
    types = malloc(sizeof(int)*num_types);
    int i;
    for (i = 0; i < num_types; i++){
        types[i] = rand_int();
    }
    
    pthread_barrier_init(&compete_start, NULL, WORKER_THREADS + 1);
    pthread_barrier_init(&compete_end, NULL, WORKER_THREADS + 1);


    //need some worker threads
    workers = malloc(sizeof(pthread_t)*WORKER_THREADS);
    for (i = 0; i < WORKER_THREADS; i++){
        life_compete_job_list_t* job = malloc(sizeof(life_compete_job_list_t));
        job->number_jobs = 1;
        job->jobs = malloc(sizeof(life_compete_job_t));
        job->jobs[0].x0 = 0;
        job->jobs[0].x1 = WINDOW_WIDTH;
        job->jobs[0].y0 = (i*WINDOW_HEIGHT)/WORKER_THREADS;
        job->jobs[0].y1 = ((i+1)*WINDOW_HEIGHT)/WORKER_THREADS;
        
        printf("Job: %dx%d-%dx%d\n", job->jobs[0].x0, job->jobs[0].y0, job->jobs[0].x1, job->jobs[0].y1);

        //init all the mutexes for this job
        int j;
        pthread_mutexattr_t mutexattr;
        pthread_mutexattr_init(&mutexattr);
        pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK);
        //everything on the x0 and x1-1 line
        for (j = 0; j < WINDOW_HEIGHT; j++){
            world_cell_t* cell = get_cell(job->jobs[0].x0, j);
            if (cell->lock == NULL){
                cell->lock = malloc(sizeof(pthread_mutex_t));
                pthread_mutex_init(cell->lock, NULL);
            }
            cell = get_cell(job->jobs[0].x1 - 1, j);
            if (cell->lock == NULL){
                cell->lock = malloc(sizeof(pthread_mutex_t));
                pthread_mutex_init(cell->lock, NULL);
            }
        }
        //everything on the y0 and y1-1 line
        for (j = 0; j < WINDOW_WIDTH; j++){
            world_cell_t* cell = get_cell(j, job->jobs[0].y0);
            if (cell->lock == NULL){
                cell->lock = malloc(sizeof(pthread_mutex_t));
                pthread_mutex_init(cell->lock, NULL);
            }
            cell = get_cell(j, job->jobs[0].y1 - 1);
            if (cell->lock == NULL){
                cell->lock = malloc(sizeof(pthread_mutex_t));
                pthread_mutex_init(cell->lock, NULL);
            }
        }
        
        pthread_create(&workers[i], NULL, worker_compete, (void*)job);
        pthread_mutexattr_destroy(&mutexattr);
    }

}


void remove_life(life_list_t* instance){
    
    remove_from_list(instance);
    
    //actually destroy the data
    destroy_elements(&instance->life_stats);
    destroy_elements(&instance->instance_state);
    free(instance);
}


life_list_t* get_next_instance(life_list_head_t* life_list, life_list_t** state){
    if (*state == NULL){
        *state = life_list->head;
    } else {
        *state = (*state)->next;
    }
    return *state;
}


//get the color of something
Uint8 get_color_r(life_list_t* instance){
    Uint8 col = get_element(&instance->life_stats,
                       get_key(instance) ^ types[GENE_COLOR_R],
                       rand()) % 256;
    //printf("%d\n", (int)col);
    return col;
}


Uint8 get_color_g(life_list_t* instance){
    return get_element(&instance->life_stats,
                       get_key(instance) ^ types[GENE_COLOR_G],
                       rand()) % 256;
}
Uint8 get_color_b(life_list_t* instance){
    return get_element(&instance->life_stats,
                       get_key(instance) ^ types[GENE_COLOR_B],
                       rand()) % 256;
}


int life_compete(world_cell_t* cell, unsigned int update_num){
    life_list_t* next_life;
    life_list_t* life_instance;
    int life_count = 0;

    if (cell->life.head != NULL){
        //printf("Found Life @ %dx%d\n", cell->x, cell->y);
        //printf("\tLight Avaible %d\n", cell->light);
    }
    lock_cell(cell);
    life_instance = cell->life.head;
    while (life_instance != NULL){
        assert(life_instance->parent_list == &cell->life);
        assert(life_instance->parent_list->tail != NULL);
        assert(life_instance->parent_list->head != NULL);
        assert(life_instance->parent_list->parent_cell == cell);
        next_life = life_instance->next;
        life_count++;
        if (life_instance->last_update >= update_num){
            life_instance = next_life;
            continue;
        }
        life_instance->last_update = update_num;
        //display_life(life_instance);
        //printf("HP1: %d\n",  get_element(&life_instance->instance_state,
        //                                 get_key(life_instance) ^ types[GENE_HP],
        //                                 MAX_HP - 1));
        life_feed(cell, life_instance);
        //printf("HP2: %d\n",  get_element(&life_instance->instance_state,
        //                                 get_key(life_instance) ^ types[GENE_HP],
        //                                 MAX_HP - 1));
        life_react(cell, life_instance);
        if (life_age(cell, life_instance)){
            life_instance = next_life;
            continue;
        }
        life_spawn(cell, life_instance);
        //printf("HP3: %d\n",  get_element(&life_instance->instance_state,
        //                                 get_key(life_instance) ^ types[GENE_HP],
        //                                 MAX_HP));

        //printf("HP4: %d\n",  get_element(&life_instance->instance_state,
        //                                 get_key(life_instance) ^ types[GENE_HP],
        //                                 MAX_HP));
        assert(life_instance->parent_list->parent_cell == cell);
        //things movement means you get two executions per cycle
        life_move(cell, life_instance);
        //we can't age it if it just moved out of our cell
        if (&cell->life == life_instance->parent_list){

        }
        
        life_instance = next_life;

    }
    unlock_cell(cell);
    //assert(life_count < 100);
    if (life_count > 50){
        //printf("%dx%d: %d objects in cell\n", cell->x, cell->y, life_count);
    }
    return life_count;
}

//look for things in the cell that we can eat
static void life_feed(world_cell_t* cell, life_list_t* instance){
    assert(instance->parent_list->head != NULL);
    assert(instance->parent_list->tail != NULL);
    int key = get_key(instance);
    int hp_change = 0;
    int hp;
    int food_size;
    life_list_t* search_state = NULL;
    life_list_t* target;
    int element, element_produced, strength;
    element_list_t* e;

    //make sure nothing has more than MAX_HP
    hp = get_element(&instance->instance_state,
                key ^ types[GENE_HP],
                     rand_int() % MAX_HP);
    if (hp > MAX_HP){
        hp = set_element(&instance->instance_state,
                    key ^ types[GENE_HP],
                    MAX_HP);
    }
    
    assert(instance->parent_list->head != NULL);
    assert(instance->parent_list->tail != NULL);
    //first everything needs water, they use it or die
    int water_change = get_life_value_mod(instance, GENE_WATER_EFF, 16) + 1;
    assert(instance->parent_list->head != NULL);
    assert(instance->parent_list->tail != NULL);
    if (cell->water < water_change){
        water_change = cell->water;
        cell->water = 0;
    } else {
        cell->water -= water_change;
    }
    assert(cell->water >= 0);
    assert(cell->light >= 0);
    assert(instance->parent_list->head != NULL);
    assert(instance->parent_list->tail != NULL);
    water_change -= get_life_value_mod(instance, GENE_WATER_USE, 16) + 1;
    assert(instance->parent_list->head != NULL);
    assert(instance->parent_list->tail != NULL);
    
    water_change = add_element_max(&instance->instance_state,
                                   key ^ types[GENE_WATER_NEEDS],
                                   water_change, get_life_value_mod(instance, GENE_WATER_NEEDS, 1024));
    assert(instance->parent_list->head != NULL);
    assert(instance->parent_list->tail != NULL);
    //if we are dehydrated, well it sucks
    
    if (water_change < 0){
        water_change *= (get_life_value_mod(instance, GENE_NO_WATER, 16) + 1);
        assert(water_change < 0);
        //printf("Removing HP due to lack of water!\n");
        hp = add_element_max(&instance->instance_state,
                             key ^ types[GENE_HP],
                            water_change, get_life_value_mod(instance, GENE_HP, MAX_HP));
    }
    
    assert(instance->parent_list->head != NULL);
    assert(instance->parent_list->tail != NULL);
    switch (get_life_value_mod(instance, GENE_FOOD_TYPE, 4)){
    case 0: //light
        //light that can be consumed
        hp_change = get_life_value_mod(instance, GENE_FOOD_SIZE, MAX_HP);
        
        if (cell->light < hp_change){
            hp_change = cell->light;
            cell->light = 0;
        } else {
            cell->light -= hp_change;
        }
        
        hp_change *= get_life_value_mod(instance, GENE_LIGHT_EFF, 4);
        //printf("\tI eat light, and will add %d to my hp\n", hp_change);
        hp = add_element_max(&instance->instance_state,
                        key ^ types[GENE_HP],
                        hp_change, get_life_value_mod(instance, GENE_HP, MAX_HP));
        assert(instance->parent_list->head != NULL);
        assert(instance->parent_list->tail != NULL);
        break;
        
    case 1://other life, smaller than us
        search_state = NULL;

        while ((target = get_next_instance(&cell->life, &search_state)) != NULL){
            if (target != instance && get_key(target) != key){
                int target_hp = get_element(&target->instance_state, get_key(target) ^ types[GENE_HP], rand_int() % MAX_HP);
                if (hp > target_hp && target_hp < get_life_value_mod(instance, GENE_FOOD_SIZE, MAX_HP) && target_hp > 0){
                    //we can eat this, all of it
                    set_element(&target->instance_state, get_key(target) ^ types[GENE_HP], - MAX_HP);//reduce its HP to zero, this will kill it when it ages
                    hp = add_element_max(&instance->instance_state,
                                         key ^ types[GENE_HP],
                                         target_hp, get_life_value_mod(instance, GENE_FOOD_SIZE, MAX_HP));
                    //printf("Eating someone\n");
                    break;
                }
                
            }
        }
        assert(instance->parent_list->head != NULL);
        assert(instance->parent_list->tail != NULL);
        break;
    case 2://other life, larger than us
        search_state = NULL;
        food_size = get_life_value_mod(instance, GENE_FOOD_SIZE, MAX_HP);
        while (food_size > 0 && (target = get_next_instance(&cell->life, &search_state)) != NULL){
            if (target != instance && get_key(target) != key){
                int target_hp = get_element(&target->instance_state, get_key(target) ^ types[GENE_HP], rand_int() % MAX_HP);

                if (hp < target_hp && target_hp > 0 && target_hp > food_size && hp > 0){
                    //printf("Biting someone!\n");
                    //we can eat this
                    //display_life(target);
                    //printf("Our HP? %d\n", hp);
                    //display_life(instance);
                    assert(food_size > 0);
                    add_element_max(&target->instance_state, get_key(target) ^ types[GENE_HP], -food_size, MAX_HP);//reduce its HP to zero, this will kill it when it ages
                    hp = add_element_max(&instance->instance_state,
                                         key ^ types[GENE_HP],
                                         food_size - 1, get_life_value_mod(instance, GENE_FOOD_SIZE, MAX_HP));

                    break;
                }
            }
            
        }
        assert(instance->parent_list->head != NULL);
        assert(instance->parent_list->tail != NULL);
        break;
    default:
    case 3://elements
        //printf("I need an element\n");
        element = get_element(&instance->life_stats, (key ^ types[GENE_ELEMENT]) + 1, rand_int());
        element_produced = get_element(&instance->life_stats, key ^ types[GENE_ELEMENT], rand_int());
        strength = get_element(&instance->life_stats, element, rand_int() % 32);
        //edible elements are mod 16 of our element
        e = cell->elements.head;
        while (strength > 0 && e != NULL){
            //can't eat stuff we produced
            if (e->key > element_produced && (e->key + element) % 16 == 0 && e->value > 0){
                if (e->value > strength){
                    e->value -= strength;
                } else {
                    strength = e->value;
                    e->value = 0;
                }
                hp = add_element_max(&instance->instance_state,
                                     key ^ types[GENE_HP],
                                     strength, get_life_value_mod(instance, GENE_FOOD_SIZE, MAX_HP));
                break;

            }
            e = e->next;
        }
        assert(instance->parent_list->head != NULL);
        assert(instance->parent_list->tail != NULL);
        break;
    }


}

int get_life_value_mod(life_list_t* instance, int gene, int mod){
    assert(instance->parent_list->head != NULL);
    assert(instance->parent_list->tail != NULL);
    int r =  get_element(&instance->life_stats, get_key(instance) ^ types[gene], rand_int())
        % mod;
    assert(instance->parent_list->head != NULL);
    assert(instance->parent_list->tail != NULL);
    return r;

}

static int life_age(world_cell_t* cell, life_list_t* instance){
    int hp_needed;

    hp_needed = get_life_value_mod(instance, GENE_HP_USE, MAX_HP);
    if (hp_needed >= 0){
        hp_needed++;
        hp_needed *= -1;
    }
    hp_needed -= 10;
    assert(hp_needed < 0);
    //printf("\tAgeing, adding %d to my hp\n", hp_needed);
    hp_needed = add_element_max(&instance->instance_state,
                                get_key(instance) ^ types[GENE_HP],
                                hp_needed, get_life_value_mod(instance, GENE_FOOD_SIZE, MAX_HP));
    if (hp_needed < 0){
        remove_life(instance);
        return 1;
    }

    //sanity checks
    //kill if it can't spawn
    if (get_life_value_mod(instance, GENE_FOOD_SIZE, MAX_HP) < get_life_value_mod(instance, GENE_BREED_HP, MAX_HP)){
        remove_life(instance);
        return 1;
    }

    if (get_life_value_mod(instance, GENE_BREED_COUNT, 3) == 0){
        remove_life(instance);
        return 1;
    }
    if (instance->parent_list->head == NULL || instance->parent_list->tail == NULL){
        //printf("Cell %dx%d is now empty\n", cell->x, cell->y);
    }
    return 0;
}

static void life_spawn(world_cell_t* cell, life_list_t* instance){
    assert(instance->parent_list->head != NULL);
    assert(instance->parent_list->tail != NULL);

    int key = get_key(instance); 
    int hp = get_element(&instance->instance_state,
                         key ^ types[GENE_HP],
                         rand_int() % MAX_HP);
    int required_hp = get_life_value_mod(instance, GENE_BREED_HP, MAX_HP);
    int breed_count = get_life_value_mod(instance, GENE_BREED_COUNT, 3);
    int final_hp = 0;
    if (hp > required_hp && required_hp > 0 && breed_count > 0){
        //we can breed
        int parent_hp = add_element_max(&instance->instance_state, key ^ types[GENE_HP], -1*required_hp - 1, get_life_value_mod(instance, GENE_FOOD_SIZE, MAX_HP));
        final_hp += parent_hp;
        int i;
        for (i = 0; i < breed_count; i++){
            life_list_t* child = life_copy(instance);
            //printf("=======My Child========\n");
            //display_life(child);
            int child_hp = set_element(&child->instance_state,
                                       key ^ types[GENE_HP], required_hp/breed_count - 1);
            //printf("%dx%d: Parent(%p): %d->%d Child(%p) %d, Required: %d Breed Count: %d Food: %d\n", cell->x, cell->y, (void*)instance, hp, parent_hp, (void*)child, child_hp, required_hp, breed_count, get_life_value_mod(instance, GENE_FOOD_TYPE, 4));
            //display_life(child);
            fuzz_elements(&child->instance_state);
            fuzz_elements(&child->life_stats);

            final_hp += child_hp;
        }
        assert(final_hp < hp);
    }

}

static life_list_t* life_copy(life_list_t* instance){
    assert(instance->parent_list->tail != NULL);
    life_list_t* l = instance->parent_list->tail->next;
    l = malloc(sizeof(life_list_t));
    instance->parent_list->tail->next = l;
    instance->parent_list->tail = l;
    l->next = NULL;
    l->parent_list = instance->parent_list;
    l->parent_list->list_size++;
    l->last_update = instance->last_update;
    //things get fuzzed, don't keep too much old stuff
    init_elements(&l->life_stats, 32);
    init_elements(&l->instance_state, 32);
    
    copy_element_list(&l->life_stats, &instance->life_stats);
    copy_element_list(&l->instance_state, &instance->instance_state);    
    return l;
}


static void life_move(world_cell_t* cell, life_list_t* instance){
    int x = cell->x - 1;
    int y = cell->y - 1; 
    world_cell_t* new_cell;
    if (get_element(&instance->life_stats, get_key(instance) ^ types[GENE_MOVE], rand_int()) < rand_int()){
        //we are moving
        //printf("Moving!\n");
        x += rand_int() % 3;
        y += rand_int() % 3;
        if (x > 0 && y > 0 && x < WINDOW_WIDTH && y < WINDOW_HEIGHT){
            new_cell = get_cell(x, y);
            if (new_cell != cell){
                //lock the cells
                if ((new_cell->x*WINDOW_WIDTH + new_cell->y) > (cell->x*WINDOW_WIDTH + cell->y)){
                    //printf("Cell Unlocked!\n");
                    unlock_cell(cell);
                    lock_cell(new_cell);
                    lock_cell(cell);
                    //printf("Cell locked!\n");
                    //verify that nobody came in and moved us!
                    if (instance->parent_list != &cell->life){
                        //printf("Aborting move, we got interrupted!\n");
                        return;
                    }
                } else {
                    lock_cell(new_cell);
                }
                assert(instance->parent_list == &cell->life);
                //printf("M: %dx%d -> %dx%d (%d)\n", cell->x, cell->y, new_cell->x, new_cell->y, (int)pthread_self());
                life_move_l(&new_cell->life, instance);
                unlock_cell(new_cell);
            }
        }
    }
    return;
}

static void life_move_l(life_list_head_t* dst_list, life_list_t* instance){
    assert((dst_list->head != NULL && dst_list->tail != NULL) ||
           (dst_list->head == NULL && dst_list->tail == NULL));
    assert(dst_list != instance->parent_list);
    remove_from_list(instance);
    //add to the tail
    dst_list->list_size++;
    if (dst_list->tail != NULL){
        dst_list->tail->next = instance;
    }
    dst_list->tail = instance;


    if (dst_list->head == NULL){
        dst_list->head = instance;
    }


    //adjust its known location
    instance->parent_list = dst_list;
    instance->next = NULL;
    assert(dst_list->list_size > 0);
    assert(dst_list->head != NULL);
    assert(dst_list->tail != NULL);
}


static void remove_from_list(life_list_t* instance){
    //assert(instance->parent_list->list_size == 1);
    assert(instance->parent_list->tail != NULL);
    assert((instance->parent_list->head != NULL && instance->parent_list->tail != NULL) ||
           (instance->parent_list->head == NULL && instance->parent_list->tail == NULL));
    life_list_t* l = instance->parent_list->head;
    life_list_t* prev = NULL;

    if (instance->parent_list->head != instance){
        while (l != NULL){

            if (l == instance){
                //found it
                prev->next = l->next;
                break;
            }
            prev = l;
            l = l->next;
        }
    if (instance->parent_list->tail == instance){

        instance->parent_list->tail = prev;
        
    }
    } else {
        instance->parent_list->head = instance->next;
        if (instance->parent_list->tail == instance){
            instance->parent_list->tail = NULL;
        }
    }

    
    instance->parent_list->list_size--;
    if (instance->parent_list->head == NULL){
        //printf("Cell %dx%d is now empty (%d)\n", instance->parent_list->parent_cell->x, instance->parent_list->parent_cell->y, (int)pthread_self());
    }
    assert((instance->parent_list->head != NULL && instance->parent_list->tail != NULL) ||
           (instance->parent_list->head == NULL && instance->parent_list->tail == NULL));
    assert(instance->parent_list->tail != NULL || instance->parent_list->list_size == 0);
}


static void life_react(world_cell_t* cell, life_list_t* instance){
    //first produce our own
    int key = get_key(instance);
    int element = get_element(&instance->life_stats, key ^ types[GENE_ELEMENT], rand_int());
    int strength = get_element(&instance->life_stats, element, rand_int() % 32) - 16;
    add_element(&cell->elements, element, strength);

    element_list_t* el = cell->elements.head;
    while (el != NULL){
        if (((el->key - get_element(&instance->life_stats, key ^ types[GENE_ELEMENT_HARM], rand_int() % 32)) % 32 ) < 16){
            if (el->value > 0){
                el->value *= -1;
            }
            //this is going to effect us
            add_element_max(&instance->instance_state, key ^ types[GENE_HP], el->value, MAX_HP);
            el->value = 0;
        }
        
        el = el->next;
    }
}

void wait_for_compete(void){
    pthread_barrier_wait(&compete_start);
    pthread_barrier_wait(&compete_end);//wait for threads
}


static void lock_cell(world_cell_t* cell){
    if (cell->lock != NULL){
        //printf("locking %dx%d\n", cell->x, cell->y);
        pthread_mutex_lock(cell->lock);
    }
}

static void unlock_cell(world_cell_t* cell){
    if (cell->lock != NULL){
        //printf("unlocking %dx%d\n", cell->x, cell->y);
        pthread_mutex_unlock(cell->lock);
    }
}
