/* 
    Robot Simulator

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    (C) 2006 Jason Hunt
    nulluser@gmail.gom 
*/

#include <windows.h>

#include <stdio.h>
#include <time.h>

#include "resource.h"
#include "main.h"
#include "display.h"
#include "console.h"
#include "world.h"
#include "robot.h"


extern world_type world;


HDC memdc;                      // Device context for offscreen drawing
HBITMAP mem_bitmap;             // Bitmap for memdc

int display_x, display_y;       // Current Size of the client area

bool keys[256] = { false };     // Key array, true if pressed

int updates = 0;                // Number of updates since last second
int updates_per_second = 0;     // Number of updates per second


bool manual_mode = false;

int timer_val = 10;

HWND neuron_window;

bool neuron_window_active = false;


robot_type *cur_robot = NULL;


unsigned int mouse_x_start;
unsigned int mouse_y_start;

bool mouse_is_down = false;

bool right_mouse_down = false;

bool show_stats = false;

/* Init the entire system */
void system_startup( HWND hwnd )
{
    srand(time(NULL));
    
    memdc_setup(hwnd);

    world_setup();

    world_update();
    world_draw(memdc);    


    SetTimer(hwnd, UPDATE_ID, timer_val, NULL);        
    SetTimer(hwnd, SECOND_ID, 1000, NULL);        
}
/* End of system_startup */


/* De-Init the entire system */
void system_shutdown( void )
{
    world_destroy();            
            
    DeleteObject(mem_bitmap);
    DeleteDC(memdc);   
}
/* End of system_shutdown */


/* Called when a key is pressed */
void key_down(HWND hwnd, WPARAM w)
{
    // Mark key as pressed
    keys[w & 0xff] = true;  

    // Deal with single press events herex
    if (keys['N'])
    {
        world_free_markers();
        world_free_impacts();
    }
    
    if (keys['V']) robot.draw_vision = !robot.draw_vision;

    if (keys[27]) PostQuitMessage(0);


    if (keys[VK_DOWN])
    {
        timer_val++;
        
        SetTimer(hwnd, UPDATE_ID, timer_val, NULL);                     
    }
    
    if (keys[VK_UP])
    {
        timer_val --;
        
        if (timer_val < 0) timer_val = 0;
        
       SetTimer(hwnd, UPDATE_ID, timer_val, NULL);
    }
   

    if (keys['R']) world_setup(); 
                  
    if (keys['T']) world.show_walls = !world.show_walls;

    if (keys['M']) manual_mode = !manual_mode;
    

     if (keys['G']) world.draw_grad = !world.draw_grad;
     
     if (keys['1']) world.scale1 -= 0.01;
     if (keys['2']) world.scale1 += 0.01;

     if (keys['3']) world.scale2 -= 0.01;
     if (keys['4']) world.scale2 += 0.01;
     
      if (keys['5']) world.scale3 -= 0.001;
     if (keys['6']) world.scale3 += 0.001;
     
     if (keys[VK_SPACE]) show_stats = !show_stats;
     
     if (keys['P']) world_compute_map_grid();
        
     
      
}
/* End of key_down */


/* Deal with main menu commands */
void main_menu(HWND hwnd, unsigned int id)
{


    switch(id)
    {
        case ID_EXIT:
            DestroyWindow(hwnd);
            return;

        case ID_SAVE:
            world_save();
            return;

        case ID_OPEN:
            world_load();
            return;
            
    }    
    
}
/* End of main menu */




void mouse_down(LPARAM l)
{
    mouse_is_down = true; 
    
    double world_x1 = (LOWORD(l) / (double)display_x) * world.x_size;
    double world_y1 = (HIWORD(l) / (double)display_y) * world.y_size;

    world_add_wall(world_x1, world_y1, 0, 0);
}


void mouse_up(LPARAM l)
{
    mouse_is_down = false;
}



void mouse_move(LPARAM l)
{
    if (mouse_is_down)
    {    
        wall_type *w = world.walls;
    
        if (w == NULL) return;

        double world_x2 = (LOWORD(l) / (double)display_x) * world.x_size;
        double world_y2 = (HIWORD(l) / (double)display_y) * world.y_size;

        if (world_x2 < w->x) return;
        if (world_y2 < w->y) return;
    
        w->x_size = world_x2 - w->x;
        w->y_size = world_y2 - w->y;
    }    
    
    if (right_mouse_down)
    {
            world_set_target(get_world_x(LOWORD(l)),
                             get_world_y(HIWORD(l))); 
    
    }
}








/* Called when a key is released */
void key_up(WPARAM w)
{
    keys[w & 0xff] = false;            
}
/* End of key up */


void manual_motion(double speed, double dir)
{
    if(!manual_mode) return;

    robot.speed = speed;
    robot.ddir = dir;
}



