/* FCE Ultra - NES/Famicom Emulator
 *
 * Copyright notice for this file:
 *  Copyright (C) 2002 Xodnizel
 *
 * 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
 */

#include "common.h"

#include "cheat.h"

static HWND acwin=0;

static int selcheat;
static int scheatmethod=0;
static uint8 cheatval1=0;
static uint8 cheatval2=0;

#define CSTOD   24

static uint16 StrToU16(char *s)
{
 unsigned int ret=0;
 sscanf(s,"%4x",&ret);
 return ret;
}

static uint8 StrToU8(char *s)
{
 unsigned int ret=0;
 sscanf(s,"%d",&ret);
 return ret;
}

static int StrToI(char *s)
{
 int ret=0;
 sscanf(s,"%d",&ret);
 return ret;
}


/* Need to be careful where these functions are used. */
static char *U16ToStr(uint16 a)
{
 static char TempArray[16];
 sprintf(TempArray,"%04X",a);
 return TempArray;
}

static char *U8ToStr(uint8 a)
{
 static char TempArray[16];
 sprintf(TempArray,"%03d",a);
 return TempArray;
}

static char *IToStr(int a)
{
 static char TempArray[32];
 sprintf(TempArray,"%d",a);
 return TempArray;
}

static HWND RedoCheatsWND;
static int RedoCheatsCallB(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data)
{
 char tmp[512];
 sprintf(tmp,"%s %s",s?"+":"-",name);
 SendDlgItemMessage(RedoCheatsWND,300,LB_ADDSTRING,0,(LPARAM)(LPSTR)tmp);
 return(1);
}

static void RedoCheatsLB(HWND hwndDlg)
{
 SendDlgItemMessage(hwndDlg,300,LB_RESETCONTENT,0,0);
 RedoCheatsWND=hwndDlg;
 FCEUI_ListCheats(RedoCheatsCallB, 0);
}

int cfcallb(uint32 a, uint8 last, uint8 current)
{
 char temp[16];

 sprintf(temp,"%04X:%03d:%03d",(unsigned int)a,last,current);
 SendDlgItemMessage(acwin,108,LB_ADDSTRING,0,(LPARAM)(LPSTR)temp);
 return(1);
}

static int scrollindex;
static int scrollnum;
static int scrollmax;

int cfcallbinsert(uint32 a, uint8 last, uint8 current)
{
 char temp[16];

 sprintf(temp,"%04X:%03d:%03d",(unsigned int)a,last,current);
 SendDlgItemMessage(acwin,108,LB_INSERTSTRING,(CSTOD-1),(LPARAM)(LPSTR)temp);
 return(1);
}

int cfcallbinsertt(uint32 a, uint8 last, uint8 current)
{
 char temp[16];

 sprintf(temp,"%04X:%03d:%03d",(unsigned int)a,last,current);
 SendDlgItemMessage(acwin,108,LB_INSERTSTRING,0,(LPARAM)(LPSTR)temp);
 return(1);
}


void AddTheThing(HWND hwndDlg, char *s, int a, int v)
{
 if(FCEUI_AddCheat(s,a,v,-1,0))
  MessageBox(hwndDlg,"Cheat Added","Cheat Added",MB_OK);
}


static void DoGet(void)
{
 int n=FCEUI_CheatSearchGetCount();
 int t;
 scrollnum=n;
 scrollindex=-32768;

 SendDlgItemMessage(acwin,108,LB_RESETCONTENT,0,0);
 FCEUI_CheatSearchGetRange(0,(CSTOD-1),cfcallb);

 t=-32768+n-1-(CSTOD-1);
 if(t<-32768)
  t=-32768;
 scrollmax=t;
 SendDlgItemMessage(acwin,120,SBM_SETRANGE,-32768,t);
 SendDlgItemMessage(acwin,120,SBM_SETPOS,-32768,1);
}

