/*
 * Mr. 4th Dimention - Allen Webster
 *
 * 12.17.2014
 *
 * Rendering layer for project codename "4ed"
 *
 */

// TOP

inline void
draw_push_clip(Render_Target *target, i32_Rect clip_box){
    target->push_clip(target, clip_box);
}

inline i32_Rect
draw_pop_clip(Render_Target *target){
    i32_Rect result = target->pop_clip(target);
    return(result);
}

inline void
draw_change_clip(Render_Target *target, i32_Rect clip_box){
    target->pop_clip(target);
    target->push_clip(target, clip_box);
}

internal void
begin_render_section(Render_Target *target, System_Functions *system){
    target->size = 0;
    target->clip_top = -1;
    
    i32_Rect clip;
    clip.x0 = 0;
    clip.y0 = 0;
    clip.x1 = target->width;
    clip.y1 = target->height;
    draw_push_clip(target, clip);
}

internal void
end_render_section(Render_Target *target, System_Functions *system){
    Assert(target->clip_top == 0);
}

internal void
draw_rectangle(Render_Target *target, i32_Rect rect, u32 color){
    Render_Piece_Combined piece;
    piece.header.type = piece_type_rectangle;
    piece.rectangle.rect = f32R(rect);
    piece.rectangle.color = color;
    target->push_piece(target, piece);
}

internal void
draw_rectangle(Render_Target *target, f32_Rect rect, u32 color){
    Render_Piece_Combined piece;
    piece.header.type = piece_type_rectangle;
    piece.rectangle.rect = rect;
    piece.rectangle.color = color;
    target->push_piece(target, piece);
}

internal void
draw_gradient_2corner_clipped(Render_Target *target, f32_Rect rect,
                              Vec4 left_color, Vec4 right_color){
    Render_Piece_Combined piece;
    piece.header.type = piece_type_gradient;
    piece.gradient.rect = rect;
    piece.gradient.left_color = pack_color4(left_color);
    piece.gradient.right_color = pack_color4(right_color);
    target->push_piece(target, piece);
}

inline void
draw_gradient_2corner_clipped(Render_Target *target, f32 l, f32 t, f32 r, f32 b,
                              Vec4 color_left, Vec4 color_right){
    draw_gradient_2corner_clipped(target, f32R(l,t,r,b), color_left, color_right);
}

internal void
draw_rectangle_outline(Render_Target *target, f32_Rect rect, u32 color){
    Render_Piece_Combined piece;
    piece.header.type = piece_type_outline;
    piece.rectangle.rect = rect;
    piece.rectangle.color = color;
    target->push_piece(target, piece);
}

inline void
draw_rectangle_outline(Render_Target *target, i32_Rect rect, u32 color){
    draw_rectangle_outline(target, f32R(rect), color);
}

internal void
draw_margin(Render_Target *target, i32_Rect outer, i32_Rect inner, u32 color){
    draw_rectangle(target, i32R(outer.x0, outer.y0, outer.x1, inner.y0), color);
    draw_rectangle(target, i32R(outer.x0, inner.y1, outer.x1, outer.y1), color);
    draw_rectangle(target, i32R(outer.x0, inner.y0, inner.x0, inner.y1), color);
    draw_rectangle(target, i32R(inner.x1, inner.y0, outer.x1, inner.y1), color);
}

inline void
draw_margin(Render_Target *target, i32_Rect outer, i32 width, u32 color){
    i32_Rect inner = get_inner_rect(outer, width);
    draw_margin(target, outer, inner, color);
}

inline internal i32
font_predict_size(i32 pt_size){
    return pt_size*pt_size*128;
}

internal void
font_draw_glyph(Render_Target *target, Font_ID font_id, i32 type, u32 codepoint, f32 x, f32 y, u32 color){
    Render_Piece_Combined piece;
    piece.header.type = type;
    piece.glyph.pos.x = x;
    piece.glyph.pos.y = y;
    piece.glyph.color = color;
    piece.glyph.font_id = font_id;
    piece.glyph.codepoint = codepoint;
    target->push_piece(target, piece);
}

internal void
font_draw_glyph(Render_Target *target, Font_ID font_id, u32 codepoint, f32 x, f32 y, u32 color){
    font_draw_glyph(target, font_id, piece_type_glyph, codepoint, x, y, color);
}