/* Process currently pressed keys */
void check_keys( void )
{
    // Decode WASD keys for manual override

    if (!manual_mode) return;

    // Forward
   if (keys['W']) 
    {
        if (keys['A']) manual_motion(0.03, -0.03); else     // Forward + left
        if (keys['D']) manual_motion(0.03, 0.03); else     // Forward + right
            manual_motion(0.03, 0.00);                      // Normal forward
                
    } else
    // Reverse
    if (keys['S'])
    {
        if (keys['A']) manual_motion(-0.015, 0.03); else   // Reverse + left
        if (keys['D']) manual_motion(-0.03, -0.03); else   // Reverse + right
            manual_motion(-0.03, 0);                    // Normal reverse
        
    } else
    if (keys['A']) manual_motion(0.0, -0.03); else         // Rotate left
    if (keys['D']) manual_motion(0.0, 0.03); else         // Rotate right
        manual_motion(0.0, 0.0);                           // No key, stop
}
/* End of check keys */


/* Deal with the system timer */
void timer_message(HWND hwnd, WPARAM wparam)
{
    if (wparam == UPDATE_ID)
    {
        check_keys();

        world_update();
        world_draw(memdc);
        
        updates++;
        InvalidateRect(hwnd, NULL, 0);                            
        return;
    }

    if (wparam == SECOND_ID)
    {
        updates_per_second = updates;
        updates = 0;

      //  world_debug_update();      
    }            
}
/* End of timer_message */


/* Deal with paint message */
void window_paint(HWND hwnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);

    char buff[400];

    if (show_stats)
    {
           
        sprintf(buff, "Update rate: %3d scale1 %f scale2 %f scale3: %f", 
                updates_per_second, world.scale1, world.scale2, world.scale3);
                       
        TextOut(memdc, 1, 1, buff, strlen(buff)); 
    }

    // Copy memory device context to display 
    BitBlt(hdc, 0, 0, display_x, display_y, memdc, 0, 0, SRCCOPY);
            
    EndPaint(hwnd, &ps); 
    
  // InvalidateRect(neuron_window, NULL, 0);      
}
/* Wnd of window_paint */



/* Setup the off screen drawing system */
void memdc_setup( HWND hwnd )
{
    RECT r;
    GetClientRect(hwnd, &r);

    // Update stored client area size
    display_x = r.right;
    display_y = r.bottom;

    HDC hdc = GetDC(hwnd);

    // Create memory device context and bitmap            
    memdc = CreateCompatibleDC(hdc);
    mem_bitmap = CreateCompatibleBitmap(hdc, r.right, r.bottom);
            
    // Select the bitmap into the memort dc
    SelectObject(memdc, mem_bitmap);
            
    ReleaseDC(hwnd, hdc);     
}
/* End of memdc_setup */


/* Chhose the correct brush color for the neuron */
void set_neuron_brush(HDC hdc, double val)
{
    if (val == 0)
        SelectObject(hdc, (HBRUSH)world.white_brush);
    else
    if (val > 0)
        SelectObject(hdc, (HBRUSH)world.blue_brush);
    else
        SelectObject(hdc, (HBRUSH)world.red_brush);     
}
/* End of set_neuron_brush */



/* Window function */
LRESULT CALLBACK main_win_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
    switch(message)
    {
        case WM_TIMER: timer_message(hwnd, wparam); return(0);

        case WM_CREATE: system_startup(hwnd); return(0);

        case WM_PAINT: window_paint(hwnd); return(0);

        case WM_DESTROY: 
            system_shutdown();            
            PostQuitMessage(0);
            return(0);
                                        
        case WM_SIZE:               // Process size message
            // These are alreadt setup, delete them
            DeleteObject(mem_bitmap);
            DeleteDC(memdc);
            
            // Setup again with the new size
            memdc_setup(hwnd);
            return(0);
                
        case WM_KEYDOWN:            // Process keydown
            key_down(hwnd, wparam);
            return(0);
    
        case WM_KEYUP:              // Process keyup
            key_up(wparam);
            return(0);
                
        case WM_LBUTTONDOWN:
            mouse_down(lparam);
            return(0);
               
        case WM_LBUTTONUP:
            mouse_up(lparam);
            return(0);
                          
        case WM_MOUSEMOVE:
            mouse_move(lparam);
            return(0);
             
            
        case WM_RBUTTONDOWN:
            world_set_target(get_world_x(LOWORD(lparam)),
                             get_world_y(HIWORD(lparam))); 
            right_mouse_down = true;
            return(0);
                                      
        case WM_RBUTTONUP:
            right_mouse_down = false;
            return(0);
                                
        case WM_COMMAND:
            main_menu(hwnd, LOWORD(wparam));
            return(0);
                
        default:
            return(DefWindowProc(hwnd, message, wparam, lparam));    
    }
    return(0);
}
/* Wnd of window function */




/* Winmain */
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE pinst, LPSTR args, int mode)
{
    char name[] = "Robot Simulator";
    
    WNDCLASS wc;
    
    wc.hInstance = hinst;
    wc.lpszClassName = name;
    wc.lpfnWndProc = main_win_proc;
    wc.style = 0;
    
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszMenuName = "MAINMENU";
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    
    wc.hbrBackground = NULL;
    
    if (!RegisterClass(&wc)) return(0);
    
    HWND hwnd = CreateWindow(name, name, WS_OVERLAPPEDWINDOW, 
                            120, 120, // x, y
                            640,480, // height, width
                            HWND_DESKTOP, NULL, hinst, NULL);
                            
    ShowWindow( hwnd, mode);
    UpdateWindow( hwnd );

    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
        
    return (msg.wParam);
}
/* End of winmain */









