#define SETUP
#include "main.h"
#include "setup.h"
#include "ex.h"

#ifdef USE_PAD
static Keymap pkeys;
#endif

void set_default_values()
{ 
  int i;
  char buf[32];

/* デフォルトのキー配置 */
  keys.rot    = XK_Up;
  keys.down   = XK_Down;
  keys.up     = XK_Up;
  keys.fall   = XK_Down;
  keys.drop   = XK_space;
  keys.left   = XK_Left;
  keys.right  = XK_Right;
  keys.star   = XK_Control_L;
  keys.yes    = XK_y;
  keys.no     = XK_n;
  keys.decide = XK_space;
  keys.quit   = XK_q;
  keys.pause  = XK_p;

/* デフォルトのカラーを設定 */
  strcpy(colors[Back  ],"Black");
  strcpy(colors[Fore  ],"White");
  strcpy(colors[Line  ],"Gray80");
  strcpy(colors[Star1 ],"maroon");
  strcpy(colors[Star2 ],"azure3");
  strcpy(colors[Star3 ],"honeydew");
  strcpy(colors[Black ],"Black");
  strcpy(colors[White ],"White");
  strcpy(colors[Easy  ],"#55eeff");
  strcpy(colors[Normal],"#ddeeff");
  strcpy(colors[Hard  ],"#ff55ee");
  strcpy(colors[Expert],"#ff0000");
  strcpy(colors[Quit  ],"#aa00ff");
  strcpy(colors[Title ],"#ffff77");

  for(i=0;i<16;i++)
  {
    sprintf(buf,"#%02x%02x%02x",127+i*8,127+i*8,255);
    strcpy(colors[Blue1+i],buf);
  }

/* 背景画(デフォルトは無し) */
  bgfn[0]='\0';

/* カラーマップ(デフォルトはプライベート) */
  priv_cmap=1;

/* １秒間に入る(入って欲しい)タイマ割り込みの回数 64 or 32 */
  ALRM_PAR_SEC=64;

#ifdef USE_PAD
  upad=0;
  strcpy(pad_dev,"/dev/pad00");
  pkeys.up     = 0x001;
  pkeys.down   = 0x002;
  pkeys.left   = 0x004;
  pkeys.right  = 0x008;
  pkeys.rot    = 0x020;
  pkeys.drop   = 0x002;
  pkeys.fall   = 0xfff;
  pkeys.star   = 0x021;
  pkeys.yes    = 0xfff;
  pkeys.no     = 0xfff;
  pkeys.decide = 0x020;
  pkeys.quit   = 0x0c0;
  pkeys.pause  = 0x040;
#endif
}

/* Usage を表示 */
void show_usage()
{
  printf("Cosmo Gang the Puzzle ver %s\n",VERSION);
  printf("Usage: %% %s [-options args...]\n",av[0]);
  printf(" Options\n");
  printf("  -display [displayname] : X server to contact\n");
  printf("  -cmap [private/public] : use private or public color-map\n");
  printf("  -bg [filename]         : set background (non-press-TIFF)\n");
  printf("  -rough                 : draw roughly\n");
  printf("  -smooth                : draw smoothly\n");
  printf("  -help                  : show this message\n");
#ifdef USE_PAD
  printf("  -pad [device/no]       : use pad (device) or not use (no)\n");
#endif
  exit(0);
}  

/* 引数を得る */
void get_arg()
{
  int i;

  for(i=1;i<ac;i++)
  {
         if(!strcmp(av[i],"-display"))
    {
      i++;
      if(i>=ac) break;
      strcpy(display,av[i]);
    }
    else if(!strcmp(av[i],"-cmap"))
    {
      i++;
      if(i>=ac) show_usage();
           if(!strcmp(av[i],"public" )) priv_cmap=0;
      else if(!strcmp(av[i],"private")) priv_cmap=1;
      else show_usage();
    }
    else if(!strcmp(av[i],"-bg"))
    {
      i++;
      if(i>=ac) show_usage();
      strcpy(bgfn,av[i]);
    }
    else if(!strcmp(av[i],"-rough"))
    {
      ALRM_PAR_SEC=32;
    }
    else if(!strcmp(av[i],"-smooth"))
    {
      ALRM_PAR_SEC=64;
    }
    else if(!strcmp(av[i],"-help"))
    {
      show_usage();
    }
#ifdef USE_PAD
    else if(!strcmp(av[i],"-pad"))
    {
      i++;
      if(i>=ac) show_usage();
      if(strcmp(av[i],"no")) strcpy(pad_dev,av[i]);
                        else upad=0;
    }
#endif
    else show_usage();
  }
}