internal f32
draw_string_base(System_Functions *system, Render_Target *target, Font_ID font_id, i32 type, String str_, i32 x_, i32 y_, u32 color){
    f32 x = 0;
    
    Render_Font *font = system->font.get_render_data_by_id(font_id);
    if (font != 0){
        f32 y = (f32)y_;
        x = (f32)x_;
        
        f32 byte_advance = font_get_byte_advance(font);
        f32 *sub_advances = font_get_byte_sub_advances(font);
        
        u8 *str = (u8*)str_.str;
        u8 *str_end = str + str_.size;
        
        Translation_State tran = {0};
        Translation_Emits emits = {0};
        
        for (u32 i = 0; str < str_end; ++str, ++i){
            translating_fully_process_byte(system, font, &tran, *str, i, str_.size, &emits);
            
            for (TRANSLATION_DECL_EMIT_LOOP(J, emits)){
                TRANSLATION_DECL_GET_STEP(step, behavior, J, emits);
                
                if (behavior.do_codepoint_advance){
                    u32 codepoint = step.value;
                    if (color != 0){
                        font_draw_glyph(target, font_id, type, codepoint, x, y, color);
                    }
                    x += font_get_glyph_advance(system, font, codepoint);
                }
                else if (behavior.do_number_advance){
                    u8 n = (u8)(step.value);
                    if (color != 0){
                        u8 cs[3];
                        cs[0] = '\\';
                        byte_to_ascii(n, cs+1);
                        
                        f32 xx = x;
                        for (u32 j = 0; j < 3; ++j){
                            font_draw_glyph(target, font_id, type, cs[j], xx, y, color);
                            xx += sub_advances[j];
                        }
                    }
                    x += byte_advance;
                }
            }
        }
        
#if 0
        for (;str < str_end;){
            u8 *byte = str;
            u32 codepoint = utf8_to_u32(&str, str_end);
            
            b32 do_codepoint = false;
            b32 do_numbers = false;
            if (codepoint){
                if (codepoint >= ' ' && codepoint <= 0xFF && codepoint != 127){
                    do_codepoint = true;
                }
                else{
                    do_numbers = true;
                }
            }
            else{
                do_numbers = true;
            }
            
            if (do_codepoint){
                if (color != 0){
                    font_draw_glyph(target, font_id, type, (u8)codepoint, x, y, color);
                }
                x += font_get_glyph_advance(system, font, codepoint);
            }
            else if (do_numbers){
                for (;byte < str; ++byte){
                    u8_4tech n = *byte;
                    if (color != 0){
                        u8 cs[3];
                        cs[0] = '\\';
                        byte_to_ascii(n, cs+1);
                        
                        f32 *advances = font_get_byte_sub_advances(font);
                        
                        f32 xx = x;
                        for (u32 j = 0; j < 3; ++j){
                            font_draw_glyph(target, font_id, type, cs[j], xx, y, color);
                            xx += advances[j];
                        }
                    }
                    
                    x += byte_advance;
                }
            }
        }
#endif
    }
    
    return(x);
}

internal f32
draw_string(System_Functions *system, Render_Target *target, Font_ID font_id, String str, i32 x, i32 y, u32 color){
    f32 w = draw_string_base(system, target, font_id, piece_type_glyph, str, x, y, color);
    return(w);
}

internal f32
draw_string(System_Functions *system, Render_Target *target, Font_ID font_id, char *str, i32 x, i32 y, u32 color){
    String string = make_string_slowly(str);
    f32 w = draw_string_base(system, target, font_id, piece_type_glyph, string, x, y, color);
    return(w);
}

internal f32
draw_string_mono(System_Functions *system, Render_Target *target, Font_ID font_id, String str, i32 x, i32 y, f32 advance, u32 color){
    f32 w = draw_string_base(system, target, font_id, piece_type_mono_glyph, str, x, y, color);
    return(w);
}

internal f32
draw_string_mono(System_Functions *system, Render_Target *target, Font_ID font_id, char *str, i32 x, i32 y, f32 advance, u32 color){
    String string = make_string_slowly(str);
    f32 w = draw_string_base(system, target, font_id, piece_type_mono_glyph, string, x, y, color);
    return(w);
}

internal f32
font_string_width(System_Functions *system, Render_Target *target, Font_ID font_id, String str){
    f32 w = draw_string_base(system, target, font_id, piece_type_glyph, str, 0, 0, 0);
    return(w);
}

internal f32
font_string_width(System_Functions *system, Render_Target *target, Font_ID font_id, char *str){
    String string = make_string_slowly(str);
    f32 w = draw_string_base(system, target, font_id, piece_type_glyph, string, 0, 0, 0);
    return(w);
}

// BOTTOM