/*
4coder_layout.cpp - Implementation of basic lookup routines on line layout data.
*/

// TOP

internal i64
layout_nearest_pos_to_xy(Layout_Item_List list, Vec2_f32 p){
    i64 closest_match = 0;
    if (p.y < 0.f){
        closest_match = list.manifested_index_range.min;
    }
    else if (p.y >= list.height){
        closest_match = list.manifested_index_range.max;
    }
    else{
        if (0.f < p.x && p.x < max_f32){
            f32 closest_x = -max_f32;
            for (Layout_Item_Block *block = list.first;
                 block != 0;
                 block = block->next){
                i64 count = block->item_count;
                Layout_Item *item = block->items;
                for (i32 i = 0; i < count; i += 1, item += 1){
                    if (HasFlag(item->flags, LayoutItemFlag_Ghost_Character)){
                        continue;
                    }
                    // NOTE(allen): This only works if we build layouts in y-sorted order.
                    if (p.y < item->rect.y0){
                        goto double_break;
                    }
                    if (item->padded_y1 <= p.y){
                        continue;
                    }
                    f32 dist0 = p.x - item->rect.x0;
                    f32 dist1 = item->rect.x1 - p.x;
                    if (dist0 >= 0.f && dist1 > 0.f){
                        closest_match = item->index;
                        goto double_break;
                    }
                    // NOTE(allen): One of dist0 and dist1 are negative, but certainly not both.
                    // 1. Take the negative one.
                    // 2. If the negative distance is larger than closest_x, then this is closer.
                    f32 neg_dist = Min(dist0, dist1);
                    if (closest_x < neg_dist){
                        closest_x = neg_dist;
                        closest_match = item->index;
                    }
                }
            }
            double_break:;
        }
        else{
            
            if (p.x == max_f32){
                Layout_Item *prev_item = 0;
                for (Layout_Item_Block *block = list.first;
                     block != 0;
                     block = block->next){
                    i64 count = block->item_count;
                    Layout_Item *item = block->items;
                    for (i32 i = 0; i < count; i += 1, item += 1){
                        if (HasFlag(item->flags, LayoutItemFlag_Ghost_Character)){
                            continue;
                        }
                        if (p.y < item->rect.y0){
                            goto double_break_2;
                        }
                        prev_item = item;
                        if (item->padded_y1 <= p.y){
                            continue;
                        }
                    }
                }
                
                double_break_2:;
                if (prev_item != 0){
                    closest_match = prev_item->index;
                }
                else{
                    closest_match = list.manifested_index_range.max;
                }
            }
            else{
                Layout_Item *closest_item = 0;
                for (Layout_Item_Block *block = list.first;
                     block != 0;
                     block = block->next){
                    i64 count = block->item_count;
                    Layout_Item *item = block->items;
                    for (i32 i = 0; i < count; i += 1, item += 1){
                        if (HasFlag(item->flags, LayoutItemFlag_Ghost_Character)){
                            continue;
                        }
                        // NOTE(allen): This only works if we build layouts in y-sorted order.
                        if (p.y < item->rect.y0){
                            goto double_break_3;
                        }
                        if (item->padded_y1 <= p.y){
                            continue;
                        }
                        closest_item = item;
                        goto double_break_3;
                    }
                }
                
                double_break_3:;
                if (closest_item != 0){
                    closest_match = closest_item->index;
                }
                else{
                    closest_match = list.manifested_index_range.min;
                }
            }
            
        }
    }
    return(closest_match);
}

internal Layout_Item*
layout_get_first_with_index(Layout_Item_List list, i64 index){
    Layout_Item *result = 0;
    Layout_Item *prev = 0;
    for (Layout_Item_Block *block = list.first;
         block != 0;
         block = block->next){
        i64 count = block->item_count;
        Layout_Item *item = block->items;
        for (i32 i = 0; i < count; i += 1, item += 1){
            if (HasFlag(item->flags, LayoutItemFlag_Ghost_Character)){
                continue;
            }
            if (item->index > index){
                result = prev;
                goto done;
            }
            if (item->index == index){
                result = item;
                goto done;
            }
            prev = item;
        }
    }
    if (result == 0){
        result = prev;
    }
    done:;
    return(result);
}

internal Rect_f32
layout_box_of_pos(Layout_Item_List list, i64 index){
    Rect_f32 result = {};
    Layout_Item *item = layout_get_first_with_index(list, index);
    if (item != 0){
        result = item->rect;
    }
    return(result);
}

function Rect_f32
layout_padded_box_of_pos(Layout_Item_List list, i64 index){
    Rect_f32 result = {};
    Layout_Item *item = layout_get_first_with_index(list, index);
    if (item != 0){
        result.x0 = item->rect.x0;
        result.y0 = item->rect.y0;
        result.x1 = item->rect.x1;
        result.y1 = item->padded_y1;
    }
    return(result);
}

internal i64
layout_get_pos_at_character(Layout_Item_List list, i64 character){
    i64 result = 0;
    if (character <= 0){
        result = list.manifested_index_range.min;
    }
    else if (character >= list.character_count){
        result = list.manifested_index_range.max;
    }
    else{
        i64 counter = 0;
        i64 next_counter = 0;
        for (Layout_Item_Block *node = list.first;
             node != 0;
             node = node->next, counter = next_counter){
            next_counter = counter + node->character_count;
            if (character >= next_counter){
                continue;
            }
            
            i64 count = node->item_count;
            i64 relative_character = character - counter;
            i64 relative_character_counter = 0;
            
            Layout_Item *item = node->items;
            for (i64 i = 0; i < count; i += 1, item += 1){
                if (HasFlag(item->flags, LayoutItemFlag_Ghost_Character)){
                    continue;
                }
                if (relative_character_counter == relative_character){
                    result = item->index;
                    break;
                }
                relative_character_counter += 1;
            }
            
            break;
        }
    }
    return(result);
}

internal i64
layout_character_from_pos(Layout_Item_List list, i64 index){
    i64 result = 0;
    i64 prev_index = -1;
    if (index <= list.manifested_index_range.first){
        result = 0;
    }
    else if (index > list.manifested_index_range.one_past_last){
        result = list.character_count - 1;
    }
    else{
        for (Layout_Item_Block *node = list.first;
             node != 0;
             node = node->next){
            Layout_Item *item = node->items;
            i64 count = node->item_count;
            for (i64 i = 0; i < count; i += 1, item += 1){
                if (item->index >= index){
                    goto double_break;
                }
                if (item->index > prev_index){
                    prev_index = item->index;
                    result += 1;
                }
            }
        }
    }
    double_break:;
    return(result);
}

// BOTTOM