The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#include "ppport.h"

#include "helper.h"

typedef struct SDLx_LayerManager
{
    AV          *layers;
    SDL_Surface *saveshot;
    SDL_Surface *dest;
    int          saved;
} SDLx_LayerManager;

typedef struct SDLx_Layer
{
    SDLx_LayerManager *manager;
    int                index;
    int                attached;
    int                touched;
    SDL_Surface       *surface;
    SDL_Rect          *clip;
    SDL_Rect          *pos;
    SDL_Rect          *attached_pos;
    SDL_Rect          *attached_rel;
    HV                *data;
} SDLx_Layer;

int intersection( SDLx_Layer *layer1, SDLx_Layer *layer2 )
{
    if(
        /* upper left point inside layer */
        (   layer1->pos->x <= layer2->pos->x
            && layer2->pos->x < layer1->pos->x + layer1->clip->w
            && layer1->pos->y <= layer2->pos->y
            && layer2->pos->y < layer1->pos->y + layer1->clip->h
        )

        /* upper right point inside layer */
        || (   layer1->pos->x < layer2->pos->x + layer2->clip->w
            && layer2->pos->x + layer2->clip->w <= layer1->pos->x + layer1->clip->w
            && layer1->pos->y <= layer2->pos->y
            && layer2->pos->y < layer1->pos->y + layer1->clip->h )

        /* lower left point inside layer */
        || (   layer1->pos->x <= layer2->pos->x
            && layer2->pos->x < layer1->pos->x + layer1->clip->w
            && layer1->pos->y < layer2->pos->y + layer2->clip->h
            && layer2->pos->y + layer2->clip->h <= layer1->pos->y + layer1->clip->h )

        /* lower right point inside layer */
        || (   layer1->pos->x < layer2->pos->x + layer2->clip->w
            && layer2->pos->x + layer2->clip->w <= layer1->pos->x + layer1->clip->w
            && layer1->pos->y < layer2->pos->y + layer2->clip->h
            && layer2->pos->y + layer2->clip->h <= layer1->pos->y + layer1->clip->h )
    ){
        return 1;
    }
    
    return 0;
}

AV *layers_behind( SDLx_Layer *layer)
{
    AV *matches = newAV();
    int i;
    int count = 0;

    for( i = layer->index - 1; i >= 0; i-- )
    {
        SV *bag            = *av_fetch(layer->manager->layers, i, 0);
        SDLx_Layer *layer2 = (SDLx_Layer *)bag2obj(bag);
        if(intersection( layer, layer2 ) || intersection( layer2, layer ))
        {
            /* TODO checking transparency */
            SvREFCNT_inc(bag);
            av_store( matches, count, bag );
            count++;
        }
    }
    
    if(count)
    {
        AV *behind = layers_behind((SDLx_Layer *)bag2obj(*av_fetch(matches, av_len(matches), 0)));
        if(av_len(behind) >= 0)
        {
            for( i = 0; i <= av_len(behind); i++ )
            {
                av_store( matches, count, *av_fetch(behind, i, 0));
                count++;
            }
        }
    }

    return matches;
}

AV *layers_ahead( SDLx_Layer *layer )
{
    AV *matches = newAV();
    int i;
    int count = 0;

    for( i = layer->index + 1; i <= av_len(layer->manager->layers); i++ )
    {
        SV *bag            = *av_fetch(layer->manager->layers, i, 0);
        SDLx_Layer *layer2 = (SDLx_Layer *)bag2obj(bag);
        if(intersection( layer, layer2 ) || intersection( layer2, layer ))
        {
            /* TODO checking transparency */
            SvREFCNT_inc(bag);
            av_store( matches, count, bag );
            count++;
        }
    }
    
    if(count)
    {
        AV *ahead = layers_ahead((SDLx_Layer *)bag2obj(*av_fetch(matches, av_len(matches), 0)));
        if(av_len(ahead) >= 0)
        {
            for( i = 0; i <= av_len(ahead); i++ )
            {
                av_store( matches, count, *av_fetch(ahead, i, 0));
                count++;
            }
        }
    }
    
    return matches;
}