#include "SM_mainPCH.h"
#include <stdio.h>
#include "SM_leaks.h"
#include "SM_Main.h"


#ifndef GET_X_LPARAM
#define GET_X_LPARAM(lp)   ((int)(short)LOWORD(lp))
#endif
#ifndef GET_Y_LPARAM
#define GET_Y_LPARAM(lp)   ((int)(short)HIWORD(lp))
#endif

#if defined(_DEBUG) && defined(_WANTNEWS)
extern "C" { _CRTIMP int __cdecl _CrtDumpMemoryLeaks( void ); }
#endif

void DumpLeaks()
{
  #if defined(_DEBUG) && defined(_WANTNEWS)
  _CrtDumpMemoryLeaks();
  #endif

}

namespace SM_Main
{
  

  bool            g_bActive   =false;
  HWND            g_hwnd      =0;
  IKeyboard*      g_pIKeyBoard=0;
  IMouse*         g_pIMouse   =0;
  INotifier*      g_pINotifier=0;
  char*           g_pcCommand =0;
  bool            g_bRunning  =false;
  HINSTANCE       m_hInstance;


  bool IsActive()
  {
    return (g_bActive);
  }

  HWND Hwnd()
  {
    return (g_hwnd);
  }

  const char* CommandLine()
  {
    return (g_pcCommand);
  }

  void SetWindowText(const char* pcText)
  {
    if (g_hwnd)
    {
      ::SetWindowText( g_hwnd, pcText);
    }
  }

  void SetKeyboardHandler(IKeyboard*     pIKeyBoard)
  {
    g_pIKeyBoard=pIKeyBoard;
  }

  void SetMouseHandler   (IMouse*        pIMouse)
  {
    g_pIMouse=pIMouse;
  }

  void SetNotifyHandler  (INotifier*  pINotifier)
  {
    g_pINotifier=pINotifier;
  }  

  void SetCursorPos(int* x, int* y)
  {
    
    int xr, yr;
    GetCursorPos(&xr, &yr);

    POINT pt;
    pt.x=x?*x:xr;
    pt.y=y?*y:yr;

    ClientToScreen( Hwnd(), &pt );
    ::SetCursorPos( pt.x, pt.y );
  }

  void GetCursorPos(int* x, int* y)
  {
    POINT pt;
    ::GetCursorPos( &pt );
    ScreenToClient( Hwnd(), &pt );    

    if (x) {*x=pt.x;}
    if (y) {*y=pt.y;}
  }

  void _cdecl OutputConsole(char* pcFormat, ...)
  { 
    #ifdef _DEBUG    
    char pcText[4096];

    va_list lst;	
	  va_start (lst, pcFormat);
	  vsprintf( pcText, pcFormat, lst);
	  va_end (lst);

    OutputDebugString(pcText);   
    #endif
  }

  void _cdecl     OutputDebug(char* pcFormat, ...)
  {
    #ifdef _DEBUG
    char pcText[4096];

    va_list lst;	
	  va_start (lst, pcFormat);
	  vsprintf( pcText, pcFormat, lst);
	  va_end (lst);

    OutputDebugString(pcText);
    #endif
  }

  void _cdecl OutputError(char* pcFormat, ...)
  {
    char pcText[4096];

    va_list lst;	
	  va_start (lst, pcFormat);
	  vsprintf( pcText, pcFormat, lst);
	  va_end (lst);

    MessageBox(Hwnd(), pcText, "ERROR", MB_OK | MB_ICONERROR);
  }

  HINSTANCE       HInstance         ()
  {
    return SM_Main::m_hInstance;
  }

}


