#include <math.h>
#include <assert.h>
#include <windows.h>
#include <windowsx.h>
#include "SM_Timer.h"
#include "SM_Main.h"
#include "SM_DemoScript.h"
#include "SM_Music.h"
#include "SM_Renderable.h"
#include "SM_ResourceManager.h"
#include "SM_Shader.h"
#include "SM_RenderPipeline.h"
#include "SM_Coordinates.h"
#include "SM_CommonVF.h"
#include "SM_Screen.h"
#include "SM_DebugText.h"
#include "DemoInterface.h"
#include "MVFS.h"
#include "FXFilter.h"
#include "FX3DText.h"
#include "resource.h"


#define ENUMERA(Efecto) void EnumeraLinka##Efecto##(); EnumeraLinka##Efecto##();

#define USE_ZIP

#ifdef USE_ZIP
int g_iPAK=-1;
#endif

void EnumerateFx()
{ 

  ENUMERA(FilterFX);
  ENUMERA(StillFX);
  //ENUMERA(ScrollFX);
  ENUMERA(Escena3DFX);
  //ENUMERA(PelosFX);
  //ENUMERA(TunelFX);
  //ENUMERA(PirulasFX);
  //ENUMERA(GreetingsFX);
  //ENUMERA(EnredaderaFX);
  //ENUMERA(IsoSurfaceFX);
  //ENUMERA(SingleFilterFX);  
  //ENUMERA(Font3DFx);  
  //ENUMERA(Text3DFx);    
  //ENUMERA(ParticulasFX);
  //ENUMERA(FlareFX);
  ENUMERA(MusicFX);
  ENUMERA(VoxelFX);
}


static BOOL CALLBACK InitDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

struct DialogData
{
  char*     pszIdiom;
  bool      bFullscreen;
  bool      b16Bit;
  bool      b32BitTextures;
  bool      bAntialias;
  unsigned  uResX;
  unsigned  uResY;
};

DialogData MyDialogData;



