/******************************************************************************/
/*                                                                            */
/*                              DIPSWITCH SUPPORT                             */
/*                                                                            */
/******************************************************************************/

#include "raine.h"
#include "games.h"
#include "dsw.h"
#include "control.h"
#include "arpro.h"

void write_dsw(UINT32 address, UINT8 data)
{
   if(address < 0x100)

      input_buffer[address] = data;

   else

      RAM[address] = data;
}

void make_dipswitch_bytes(void)
{
   UINT32 ta,tb,tc,i;

   for(i=0;i<MAX_DIPSWITCHES; i++){

   if(dipswitch[i].count){

      for(ta=0;ta<dipswitch[i].statcount;ta++){
         tb = dipswitch[i].statlist[ta].pos;
         tc = dipswitch[i].statlist[ta].pos + dipswitch[i].statlist[ta].offset + 1;
         tb = dipswitch[i].diplist[tb].bits;
         tc = dipswitch[i].diplist[tc].bits;
         dipswitch[i].value &= ~tb;			// Clear bits
         dipswitch[i].value |= (tc & tb);		// Set bits
      }
      write_dsw(dipswitch[i].address, dipswitch[i].value);
      print_debug("DSW %d: %02x\n",i,dipswitch[i].value);

   }

   }

   make_dipswitch_statlist();
}

void make_dipswitch_statlist(void)
{
   UINT32 ta,tb,tc,td,te,i;

   for(i=0;i<MAX_DIPSWITCHES;i++){

      if(dipswitch[i].count){
         for(ta=0;ta<dipswitch[i].statcount;ta++){
            tb = dipswitch[i].statlist[ta].pos;
            tc = dipswitch[i].diplist[tb].bits;
            td = dipswitch[i].value & tc;

            for(te=0;te<dipswitch[i].diplist[tb].values;te++){
               tc = dipswitch[i].diplist[tb+te+1].bits;
               if(td==tc){
                  dipswitch[i].statlist[ta].offset = te;
               }
            }
         }
         write_dsw(dipswitch[i].address, dipswitch[i].value);
      }

   }

}

// RestoreDSWDefault():
// Restores DSW to the factory settings
// Does not modify DSW info lists, call make_dipswitch_statlist
// to update them...

void RestoreDSWDefault(void)
{
   int i;

   for(i=0;i<MAX_DIPSWITCHES;i++)
      dipswitch[i].value = dipswitch[i].def;
}

void init_dsw(void)
{
   const DSW_INFO *dsw_src;
   DSW_DATA *dsw_data;
   int ta,tb,tc;

   for(ta = 0; ta < MAX_DIPSWITCHES; ta++){

      dipswitch[ta].address   = 0;
      dipswitch[ta].count     = 0;
      dipswitch[ta].statcount = 0;

   }

   dsw_src = current_game->dsw_list;

   if(dsw_src){

   ta=0;

   while(dsw_src[ta].data){

   dsw_data = dsw_src[ta].data;

   dipswitch[ta].def       = dsw_src[ta].factory_setting;
   dipswitch[ta].value     = dsw_src[ta].factory_setting;
   dipswitch[ta].address   = dsw_src[ta].offset;

   tb = 0;
   tc = 0;

   while(dsw_data[tb].name){

      dipswitch[ta].diplist[tb].DSWName = dsw_data[tb].name;
      dipswitch[ta].diplist[tb].bits    = dsw_data[tb].bit_mask;
      dipswitch[ta].diplist[tb].values  = dsw_data[tb].count;

      if(dsw_data[tb].count){
         dipswitch[ta].statlist[tc].pos    = tb;
         dipswitch[ta].statlist[tc].offset = 0;
         tc++;
      }

      tb++;

   }

   dipswitch[ta].count     = tb;
   dipswitch[ta].statcount = tc;

   ta++;

   }

   }
}