/* passwd からユーザのデータを得る */
void get_user_data()
{
  struct passwd *p;

  user.uid=getuid();
  p=getpwuid(user.uid);
  strcpy(user.name,p->pw_name);
  strcpy(home_dir,p->pw_dir);
  if( home_dir[strlen(home_dir)-1] != '/' ) strcat(home_dir,"/");
  strcpy(rc_file,home_dir);
  strcat(rc_file,".cosmorc");
}

/* 文字列(buf)の n 番目の要素を返す */
char *getnword(char *buf,int n)
{
  int i,j=0;
  static char word[256];

  for(i=0;i<=n;i++)
  {
    if(i!=0) while(buf[j]!=' '&&buf[j]!='\t'&&buf[j]!='\0'&&buf[j]!=0xa) j++;
    while(buf[j]==' '||buf[j]=='\t') j++;
    if(buf[j]=='\0' || buf[j]=='\n' || buf[j]==0xa ) return NULL;
  }

  i=0;
  while(buf[j]!=' '&&buf[j]!='\t'&&buf[j]!='\0'&&buf[j]!=0xa)
  {
    if(i>63) return NULL;
    word[i++]=buf[j++];
  }
  word[i]='\0';

  return word;
}

/* 色を変える */
void set_color(char *buf,int line)
{
  char *p,colorname[64],color[64];

  if( (p=getnword(buf,1))==NULL )
  {
    show_error("Too Few Arguments",buf,line,2);
    return;
  }
  strcpy(colorname,p);

  if( (p=getnword(buf,2))==NULL )
  {
    show_error("Too Few Arguments",buf,line,3);
    return;
  }
  strcpy(color,p);

       if( !strcmp(colorname,"Background") ) strcpy(colors[Back],color);
  else if( !strcmp(colorname,"Foreground") ) strcpy(colors[Fore],color);
  else if( !strcmp(colorname,"Line"      ) ) strcpy(colors[Line],color);
  else show_error("Wrong Color Code",colorname,line,2);
}

int xtoi(char *x)
{
  int ret=0;

  while(*x!='\0')
  {
    ret*=0x10;
    if(*x>='0'&&*x<='9') ret+=*x-'0';
    if(*x>='a'&&*x<='f') ret+=*x-'a'+10;
    if(*x>='A'&&*x<='F') ret+=*x-'A'+10;
    x++;
  }

  return ret;
}

/* key 配置を変える */
void define_key(char *buf,int line,Keymap *km)
{
  KeySym ks;
  char *p,keyname[64],key[64];

  if( (p=getnword(buf,1))==NULL )
  {
    show_error("Too Few Arguments",buf,line,2);
    return;
  }
  strcpy(keyname,p);

  if( (p=getnword(buf,2))==NULL )
  {
    show_error("Too Few Arguments",buf,line,3);
    return;
  }
  strcpy(key,p);

  if( (ks=XStringToKeysym(key)) == 0 )
  {
    if( key[0]!='#' )
    {
      show_error("Wrong Key Code",key,line,3);
      return;
    }
    else
      ks=xtoi(&key[1]);
  }

       if( !strcmp(keyname,"Rotate") ) km->rot   =ks;
  else if( !strcmp(keyname,"Up"    ) ) km->up    =ks;
  else if( !strcmp(keyname,"Down"  ) ) km->down  =ks;
  else if( !strcmp(keyname,"Drop"  ) ) km->drop  =ks;
  else if( !strcmp(keyname,"Fall"  ) ) km->fall  =ks;
  else if( !strcmp(keyname,"Left"  ) ) km->left  =ks;
  else if( !strcmp(keyname,"Right" ) ) km->right =ks;
  else if( !strcmp(keyname,"Star"  ) ) km->star  =ks;
  else if( !strcmp(keyname,"Yes"   ) ) km->yes   =ks;
  else if( !strcmp(keyname,"No"    ) ) km->no    =ks;
  else if( !strcmp(keyname,"Decide") ) km->decide=ks;
  else if( !strcmp(keyname,"Quit"  ) ) km->quit  =ks;
  else if( !strcmp(keyname,"Pause" ) ) km->pause =ks;
  else show_error("Wrong Key Name",keyname,line,2);
}

void set_key(char *buf,int line)
{
  define_key(buf,line,&keys);
}