static BOOL CALLBACK InitDlgProc( HWND _hdlg, UINT _uMsg, WPARAM _wparam, LPARAM _lparam)
{
  //static sData* dlgdata = 0;
  static DialogData* dlgdata = 0;

  switch (_uMsg)
  {
    case WM_INITDIALOG :
      {
        SetWindowPos(_hdlg,HWND_TOPMOST,0,0,1,1,SWP_NOMOVE|SWP_NOSIZE);

        dlgdata = (DialogData*)_lparam;

        HWND hcombo = GetDlgItem( _hdlg,IDC_RESOLUTION);
        ComboBox_ResetContent( hcombo );
        ComboBox_InsertString( hcombo, 0, "640x480" );
        ComboBox_InsertString( hcombo, 1, "800x600" );
        ComboBox_InsertString( hcombo, 2, "1024x768" );
        ComboBox_InsertString( hcombo, 3, "1280x1024" );
        ComboBox_SetCurSel   (hcombo, 0);

        Button_SetCheck( GetDlgItem(_hdlg,IDC_16BIT), BST_CHECKED );
        //Button_SetCheck( GetDlgItem(_hdlg,IDC_ANTIALIAS), BST_CHECKED );

        //Button_SetCheck( GetDlgItem(_hdlg,IDC_TEXTURES32), BST_CHECKED );
        
        
        RECT rectWindow;
	      RECT rectClient;
	      long lCoorxWin, lCooryWin;

    
	      GetWindowRect(_hdlg, &rectWindow);
	      GetClientRect(_hdlg, &rectClient);

        lCoorxWin = (GetSystemMetrics(SM_CXSCREEN) - rectWindow.right) /2;
	      lCooryWin = (GetSystemMetrics(SM_CYSCREEN) - rectWindow.bottom) /2;
	      
	      GetWindowRect(_hdlg, &rectClient);
	      
        BOOL b=SetWindowPos( _hdlg, HWND_NOTOPMOST, 
          lCoorxWin, lCooryWin, 
          rectWindow.right-rectWindow.left, rectWindow.bottom-rectWindow.top, 
          SWP_SHOWWINDOW|SWP_FRAMECHANGED );			                      		      

        /*
        // radio ventana / pantalla completa
        if (dlgdata->coop_mode==sData::COOP_FULL)
          Button_SetCheck( GetDlgItem(_hdlg,IDC_RADIO_FULLSCREEN), BST_CHECKED );
        else
          Button_SetCheck( GetDlgItem(_hdlg,IDC_RADIO_WINDOW), BST_CHECKED );

        // checkboxes warp y quicklad
        Button_SetCheck( 
          GetDlgItem(_hdlg,IDC_CHECK_WARP), 
          dlgdata->warp ? BST_CHECKED : BST_UNCHECKED );

        Button_SetCheck( 
          GetDlgItem(_hdlg,IDC_CHECK_QUICKLOAD), 
          dlgdata->quickload ? BST_CHECKED : BST_UNCHECKED );

        // radio sonido on/off
        if (dlgdata->sound==sData::SND_ON)
          Button_SetCheck( GetDlgItem(_hdlg,IDC_RADIO_SOUNDON), BST_CHECKED );
        else
          Button_SetCheck( GetDlgItem(_hdlg,IDC_RADIO_SOUNDOFF), BST_CHECKED );

        // radio bits textura 16/32
        if (dlgdata->texture_bits==sData::TB_16)
          Button_SetCheck( GetDlgItem(_hdlg,IDC_RADIO_TEXTUREBITS_16), BST_CHECKED );
        else
          Button_SetCheck( GetDlgItem(_hdlg,IDC_RADIO_TEXTUREBITS_32), BST_CHECKED );

        // radio bits zbuffer 16/24/32
        if (dlgdata->zbuffer_bits==sData::ZB_16)
          Button_SetCheck( GetDlgItem(_hdlg,IDC_RADIO_ZBITS_16), BST_CHECKED );
        else
        if (dlgdata->zbuffer_bits==sData::ZB_24)
          Button_SetCheck( GetDlgItem(_hdlg,IDC_RADIO_ZBITS_24), BST_CHECKED );
        else
          Button_SetCheck( GetDlgItem(_hdlg,IDC_RADIO_ZBITS_32), BST_CHECKED );

        // combo box con dispositivos disponibles
        {
          HWND hcombo = GetDlgItem( _hdlg,IDC_DDM );
          // rellenar combo con dispositivos disponibles
          ComboBox_ResetContent( hcombo );
          grx_direct3D::enumDriverDeviceMode( (void*)hcombo, cb_enumDDM );

          // seleccionar dispositivo / modo
          if (dlgdata->szDriverDeviceMode[0]==0)
            ComboBox_SetCurSel( hcombo, 0 ); // por defecto seleccione el primero
          else
            ComboBox_SelectString( hcombo, 0, dlgdata->szDriverDeviceMode );
        }

        // list box con entradas WC
        {
          HWND hlist = GetDlgItem( _hdlg,IDC_LIST_WC );
#ifdef STATICPRUEBAS
          ListBox_ResetContent( hlist );
          pruebas_for_each( (void*)hlist, cb_enumWC );
#else
          EnableWindow( hlist, FALSE );
#endif
        }
        */
      }
      return TRUE;


    case WM_COMMAND :
      switch ( LOWORD(_wparam) )
      {
        case IDOK :
            dlgdata->bFullscreen=(Button_GetCheck(GetDlgItem(_hdlg,IDC_WINDOWED))==BST_CHECKED)?false:true;
            

            dlgdata->b16Bit         =Button_GetCheck(GetDlgItem(_hdlg,IDC_16BIT))==BST_CHECKED;
            dlgdata->bAntialias     =Button_GetCheck(GetDlgItem(_hdlg,IDC_ANTIALIAS))==BST_CHECKED;
            dlgdata->b32BitTextures =Button_GetCheck(GetDlgItem(_hdlg,IDC_TEXTURES32))==BST_CHECKED;

            ShaderManager::g_b32BitTextures=dlgdata->b32BitTextures;

            if (Button_GetCheck(GetDlgItem(_hdlg,IDC_HIGHDETAIL))==BST_CHECKED)
            {
              SIZEWIDTH =1024;
              SIZEHEIGHT=1024;
            }
            else
            {
              SIZEWIDTH =512;
              SIZEHEIGHT=512;
            }

            switch (ComboBox_GetCurSel(GetDlgItem( _hdlg,IDC_RESOLUTION )))
            {
            case 0:              
              dlgdata->uResX=640;
              dlgdata->uResY=480;
              break;
            case 1:
              dlgdata->uResX=800;
              dlgdata->uResY=600;
              break;
            case 2:
              dlgdata->uResX=1024;
              dlgdata->uResY=768;
              break;
            case 3:
              dlgdata->uResX=1280;
              dlgdata->uResY=1024;
              break;

            }

            dlgdata->pszIdiom=".txt";
            TextManager::SetLanguage(dlgdata->pszIdiom);  

          EndDialog( _hdlg, IDOK );
          break;

        case IDCANCEL :
          /*
          dlgdata = 0;
          */
          EndDialog( _hdlg, IDCANCEL );
          break;
      }
      break;
  }

  return FALSE;
}

