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

#include "utility.h"
#include "window.h"
#include "opengl.h"


window_class::window_class( void )
{
    fps = 0;
    frames = 0;  

    display_x = 800;
    display_y = 600;
   
    mouse_down = false;
}



int window_class::start( HINSTANCE hinst, opengl_class *link_source )
{
    log("window start");

    opengl_link = link_source; 


    WNDCLASS wc;

    wc.style = CS_OWNDC;    

    wc.lpfnWndProc = window_class::wnd_wrapper;

    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hinst;
    wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
    wc.hCursor = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "WeatherCL";
    
    RegisterClass( &wc );

    unsigned int win_flags =  WS_OVERLAPPEDWINDOW | WS_VISIBLE;

    RECT win_rect = {0, 0, display_x, display_y};

    AdjustWindowRect(&win_rect, win_flags, false);

    CreateWindow("WeatherCL", "Weather", 
                      win_flags, 0, 0, 
                      win_rect.right - win_rect.left, 
                      win_rect.bottom - win_rect.top,
                      NULL, NULL, hinst, this);   
}



void window_class::stop( void )
{
    log("window stop");
    
    destroy_buffer();
        
    DestroyWindow( hwnd );
}


void window_class::draw( void )
{
   // log("window draw");

    char tmp[400];
    sprintf(tmp, "FPS: %4d  x_ang: %5.2f  y_ang: %5.3f zoom: %5.2f", fps,
    opengl_link->x_ang, opengl_link->y_ang, opengl_link->zoom);

    TextOut(hdc, 0,0, tmp, strlen(tmp));     
}


/* Create off screen buffer */
void window_class::setup_buffer( void )
{
    log("window setup buffer");

 /*   // Get main DC
    HDC hdc = GetDC(hwnd);

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

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

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

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


void window_class::destroy_buffer( void )
{
//    DeleteObject(mem_bitmap);		//	 Delete off screen buffer
//    DeleteDC(memdc);	       		// Delete memory DC
}


LRESULT CALLBACK window_class::wnd_wrapper (HWND hwnd, UINT message, 
                                    WPARAM wParam, LPARAM lParam)
{
    // First call, we need to set the window pointer
	if (message == WM_NCCREATE) 
        SetWindowLong (hwnd, GWL_USERDATA, long((LPCREATESTRUCT(lParam))->lpCreateParams));
        
   window_class *win_ptr = (window_class*) (::GetWindowLong (hwnd, GWL_USERDATA));

    // Pass messages 
	if (win_ptr)
		return(win_ptr->wnd_proc (hwnd, message, wParam, lParam));
	else
		return ::DefWindowProc (hwnd, message, wParam, lParam);  
}


LRESULT CALLBACK window_class::wnd_proc (HWND hwnd_src, UINT message, 
                                         WPARAM wParam, LPARAM lParam)
{
 
   switch (message) 
    {
      case WM_CREATE: 
            hwnd = hwnd_src;
            setup_buffer();
            SetTimer(hwnd, ID_SEC, 1000, NULL);                           
        return 0;

      case WM_TIMER:

        if (wParam == ID_SEC) 
        {
           fps = frames;
           frames = 0;
        }             
        
        return 0;


      case WM_CLOSE:
        PostQuitMessage( 0 );
        return 0;

      case WM_DESTROY:
        return 0;

      case WM_KEYDOWN:
        switch (wParam) 
        {
          case VK_ESCAPE:
            PostQuitMessage( 0 );
            return 0;
        }
        return 0;

        case WM_SIZE: resize(); return(0);
     //   case WM_PAINT: paint(); return(0);

        case WM_LBUTTONDOWN: left_mouse_down(lParam); return(0);
        case WM_LBUTTONUP: left_mouse_up(lParam); return(0);
        case WM_MOUSEMOVE: mouse_move(lParam); return(0);
        case WM_MOUSEWHEEL: mouse_wheel(wParam); return(0);


        default:
          return DefWindowProc(hwnd_src, message, wParam, lParam);
  }   
    
    
}




int window_class::loop ( void )
{
    while (1) 
    {
        MSG msg;
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
        {
            if (msg.message == WM_QUIT)  return msg.wParam; else 
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
         } 
         else 
         {
            opengl_link->frame();
            
            draw();
            
            frames++;
            InvalidateRect(hwnd, NULL, 0); 
         }
    }   
}




void window_class::resize ( void )
{
    log("window resize");

    static bool first_resize = true;

    // Ignore first resize
    if (first_resize)
    {
        first_resize = false;
        return;
    }


    RECT r;
 
    GetClientRect(hwnd, &r);
  
    char tmp[400];
    sprintf(tmp, "window resize Hwnd :  %d  right %d  bottom %d", hwnd, r.right, r.bottom);
    log(tmp);

    display_x = r.right;
    display_y = r.bottom;
 
    destroy_buffer();
    setup_buffer();
 
    opengl_link->setup_view();
}


void window_class::paint( void )
{
  /*  PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);
    BitBlt(hdc, 0, 0, display_x, display_y, memdc, 0, 0, SRCCOPY);
    EndPaint(hwnd, &ps);  */

}



void window_class::left_mouse_down( LPARAM l)
{
    mouse_down = true;
    mouse_start_x = LOWORD(l); 
    mouse_start_y = HIWORD(l);     
}

void window_class::left_mouse_up( LPARAM l)
{
    mouse_down = false;
}


void window_class::mouse_move( LPARAM l )
{
    if(!mouse_down) return;

    int cur_x = LOWORD(l);
    int cur_y = HIWORD(l);
    

    double x_ang = -(cur_y - mouse_start_y) * (1-fabs(opengl_link ->zoom)) * 0.12;
    double y_ang = -(cur_x - mouse_start_x) * (1-fabs(opengl_link ->zoom)) * 0.12;

    mouse_start_x = cur_x;
    mouse_start_y = cur_y;

    char tmp[300];

    sprintf(tmp, "x diff: %f", x_ang);

   // log(tmp);

    opengl_link -> x_ang += x_ang;
    opengl_link -> y_ang += y_ang;

    if( opengl_link -> y_ang > 360) opengl_link -> y_ang -=  360;
    if( opengl_link -> y_ang < -360) opengl_link -> y_ang +=  360;


//    if( opengl_link -> x_ang > 360) opengl_link -> x_ang -=  360;
//    if( opengl_link -> x_ang < -360) opengl_link -> x_ang +=  360;

    if( opengl_link -> x_ang > 90) opengl_link -> x_ang =  90;
    if( opengl_link -> x_ang < -90) opengl_link -> x_ang =  -90;



}



void window_class::mouse_wheel (WPARAM wParam )
{
    int move = (int)HIWORD(wParam);



    double delta = -(1-fabs(opengl_link ->zoom)) * GET_WHEEL_DELTA_WPARAM(wParam);


    
    opengl_link -> zoom += delta / 1000.0;
    
    if ( opengl_link -> zoom  > -1.11)  opengl_link -> zoom = -1.11;
    if ( opengl_link -> zoom  < -10.0)  opengl_link -> zoom = -10.0;
   
    
}












