/*
    Robot Interface
    (C) 2006 Jason Hunt
    nulluser@gmail.com
    
    File: display.cpp
*/

#include <windows.h>
#include <stdio.h>

#include "display.h"
#include "types.h"
#include "robot.h"
#include "input.h"
#include "camera.h"

unsigned int display_x = 600;             // Initial screen size
unsigned int display_y = 400;


HDC memdc = NULL;	           	           // Memory device context
HBITMAP h_mem_bitmap = NULL;                // Offscreen bitmap

CRITICAL_SECTION text_lock;     // Lock for update speed
   

static char text_area[text_row][MAX_LINE];  // The data for text display

       
void display_start( void )
{
    InitializeCriticalSection(&text_lock);        
}       
       

/* Adds a line to the text buffer */
void add_line(char *line)
{    
    EnterCriticalSection(&text_lock);

    static bool text_clear = false;

    if (!text_clear)
    {
        memset(text_area, 0, text_row * MAX_LINE);
        text_clear = true;
    }

    static unsigned int text_y = 0; 

    // Scrool the display up
    if (text_y == text_row)
    {
        for (int i = 1; i < text_row; i++)
            memcpy(text_area[i-1], text_area[i], MAX_LINE);
    }
    else
        text_y ++;

    // Copy the string
    unsigned int line_len = strlen(line);

    strncpy(text_area[text_y - 1], line, MAX_LINE);
    
    LeaveCriticalSection(&text_lock);    
}
/* End of add line */



/* Copy offscreen buffer to display */
void do_paint(HWND hwnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);
    BitBlt(hdc, 0, 0, display_x, display_y, memdc, 0, 0, SRCCOPY);
    EndPaint(hwnd, &ps);  
}
/* End of do_paint */


/* Draw a bar graph bounded by the two cords */
void draw_bar_graph(unsigned int x1, unsigned int y1, 
                    unsigned int x2, unsigned int y2, double size, unsigned long color)
{
    // Scale sonar into display
    unsigned int draw_size = (unsigned int)((y2 - y1) * (1-size));

    if (size > y2-y1) size = y2-y1;

    HBRUSH color1 = CreateSolidBrush(RGB(150, 150, 150));
    HBRUSH color2 = CreateSolidBrush(color);

    RECT r;

    r.left = x1;
    r.right = x2;

    r.top = y1;
    r.bottom = y1 + draw_size;

    FillRect(memdc, &r,color1);

    r.top = y1 + draw_size;
    r.bottom = y2;

    FillRect(memdc, &r,color2);
    
    DeleteObject(color1);
    DeleteObject(color2);    
}
/* End of draw_bar_graph */





/* Draw motor bar graphs and lables at positon */
void draw_control(unsigned int x, unsigned int y, control_type c)
{
    unsigned int l_color = RGB(0, 0, 255);
    unsigned int r_color = RGB(0, 0, 255);

    if (c.left_motor_dir) l_color = RGB(255, 0, 0);
    if (c.right_motor_dir) r_color = RGB(255, 0, 0);
    
    char b[400];
    sprintf(b, "Motor Target");
    TextOut(memdc,  x, y, b, strlen(b));        
     
    draw_bar_graph(x, y+20, x+35, y+120, c.left_motor_speed / 255.0, l_color);
    draw_bar_graph(x+40, y+20, x+40+35, y+120, c.right_motor_speed / 255.0, r_color);

    sprintf(b, "%3.0f", c.left_motor_target);
    TextOut(memdc, x, y+120, b, strlen(b));

    sprintf(b, "%3.0f", c.right_motor_target);
    TextOut(memdc, x+40,y+120, b, strlen(b));
}
/* End of draw_motor_info */


/* Draw graphs and data fro telemetry */
void draw_telemetry(unsigned int x, unsigned int y, telemetry_type t)
{
    // Bar graph parameters
    unsigned int slice_width = 40;
    unsigned int bar_width = 35;
    unsigned int base_x = x;

    unsigned int start_y = y+20;
    unsigned int y_size = 100;


    char b[300];
    sprintf(b, "Analog Data");
    TextOut(memdc,  x, y, b, strlen(b));        
   

    // Draw graphs for analog
    for (int i = 0; i < 8; i++)
    {
        draw_bar_graph(base_x + i*slice_width,  start_y,
                       base_x+bar_width+i*slice_width, 
                       start_y+y_size, 
                       t.analog_data[i]/1024.0, RGB(0,0,255));

        sprintf(b, "%4d ", t.analog_data[i]);
        TextOut(memdc, base_x + i*slice_width, start_y + y_size, b, strlen(b));
    }
}
/* End of draw_telemetry */


/* Update display */
void update_display(HWND hwnd)
{
    telemetry_type t;
    control_type c;
    
    robot.get_control(&c);
    robot.get_telemetry(&t);

    SelectObject(memdc, (HBRUSH) GetStockObject(WHITE_BRUSH));
    SelectObject(memdc, (HBRUSH) GetStockObject(WHITE_PEN));    
   
    RECT r;

    GetClientRect(hwnd, &r);

    // Clear old offscreen buffer
    Rectangle(memdc, r.left, r.top, r.right, r.bottom);

    char b[400];    

    sprintf(b, "Serial Rate %3.0f ", robot.get_update_speed());
    TextOut(memdc, 1, 1, b, strlen(b));

    sprintf(b, "Camera Rate %3d ",  camera.get_update_rate());
    TextOut(memdc, 1, 20, b, strlen(b));

//    sprintf(b, "Motion time %4.2f ", motion_time);
//    TextOut(memdc, 1, 40, b, strlen(b));

    if (remote_mode)
        strcpy(b, "Remote mode");
    else
        strcpy(b, "Local mode");

     TextOut(memdc, 0, 40, b, strlen(b));


    if (robot.get_auto_mode())
        strcpy(b, "Auto mode");
    else
        strcpy(b, "Manual mode");

     TextOut(memdc, 0, 60, b, strlen(b));



    // Draw Sensors
    draw_telemetry(260, 0,  t);

    // Draw control data
    draw_control(160, 0, c);

    unsigned int text_height = font_y_size * text_row;

    SelectObject(memdc, (HBRUSH) GetStockObject(BLACK_PEN));    

    // Clear the old text area
    Rectangle(memdc, 0, display_y -text_height, display_x, display_y );
        
        
    EnterCriticalSection(&text_lock);        
        
       // draw text lines
    for (unsigned int r = 0; r < text_row; r++)
        TextOut(memdc, 2, display_y -text_height + r * font_y_size + 1, text_area[r], strlen(text_area[r]));
        
        
    LeaveCriticalSection(&text_lock);        
}
/* End of update display */



/* Create off screen buffer */
void setup_display( HWND hwnd )
{
    // Get main DC
    HDC hdc = GetDC(hwnd);

  	// Create Memory device contextand bitmap
    memdc = CreateCompatibleDC(hdc);	

    // Create off screen buffer
  	h_mem_bitmap = CreateCompatibleBitmap(hdc, display_x, display_y);

  	// Select the off screen buffer into the DC
   	SelectObject(memdc, h_mem_bitmap);		

    ReleaseDC(hwnd, hdc);       // Main DC is no longer needed
}
/* End of setup_display */



/* Resize the display and update buffers */
void resize_display(HWND hwnd, LPARAM l)
{
    display_x = LOWORD(l);
    display_y = HIWORD(l);

    DeleteObject(h_mem_bitmap);		//	 Delete old screen buffer
    DeleteDC(memdc);		      	// Delete old memory DC

    setup_display(hwnd);

    InvalidateRect(hwnd, NULL, true);   
}
/* End of resize_display */