int SmWantMainWindow()
{
  return 1;
}

int SmIgnoreClears()
{
  return 1;
}

int SmAppPreInit()
{
  int res = DialogBoxParam(	
                SM_Main::HInstance(),
                MAKEINTRESOURCE(IDD_STARTDIALOG),
                0, /* parent wnd : main win not created yet! */
                (DLGPROC)InitDlgProc,
                (LPARAM)&MyDialogData
              );

  return res==IDOK?0:-1;  
}

DemoControl Control;

float g_fStartTime;
int SmAppInit()
{ 
  SetClassLong(SM_Main::Hwnd(), GCL_HICON, (LONG) LoadIcon(SM_Main::HInstance(), MAKEINTRESOURCE(IDI_MAIN_ICON))); 
  MVFS::Init("");

  #ifdef USE_ZIP
  g_iPAK=MVFS::AddPackage(MVFS::E_ZIP, "data.dat");
  #endif

  if (SM_D3d::Init()!=0)
  {
    SM_Main::OutputError("Error initializing d3d ");
    return (-1);
  }

  SM_Main::SetWindowText("ALUF");

  if (strlen(SM_Main::CommandLine()))
  {
    MyDialogData.bFullscreen = false;
  }

  if (Control.Init(SM_Main::Hwnd(), 
                   MyDialogData.uResX,
                   MyDialogData.uResY,
                   MyDialogData.b16Bit?16:32,
                   false,
                   MyDialogData.bFullscreen,
                   MyDialogData.bAntialias,
                   true, 
                   true,
                   false) != 0)
  {
    SM_Main::OutputError("Failed to initialize demo control");
    return (-1);
  }
  
  if (Control.Load("script.txt") != 0)
  {
    SM_Main::OutputError("Failed to load script");
    return (-1);
  }

  // Preload fx
  if (Control.PreloadFX() != 0)
  {
    SM_Main::OutputError("Failed to preload fx");
    return (-1);
  }

  //g_fStartTime = float(timeGetTime())/1000.0f;

  LARGE_INTEGER li;
  QueryPerformanceFrequency(&li);

  LARGE_INTEGER liCounter;
  QueryPerformanceCounter(&liCounter);

  g_fStartTime = float(liCounter.QuadPart)/float(li.QuadPart);
  Control.RunToTime(-1.0f);    
  Control.RunToTime(0.0f);    
  
  return 0;
}

int SmAppRun()
{
  MSG msg;
  while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  { 
    TranslateMessage(&msg);
		DispatchMessage(&msg);      
	} 

  if (SM_Main::IsActive())
  {
    LARGE_INTEGER li;
    QueryPerformanceFrequency(&li);

    LARGE_INTEGER liCounter;
    QueryPerformanceCounter(&liCounter);

    float fTime = float(liCounter.QuadPart)/float(li.QuadPart);
  
    return Control.Run(fTime - g_fStartTime);  
  }
  else
  {
    Sleep(20);
    return 1;
  }
  
}

int SmAppEnd()
{
  #ifdef USE_ZIP
  if (g_iPAK!=-1)
  {  
    MVFS::RemovePackage(g_iPAK);
    g_iPAK = -1;
  }  
  #endif

  Control.Shutdown();

  MVFS::Shutdown();

  SM_D3d::Shutdown();

  return 0;
}