static long WINAPI windowProc(const HWND hwnd, const UINT message, const WPARAM wParam, const LPARAM lParam)
{
  
	switch (message)
	{
		case WM_CREATE:
      SM_Main::g_hwnd=hwnd;
			break;
		case WM_DESTROY:
      PostQuitMessage(0);
      SM_Main::g_bRunning=false;
			break;
    case WM_ACTIVATEAPP :
      SM_Main::g_bActive=LOWORD(wParam)!=WA_INACTIVE;
      if (SM_Main::g_pINotifier) SM_Main::g_pINotifier->OnActivate(SM_Main::g_bActive);      
      break;      
    case WM_SYSKEYDOWN:
      if (SM_Main::g_pIKeyBoard) SM_Main::g_pIKeyBoard->OnKeyDown(int(wParam), true);
			break;
		case WM_SYSKEYUP:
      if (SM_Main::g_pIKeyBoard) SM_Main::g_pIKeyBoard->OnKeyUp(int(wParam), true);
			break;	
    case WM_KEYDOWN:
      if (SM_Main::g_pIKeyBoard) SM_Main::g_pIKeyBoard->OnKeyDown(int(wParam), false);
			break;
		case WM_KEYUP:
      if (SM_Main::g_pIKeyBoard) SM_Main::g_pIKeyBoard->OnKeyUp(int(wParam), false);
			break;	
    case WM_MOUSEMOVE:
      if (SM_Main::g_pIMouse) SM_Main::g_pIMouse->OnMouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));      
      break;
    case WM_LBUTTONDOWN :
    case WM_RBUTTONDOWN :
    case WM_MBUTTONDOWN :
      {
        SM_Main::IMouse::eButton Button;
        switch (message)
        {
          case WM_LBUTTONDOWN : Button=SM_Main::IMouse::LEFT_BUTTON   ; break;
          case WM_RBUTTONDOWN : Button=SM_Main::IMouse::RIGHT_BUTTON  ; break;
          case WM_MBUTTONDOWN : Button=SM_Main::IMouse::MIDDLE_BUTTON ; break;
        }
        if (SM_Main::g_pIMouse) SM_Main::g_pIMouse->OnMouseButtonDown(Button);      
        break;
      }
    case WM_LBUTTONUP   :
    case WM_RBUTTONUP   :
    case WM_MBUTTONUP   :
      {
        SM_Main::IMouse::eButton Button;
        switch (message)
        {
          case WM_LBUTTONUP   : Button=SM_Main::IMouse::LEFT_BUTTON   ; break;
          case WM_RBUTTONUP   : Button=SM_Main::IMouse::RIGHT_BUTTON  ; break;
          case WM_MBUTTONUP   : Button=SM_Main::IMouse::MIDDLE_BUTTON ; break;
        }
        if (SM_Main::g_pIMouse) SM_Main::g_pIMouse->OnMouseButtonUp(Button);      
        break;    
      }
    case WM_SYSCOMMAND :
      switch(wParam)
      {
      case SC_SCREENSAVE:
        // Rechazamos salvapantallas
        return 0;
      case SC_MONITORPOWER:
        // rechazamos baja energia de monitor        
        return 0;
      }                
      break;
    case WM_DISPLAYCHANGE:
      if (SM_Main::g_pINotifier) SM_Main::g_pINotifier->OnDisplayChange();
      break;		    

    case WM_PAINT :
      if (SmIgnoreClears())
      {
        ValidateRect(SM_Main::Hwnd(),NULL);
        return 0;
      }
      break;
      

    case WM_ERASEBKGND :      
      if (SmIgnoreClears())
      {
        return 0;
      }
      break;
      
      
	}

	return DefWindowProc(hwnd, message, wParam, lParam);

  return (0);
}


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
 
 #if defined(_DEBUG) && defined(_WANTNEWS)
  int iFlags=_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG );      // Get current flags
  _CrtSetDbgFlag(iFlags | _CRTDBG_LEAK_CHECK_DF);       // Dump Leaks on program termination
  #endif

  
  SM_Main::m_hInstance=hInstance;

  if (SmAppPreInit()!=0)
  {
    return -1;
  }

  if (SmWantMainWindow())
  {
    WNDCLASS wc;

	  wc.style = CS_HREDRAW | CS_VREDRAW;
	  wc.lpfnWndProc = (WNDPROC)windowProc;
	  wc.cbClsExtra = 0;
	  wc.cbWndExtra = 0;
	  wc.hInstance = NULL;
	  wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	  wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	  wc.lpszMenuName = "";
	  wc.lpszClassName = "Window";

	  RegisterClass(&wc);


    SM_Main::g_hwnd = CreateWindow("Window", "", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,     
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        0, 0, hInstance, 0 );

    if (FAILED(SM_Main::g_hwnd))
    {
      return -1;
    }

    ShowCursor(FALSE);
    ShowWindow(SM_Main::Hwnd(), SW_SHOW);    
  }
  
  // Copiamos linea de comando
  SM_Main::g_pcCommand=new char[strlen(lpCmdLine)+1];
  if (!SM_Main::g_pcCommand)
  {
    return (-1);
  }

  strcpy(SM_Main::g_pcCommand, lpCmdLine);


  if (SmAppInit()==0)
  {
    SM_Main::g_bRunning=true;
    do 
    {
      /*
      MSG msg;
      while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
      { 
        TranslateMessage(&msg);
			  DispatchMessage(&msg);      
		  } 
      */
    } 
    while (SM_Main::g_bRunning && SmAppRun());
  }
  else
  {
    MessageBox(SM_Main::Hwnd(), "SmAppInit() Failed", "Error", MB_OK);
  }

  SmAppEnd ();

  delete[] SM_Main::g_pcCommand;
  
  return 0;
}


    