#include"IGScript.h"
namespace{
  bool LucaSystemFilter1(LPVOID data, size_t *size, HookParam *)
  {
    auto text = reinterpret_cast<LPSTR>(data);
    auto len = reinterpret_cast<size_t *>(size);
    StringFilter(text, len, "\x81\x94", 2);
    //秋&冬  官中
    StringReplacer(text, len, "\x82\xa1", 2,"\xa3\xac",2);//,
    StringReplacer(text, len, "\x82\xa3", 2,"\xa1\xa3",2);//。
    StringReplacer(text, len, "\x82\xa5", 2,"\xa1\xa2",2);//、
    StringReplacer(text, len, "\x83\x48", 2,"\xa1\xb1",2);//”
    StringReplacer(text, len, "\x83\x44", 2,"\xa3\xbf",2);//?
    StringReplacer(text, len, "\x83\x42", 2,"\xa3\xa1",2);//!
    StringReplacer(text, len, "\x82\xa7", 2,"\xa1\xb9",2);//」
    StringReplacer(text, len, "\x82\xc1", 2,"\xa1\xb7",2);//》
    StringReplacer(text, len, "\x83\x46", 2,"\xa1\xaf",2);//’

    return true;
  }
  template<int arg>
  void SpecialHookigi(hook_stack* stack,  HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len){
      DWORD Src = stack->stack[arg]; 
      DWORD Size = stack->stack[arg+1];
      if(strlen((char*)Src)<=2)return;
      if(strlen((char*)Src)>=Size)return;
      if(strlen((char*)Src)<Size-4)return;
      *data = Src;
      *len=strlen((char*)Src); 
      // ConsoleOutput(WideStringToString(StringToWideString((char*)Src,936).value()).c_str());
      // std::string xx;
      // for(int i=0;i<*len;i++){
      //   xx+=" "+std::to_string(*(BYTE*)(Src+i));

      // }
      // ConsoleOutput(xx.c_str());
  } 
}
bool IGScript1attach_function() {
  /*
  FLOWERS 
	* https://vndb.org/v15395
	* https://vndb.org/v14267
	* https://vndb.org/v18152
	* https://vndb.org/r82704
  */
  const BYTE bytes[] = {
    //memcpy(dst,src,size)
    0x81,0xf9,0x00,0x01,0x00,0x00,
    0x72,XX,
    0x83,0x3d,XX4,0x00,
    0x74,XX,
    0x57,0x56,
    0x83,0xe7,0x0f,
    0x83,0xe6,0x0f,
    0x3b,0xfe
  };
  HMODULE module = GetModuleHandleW(L"Script.dll");
	auto [minAddress, maxAddress] = Util::QueryModuleLimits(module);
  ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), minAddress, maxAddress);
  if (addr == 0)return false;
  addr = MemDbg::findEnclosingAlignedFunction(addr,0x100);
  if (addr == 0)return false;
  HookParam hp;
  hp.address = addr;
  const BYTE funcstart[] = {
    0x55,0x8b,0xec,0x57,0x56
  };
  bool insertgbk=memcmp(funcstart,(LPVOID*)addr,5)==0; 
  hp.text_fun=SpecialHookigi<2>;
  hp.type=NO_CONTEXT;
  //hp.filter_fun=LucaSystemFilter1;
  bool succ=NewHook(hp, "IGScript");
   
  if(insertgbk){
    hp.address +=5;
    hp.text_fun=SpecialHookigi<5>;
    //仅官中适用这个过滤器。日语原版不需要过滤
    hp.filter_fun=LucaSystemFilter1;
    succ|=NewHook(hp, "IGScript_1");
  }
  return succ;
   
} 
namespace{
  bool LucaSystemFilter(LPVOID data, size_t *size, HookParam *)
{
  auto text = reinterpret_cast<LPSTR>(data);
  auto len = reinterpret_cast<size_t *>(size);

  if ( text[0] == '\x81' && text[1] == '\x94')
    return false;

  StringCharReplacer(text, len, "\x81\x90", 2, ' '); // new line
  //replacement from Flowers 4 config.json
  CharReplacer(text, len, '\xA5', ' ');
  CharReplacer(text, len, '\xA2', '<');
  CharReplacer(text, len, '\xA3', '>');
  CharReplacer(text, len, '\xA1', '\"');
  CharReplacer(text, len, '\xA4', '\'');
  CharReplacer(text, len, '\xA7', 'à');
  CharReplacer(text, len, '\xA8', 'è');
  CharReplacer(text, len, '\xA9', 'é');
  CharReplacer(text, len, '\xAA', 'ë');
  CharReplacer(text, len, '\xAB', 'ō');
  CharReplacer(text, len, '\xB0', '-');
  CharReplacer(text, len, '\xBB', ' ');

  while(cpp_strnstr(text, "  ", *len)) // Erasing all but one whitespace from strings
    StringCharReplacer(text, len, "  ", 2, ' ');

  if (text[0] == ' ')
    ::memmove(text, text + 1, --*len);

  return true;
}

bool InsertLucaSystemHook() {
	
	/*
	* Sample games:
	* https://vndb.org/v15395
	* https://vndb.org/v14267
	* https://vndb.org/v18152
	* https://vndb.org/r82704
	*/
	const BYTE bytes[] = {
		0xCC,                       // int 3 
		0xE9, XX4,                  // jmp d3d9.dll+1E420
		0x56,                       // push esi
		0x57,                       // push edi
		0x8B, 0x7C, 0x24, 0x20,     // mov edi,[esp+20]
		0x8B, 0xD8,                 // mov ebx,eax
		0x8B, 0x07                  // mov eax,[edi]
	};
	const BYTE bytes2[] = {
		0xCC,                       // int 3 
		0x83, 0xEC, 0x0C,           // sub esp,0C      <- hook here
		0x53,                       // push ebx
		0x55,                       // push ebp
		0x56                        // push esi
	};

	HMODULE module = GetModuleHandleW(L"Script.dll");
	auto [minAddress, maxAddress] = Util::QueryModuleLimits(module);
	ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), minAddress, maxAddress);
	if (!addr) {
		addr = MemDbg::findBytes(bytes2, sizeof(bytes2), minAddress, maxAddress);
		if (!addr) {
			ConsoleOutput("LucaSystem: pattern not found");
			return false;
		}
	}

	HookParam hp;
	hp.address = addr + 1;
	hp.offset =get_stack(1);
	hp.padding = 0x04;
	hp.type = USING_STRING;
	hp.filter_fun = LucaSystemFilter; 
	

	return NewHook(hp, "LucaSystem");
}
}
bool IGScript::attach_function() {
   
  auto b1= IGScript1attach_function();
  b1=InsertLucaSystemHook()||b1;
  return b1;
   
}