struct DSW_DATA dsw_data_default_0[] =
{
   { MSG_DSWA_BIT1,           0x01, 0x02 },
   { MSG_OFF,                 0x01, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWA_BIT2,           0x02, 0x02 },
   { MSG_OFF,                 0x02, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWA_BIT3,           0x04, 0x02 },
   { MSG_OFF,                 0x04, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWA_BIT4,           0x08, 0x02 },
   { MSG_OFF,                 0x08, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWA_BIT5,           0x10, 0x02 },
   { MSG_OFF,                 0x10, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWA_BIT6,           0x20, 0x02 },
   { MSG_OFF,                 0x20, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWA_BIT7,           0x40, 0x02 },
   { MSG_OFF,                 0x40, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWA_BIT8,           0x80, 0x02 },
   { MSG_OFF,                 0x80, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { NULL,                    0,    0,   },
};

struct DSW_DATA dsw_data_default_1[] =
{
   { MSG_DSWB_BIT1,           0x01, 0x02 },
   { MSG_OFF,                 0x01, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWB_BIT2,           0x02, 0x02 },
   { MSG_OFF,                 0x02, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWB_BIT3,           0x04, 0x02 },
   { MSG_OFF,                 0x04, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWB_BIT4,           0x08, 0x02 },
   { MSG_OFF,                 0x08, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWB_BIT5,           0x10, 0x02 },
   { MSG_OFF,                 0x10, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWB_BIT6,           0x20, 0x02 },
   { MSG_OFF,                 0x20, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWB_BIT7,           0x40, 0x02 },
   { MSG_OFF,                 0x40, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWB_BIT8,           0x80, 0x02 },
   { MSG_OFF,                 0x80, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { NULL,                    0,    0,   },
};

struct DSW_DATA dsw_data_default_2[] =
{
   { MSG_DSWC_BIT1,           0x01, 0x02 },
   { MSG_OFF,                 0x01, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWC_BIT2,           0x02, 0x02 },
   { MSG_OFF,                 0x02, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWC_BIT3,           0x04, 0x02 },
   { MSG_OFF,                 0x04, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWC_BIT4,           0x08, 0x02 },
   { MSG_OFF,                 0x08, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWC_BIT5,           0x10, 0x02 },
   { MSG_OFF,                 0x10, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWC_BIT6,           0x20, 0x02 },
   { MSG_OFF,                 0x20, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWC_BIT7,           0x40, 0x02 },
   { MSG_OFF,                 0x40, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { MSG_DSWC_BIT8,           0x80, 0x02 },
   { MSG_OFF,                 0x80, 0x00 },
   { MSG_ON,                  0x00, 0x00 },
   { NULL,                    0,    0,   },
};


UINT8 get_dsw(int i)
{
   return dipswitch[i].value;
}

static char *save_name[MAX_DIPSWITCHES] =
{
  "dswa", "dswb", "dswc", "dswd", "dswe", "dswf", "dswg", "dswh", "dswi",
  "dswj"
};

void load_dipswitches(char *section)
{
   int i;

   for(i = 0; i < MAX_DIPSWITCHES; i++)
      if(dipswitch[i].count)
         dipswitch[i].value = raine_get_config_hex(section, save_name[i], dipswitch[i].value);

   make_dipswitch_statlist();
}

void save_dipswitches(char *section)
{
   int i;

   for(i = 0; i < MAX_DIPSWITCHES; i++)
      if(dipswitch[i].count)
         raine_set_config_hex(section, save_name[i], dipswitch[i].value);
}

/******************************************************************************/
/*                                                                            */
/*         ROM SWITCH SUPPORT (consider them unofficial dip switches)         */
/*                                                                            */
/******************************************************************************/

/*

todo:

- multiple romswitch support : required for sfzch
   you are allowed to specify multiple offsets in the ROMSW_INFO struct
   but this address will get the same data from the ROMSW_DATA struct.
- multiple byte patchin support (also not required)
- remove array limit on number of rom switch states (better code)

*/

void init_romsw(void)
{
  const ROMSW_INFO *romsw_src;
  ROMSW_DATA *romsw_data;
  int ta,tb;

  LanguageSw.Address = 0;
  LanguageSw.Count   = 0;

  ta=0;

  romsw_src = current_game->romsw_list;

  if(romsw_src){

    while(romsw_src[ta].data){

      romsw_data = romsw_src[ta].data;

      LanguageSw.Address      = romsw_src[ta].offset;
      LanguageSw.def          = romsw_src[ta].factory_setting;

      tb = 0;

      while(romsw_data[tb].name){

	LanguageSw.Mode[tb] = romsw_data[tb].name;
	LanguageSw.Data[tb] = romsw_data[tb].data;
	tb++;

      }

      LanguageSw.Count    = tb;
      gen_cpu_write_byte(LanguageSw.Address,LanguageSw.def);

      ta++;

    }
  }
}

void SetupLanguageSwitch(UINT32 addr)
{
   LanguageSw.Address=addr;
   LanguageSw.Count=0;
}

void AddLanguageSwitch(UINT8 ldata, char *lname)
{
   LanguageSw.Mode[LanguageSw.Count]=lname;
   LanguageSw.Data[LanguageSw.Count]=ldata;
   LanguageSw.Count++;
}

void SetLanguageSwitch(int number)
{
  const ROMSW_INFO *romsw_src;
  int ta;

  romsw_src = current_game->romsw_list;
  ta = 0;
  if(romsw_src){

    while(romsw_src[ta].data){

      LanguageSw.Address      = romsw_src[ta++].offset;
      gen_cpu_write_byte(LanguageSw.Address,LanguageSw.Data[number]);
    }
  }
}

int GetLanguageSwitch(void)
{
   int ta,tb;

   if(LanguageSw.Address){

      tb = gen_cpu_read_byte(LanguageSw.Address);

      for(ta=0;ta<LanguageSw.Count;ta++){
          if(LanguageSw.Data[ta]==tb)
             return ta;
      }

   }
   return 0;
}

void load_romswitches(char *section)
{
   if(LanguageSw.Address)
      SetLanguageSwitch( raine_get_config_hex(section,"Version",GetLanguageSwitch()) );
}

void save_romswitches(char *section)
{
   if(LanguageSw.Address)
      raine_set_config_hex(section,"Version",GetLanguageSwitch());
}

/******************************************************************************/
/*                                                                            */
/*                ROM PATCHING SUPPORT (something like an .ips)               */
/*                                                                            */
/******************************************************************************/

void patch_rom(UINT8 *src, ROM_PATCH *patch)
{
   int ta;

   ta = 0;

   while(patch[ta].offset != -1){

      WriteLong68k(&src[patch[ta].offset + 0], patch[ta].data_0);
      WriteLong68k(&src[patch[ta].offset + 4], patch[ta].data_1);

      ta++;
   };

}

/******************************************************************************/