static void FixCheatSelButtons(HWND hwndDlg, int how)
{
 /* Update Cheat Button */
 EnableWindow(GetDlgItem(hwndDlg,251),how);

 /* Delete Cheat Button */
 EnableWindow(GetDlgItem(hwndDlg,252),how);
}

static BOOL CALLBACK AddCheatCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  static int lbfocus;
  static HWND hwndLB;

  switch(uMsg)
  {
   case WM_VSCROLL:
                if(scrollnum>(CSTOD-1))
                {
                 switch((int)LOWORD(wParam))
                 {
                  case SB_TOP:
                        scrollindex=-32768;
                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,(CSTOD-1),0);
                        FCEUI_CheatSearchGetRange(scrollindex+32768,scrollindex+32768+(CSTOD-1),cfcallb);
                        break;
                  case SB_BOTTOM:
                        scrollindex=scrollmax;
                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,(CSTOD-1),0);
                        FCEUI_CheatSearchGetRange(scrollindex+32768,scrollindex+32768+(CSTOD-1),cfcallb);
                        break;
                  case SB_LINEUP:
                        if(scrollindex>-32768)
                        {
                         scrollindex--;
                         SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                         SendDlgItemMessage(hwndDlg,108,LB_DELETESTRING,(CSTOD-1),0);
                         FCEUI_CheatSearchGetRange(scrollindex+32768,scrollindex+32768,cfcallbinsertt);
                        }
                        break;

                  case SB_PAGEUP:
                        scrollindex-=CSTOD;
                        if(scrollindex<-32768) scrollindex=-32768;
                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,(CSTOD-1),0);
                        FCEUI_CheatSearchGetRange(scrollindex+32768,scrollindex+32768+(CSTOD-1),cfcallb);
                        break;

                  case SB_LINEDOWN:
                        if(scrollindex<scrollmax)
                        {
                         scrollindex++;
                         SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                         SendDlgItemMessage(hwndDlg,108,LB_DELETESTRING,0,0);
                         FCEUI_CheatSearchGetRange(scrollindex+32768+(CSTOD-1),scrollindex+32768+(CSTOD-1),cfcallbinsert);
                        }
                        break;

                  case SB_PAGEDOWN:
                        scrollindex+=CSTOD;
                        if(scrollindex>scrollmax)
                         scrollindex=scrollmax;
                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,0,0);
                        FCEUI_CheatSearchGetRange(scrollindex+32768,scrollindex+32768+(CSTOD-1),cfcallb);
                        break;

                  case SB_THUMBPOSITION:
                  case SB_THUMBTRACK:
                        scrollindex=(short int)HIWORD(wParam);
                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,0,0);
                        FCEUI_CheatSearchGetRange(32768+scrollindex,32768+scrollindex+(CSTOD-1),cfcallb);
                        break;
                 }

                }
                break;

   case WM_INITDIALOG:
                selcheat = -1;
                FixCheatSelButtons(hwndDlg, 0);
                acwin=hwndDlg;
                SetDlgItemText(hwndDlg,110,(LPTSTR)U8ToStr(cheatval1));
                SetDlgItemText(hwndDlg,111,(LPTSTR)U8ToStr(cheatval2));
                DoGet();
                CheckRadioButton(hwndDlg,115,120,scheatmethod+115);
                lbfocus=0;
                hwndLB=0;

                RedoCheatsLB(hwndDlg);
                break;

   case WM_VKEYTOITEM:
                if(lbfocus)
                {
                 int real;

                 real=SendDlgItemMessage(hwndDlg,108,LB_GETCURSEL,0,(LPARAM)(LPSTR)0);
                 switch((int)LOWORD(wParam))
                 {
                  case VK_UP:
                              /* mmmm....recursive goodness */
                              if(!real)
                               SendMessage(hwndDlg,WM_VSCROLL,SB_LINEUP,0);
                              return(-1);
                              break;
                  case VK_DOWN:
                              if(real==(CSTOD-1))
                               SendMessage(hwndDlg,WM_VSCROLL,SB_LINEDOWN,0);
                              return(-1);
                              break;
                  case VK_PRIOR:
                              SendMessage(hwndDlg,WM_VSCROLL,SB_PAGEUP,0);
                              break;
                  case VK_NEXT:
                              SendMessage(hwndDlg,WM_VSCROLL,SB_PAGEDOWN,0);
                              break;
                  case VK_HOME:
                              SendMessage(hwndDlg,WM_VSCROLL,SB_TOP,0);
                              break;
                  case VK_END:
                              SendMessage(hwndDlg,WM_VSCROLL,SB_BOTTOM,0);
                              break;
                 }
                 return(-2);
                }
                break;

   case WM_CLOSE:
   case WM_QUIT: goto gornk;
   case WM_COMMAND:
                switch(LOWORD(wParam))
                {
                 case 300:      /* List box selection changed. */
                        if(HIWORD(wParam)==LBN_SELCHANGE)
                        {
                         char *s;
                         uint32 a;
                         uint8 v;
                         int status;
                         int c,type;

                         selcheat=SendDlgItemMessage(hwndDlg,300,LB_GETCURSEL,0,(LPARAM)(LPSTR)0);
                         if(selcheat<0)
                         {
                          FixCheatSelButtons(hwndDlg,0);
                          break;
                         }
                         FixCheatSelButtons(hwndDlg, 1);

                         FCEUI_GetCheat(selcheat,&s,&a,&v,&c,&status,&type);
                         SetDlgItemText(hwndDlg,200,(LPTSTR)s);
                         SetDlgItemText(hwndDlg,201,(LPTSTR)U16ToStr(a));
                         SetDlgItemText(hwndDlg,202,(LPTSTR)U8ToStr(v));
                         SetDlgItemText(hwndDlg,203,(c==-1)?(LPTSTR)"":(LPTSTR)IToStr(c));
                         CheckDlgButton(hwndDlg,204,type?BST_CHECKED:BST_UNCHECKED);
                        }
                        break;
                 case 108:
                        switch(HIWORD(wParam))
                        {
                         case LBN_SELCHANGE:
                                 {
                                  char TempArray[32];
                                  SendDlgItemMessage(hwndDlg,108,LB_GETTEXT,SendDlgItemMessage(hwndDlg,108,LB_GETCURSEL,0,(LPARAM)(LPSTR)0),(LPARAM)(LPCTSTR)TempArray);
                                  TempArray[4]=0;
                                  SetDlgItemText(hwndDlg,201,(LPTSTR)TempArray);
                                 }
                                 break;
                         case LBN_SETFOCUS:
                                 lbfocus=1;
                                 break;
                         case LBN_KILLFOCUS:
                                 lbfocus=0;
                                 break;
                        }
                        break;
                }

                switch(HIWORD(wParam))
                {
                 case LBN_DBLCLK:
                        if(selcheat>=0)
                        {
                         if(LOWORD(wParam)==300)
                          FCEUI_ToggleCheat(selcheat);
                         RedoCheatsLB(hwndDlg);
                         SendDlgItemMessage(hwndDlg,300,LB_SETCURSEL,selcheat,0);
                        }
                        break;

                 case BN_CLICKED:
                        if(LOWORD(wParam)>=115 && LOWORD(wParam)<=120)
                         scheatmethod=LOWORD(wParam)-115;
                        else switch(LOWORD(wParam))
                        {
                         case 112:
                          FCEUI_CheatSearchBegin();
                          DoGet();
                          break;
                         case 113:
                          FCEUI_CheatSearchEnd(scheatmethod,cheatval1,cheatval2);
                          DoGet();
                          break;
                         case 114:
                          FCEUI_CheatSearchSetCurrentAsOriginal();
                          DoGet();
                          break;
                         case 107:
                          FCEUI_CheatSearchShowExcluded();
                          DoGet();
                          break;
                         case 250:      /* Add Cheat Button */
                          {
                           int a,v,c,t;
                           char name[257];
                           char temp[16];

                           GetDlgItemText(hwndDlg,200,name,256+1);
                           GetDlgItemText(hwndDlg,201,temp,4+1);
                           a=StrToU16(temp);
                           GetDlgItemText(hwndDlg,202,temp,3+1);
                           v=StrToU8(temp);
                           GetDlgItemText(hwndDlg,203,temp,3+1);
                           if(temp[0]==0)
                            c=-1;
                           else
                            c=StrToI(temp);
                           t=(IsDlgButtonChecked(hwndDlg,204)==BST_CHECKED)?1:0;
                           FCEUI_AddCheat(name,a,v,c,t);
                           RedoCheatsLB(hwndDlg);
                           SendDlgItemMessage(hwndDlg,300,LB_SETCURSEL,selcheat,0);
                          }
                          break;
                         case 253:      /* Add GG Cheat Button */
                          {
                           uint16 a;
                           int c;
                           uint8 v;
                           char name[257];

                           GetDlgItemText(hwndDlg,200,name,256+1);

                           if(FCEUI_DecodeGG(name,&a,&v,&c))
                           {
                            FCEUI_AddCheat(name,a,v,c,1);
                            RedoCheatsLB(hwndDlg);
                            SendDlgItemMessage(hwndDlg,300,LB_SETCURSEL,selcheat,0);
                           }
                          }
                          break;

                         case 251:      /* Update Cheat Button */
                          if(selcheat>=0)
                          {
                           int a,v,c,t;
                           char name[257];
                           char temp[16];

                           GetDlgItemText(hwndDlg,200,name,256+1);
                           GetDlgItemText(hwndDlg,201,temp,4+1);
                           a=StrToU16(temp);
                           GetDlgItemText(hwndDlg,202,temp,3+1);
                           v=StrToU8(temp);
                           GetDlgItemText(hwndDlg,203,temp,3+1);
                           if(temp[0]==0)
                            c=-1;
                           else
                            c=StrToI(temp);
                           t=(IsDlgButtonChecked(hwndDlg,204)==BST_CHECKED)?1:0;
                           FCEUI_SetCheat(selcheat,name,a,v,c,-1,t);
                           RedoCheatsLB(hwndDlg);
                           SendDlgItemMessage(hwndDlg,300,LB_SETCURSEL,selcheat,0);
                          }
                          break;
                         case 252:      /* Delete cheat button */
                          if(selcheat>=0)
                          {
                           FCEUI_DelCheat(selcheat);
                           SendDlgItemMessage(hwndDlg,300,LB_DELETESTRING,selcheat,0);
                           FixCheatSelButtons(hwndDlg, 0);
                           selcheat=-1;
                           SetDlgItemText(hwndDlg,200,(LPTSTR)"");
                           SetDlgItemText(hwndDlg,201,(LPTSTR)"");
                           SetDlgItemText(hwndDlg,202,(LPTSTR)"");
                           SetDlgItemText(hwndDlg,203,(LPTSTR)"");
                           CheckDlgButton(hwndDlg,204,BST_UNCHECKED);
                          }
                          break;
                         case 106:
                          gornk:
                          EndDialog(hwndDlg,0);
                          acwin=0;
                          break;
                        }
                        break;
                 case EN_CHANGE:
                        {
                         char TempArray[256];
                         GetDlgItemText(hwndDlg,LOWORD(wParam),TempArray,256);
                         switch(LOWORD(wParam))
                         {
                          case 110:cheatval1=StrToU8(TempArray);break;
                          case 111:cheatval2=StrToU8(TempArray);break;
                         }
                        }
                        break;
                }
              }
  return 0;
}

void ConfigAddCheat(HWND wnd)
{
 if(!GI)
 {
  FCEUD_PrintError("You must have a game loaded before you can manipulate cheats.");
  return;
 }

 if(GI->type==GIT_NSF)
 {
  FCEUD_PrintError("Sorry, you can't cheat with NSFs.");
  return;
 }

 DialogBox(fceu_hInstance,"ADDCHEAT",wnd,AddCheatCallB);
}