/* background の絵のファイル名を変更 */
void set_bg(char *buf,int line)
{
  int i;
  char *p;
  char name[256];
  struct passwd *pswd;

  if( (p=getnword(buf,1))==NULL )
  {
    show_error("Too Few Arguments",buf,line,2);
    return;
  }

  /* 頑張って ~ を展開 */
  if(p[0]=='~')
  {
    i=1;
    while(p[i]!='/'&&p[i]!='\0') name[i-1]=p[i++];
    name[i-1]='\0';
    if(i==1) strcpy(name,user.name);

    do
    {
      if( (pswd=getpwent())==NULL ) break;
    } while(strcmp(name,pswd->pw_name));

    if(pswd!=NULL)
    {
      strcpy(bgfn,pswd->pw_dir);
      if( bgfn[strlen(bgfn)-1]!='/' ) strcat(bgfn,"/");
      if(p[i]!='\0') strcat(bgfn,&p[i+1]);
    }
    else strcpy(bgfn,p);  /* 該当ユーザがいない場合は放っておく */
  }
  else strcpy(bgfn,p);
}

/* カラーマップの変更 */
void set_cmap(char *buf, int line)
{
  char *p;
  
  if( (p=getnword(buf,1))==NULL )
  {
    show_error("Too Few Arguments",buf,line,2);
    return;
  }

       if( !strcmp(p,"Private") ) priv_cmap=1;
  else if( !strcmp(p,"Public" ) ) priv_cmap=0;
  else show_error("Wrong Argument",p,line,2);
}

/* １秒あたりの割り込み回数の変更 */
void set_aps(char *buf,int line)
{
  char *p;
  
  if( (p=getnword(buf,1))==NULL )
  {
    show_error("Too Few Arguments",buf,line,2);
    return;
  }

       if( !strcmp(p,"True" ) ) ALRM_PAR_SEC=32;
  else if( !strcmp(p,"False") ) ALRM_PAR_SEC=64;
  else show_error("Wrong Argument",p,line,2);
}

void set_pad(char *buf,int line)
{
#ifdef USE_PAD
  char *p;

  if( (p=getnword(buf,1))==NULL )
  {
    show_error("Too Few Arguments",buf,line,2);
    return;
  }

       if( !strcmp(p,"True" ) ) upad=1;
  else if( !strcmp(p,"False") ) upad=0;
  else show_error("Wrong Argument",p,line,2);
#endif
}

void set_pad_dev(char *buf,int line)
{
#ifdef USE_PAD
  char *p;

  if( (p=getnword(buf,1))==NULL )
  {
    show_error("Too Few Arguments",buf,line,2);
    return;
  }

  strcpy(pad_dev,p);
#endif
}

void set_pad_key(char *buf,int line)
{
#ifdef USE_PAD
  define_key(buf,line,&pkeys);
#endif
}

static COMMAND command[] = {
  { "define-key ", set_key },
  { "define-color ", set_color },
  { "background", set_bg },
  { "colormap", set_cmap },
  { "draw-roughly", set_aps },
  { "use-pad", set_pad },
  { "pad-device", set_pad_dev },
  { "define-pad", set_pad_key },
  { "", NULL }
};

/* .cosmorc を読み込む */
void read_rc()
{
  int i;
  int line;
  char buf[1024];
  char *p;
  FILE *fp;

  if( (fp=fopen(rc_file,"r")) == NULL ) return;

  for(line=1;;line++)
  {
    if( fgets(buf,1024,fp) == 0 ) break;
    for(i=0;i<strlen(buf);i++)
    {
      if(buf[i]=='!')
      {
	buf[i]='\0';
	break;
      }
    }

    if( buf[strlen(buf)-1] == 0xa ) buf[strlen(buf)-1]='\0';
    if( (p = getnword(buf,0)) == NULL ) continue;
    strcat(p," ");

    for(i=0;command[i].func!=NULL;i++)
    {
      if( !strncmp(p,command[i].name,strlen(command[i].name)) )
      {
	command[i].func(buf,line);
	break;
      }
    }
    if(command[i].func==NULL) show_error("Syntax Error",p,line,1);
  }
}

/* 各種初期設定 と カスタマイズ */
void setup()
{
  printf("\nNow Initializing... Please wait.\n");

  srandom(time(NULL));
  signal(SIGINT,end_session);

  get_user_data();
  set_default_values();
  read_rc();
  get_arg();
  rough=64/ALRM_PAR_SEC;

#ifdef USE_PAD
  if(upad) upad=pad_init(pad_dev);
  if(upad) memcpy(&keys,&pkeys,sizeof(Keymap));
#endif
  x_init();
  init_timer();

  XMapWindow(disp,w1attr.win);
  x_flush();
  XNextEvent(disp,&event);  /* window が map されるまで待つ */

  printf("Good Luck!!\n");
}
