#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<signal.h>
#include<X11/Intrinsic.h>
#include<X11/StringDefs.h>
#include<X11/Xaw/Form.h>
#include<X11/Xaw/Label.h>

#include"koken.h"

extern char *DefaultResources[];

static XtAppContext App;   /* アプリケーションコンテクスト */

static Widget
       Top,
       Scr,
       Game,
       Next,
       Title,
       Gameover,
       Score,
       Level,
       Highscore;


static Colormap Cmap;    /* カラーマップ */

static int IntervalState;       /* タイマ処理中? */
static XtIntervalId IntervalId; /* タイマー処理のＩＤ */

static int Title_mode;

int Map[8][13];
int Next_color[3];
int Next_dir;

int High_score;

const Dir_x[4] = { 0,1,0,-1 };
const Dir_y[4] = { -1,0,1,0 };

/* プロトタイプ宣言 */

static void timi( XtPointer c, XtIntervalId id );
void init_graph( Widget scr,Widget next );


char *Myname;   /* プログラム名 */


static void load_highscore( void )
{
  FILE *fp;
  char buf[80];

  int r;

  r = -1;

  if( (fp = fopen(".koken_score","r+" )) != NULL ){
    if( fgets(buf,80,fp ) != NULL ){
      if( sscanf(buf,"%d",&r ) != 1 )
	r = -1;
    }
    fclose(fp);
  }
  High_score = r;

  if( r >= 0 ){
    sprintf(buf,"%8d",r );
    XtVaSetValues( Highscore,XtNlabel,buf,NULL );
  }

}

void save_highscore( int i )
{
  FILE *fp;

  if( High_score < 0 )
    return;

  if( i != -1 && i != High_score )
    return;

  if( (fp = fopen(".koken_score","w")) != NULL ){
    fprintf(fp,"%d\n",High_score );
    fclose( fp );
  }
}



/* タイマー中断 */

static void reset_timer( void )
{
  if( IntervalState ){
    XtRemoveTimeOut( IntervalId );
    IntervalState = 0;
  }
}


/* タイマースタート */

static void set_timer( int t )
{
  if( IntervalState )
    reset_timer();
  IntervalId = XtAppAddTimeOut( App, t ,(XtTimerCallbackProc)timi,NULL );
  IntervalState = 1;
}


/* タイマー処理ルーチン */

static void timi( XtPointer c,XtIntervalId id )
{
  IntervalState = 0;
  set_timer( game() );
}


/* エクスポーズ処理 (イベントハンドラ) / screen */

static void expose_scr( Widget w,XtPointer p,XEvent *e )
{
  int sx,xx,yy,y,x;

  sx = e->xexpose.x / 32;
  y = e->xexpose.y / 32;
  xx = (e->xexpose.x + e->xexpose.width - 1) / 32;
  yy = (e->xexpose.y + e->xexpose.height - 1) / 32;

  for( ; y <= yy ; y++ )
    for( x = sx ; x <= xx ; x++ )
      draw_map( x,y );
}

/* エクスポーズ処理 (イベントハンドラ) / next */

static void expose_next( Widget w,XtPointer p,XEvent *e )
{
  if( e->xexpose.count )
    return;

  draw_next();
}


/* プログラム終了 (アクションハンドラ) */

static void key_quit( Widget w,XEvent *e,String *s,Cardinal *num )
{
#if 1
  exit(0);
#endif
}


static void key_right( Widget w,XEvent *e,String *s,Cardinal *num )
{
  move_right();
}

static void key_left( Widget w,XEvent *e,String *s,Cardinal *num )
{
  move_left();
}

static void key_rotate( Widget w,XEvent *e,String *s,Cardinal *num )
{
  rotate();
}


static void key_fall_on( Widget w,XEvent *e,String *s,Cardinal *num )
{
  if( fall_on() )
    set_timer( game() );
}


static void key_fall_off( Widget w,XEvent *e,String *s,Cardinal *num )
{
  fall_off();
}

static void key_start( Widget w,XEvent *e,String *s,Cardinal *num )
{
  switch( push_start() ){
  case 1:
    set_timer( start_game() );
    break;

  case 2:
    set_timer( game() );
    break;
  }
}

static void key_color_up( Widget w,XEvent *e,String *s,Cardinal *num )
{
  change_color(0);
}

static void key_color_down( Widget w,XEvent *e,String *s,Cardinal *num )
{
  change_color(1);
}

  

void show_title( int mode )
{
  if( mode < 0 )
    Title_mode = !Title_mode;
  else
    Title_mode = mode;

  if( Title_mode )
    XtMapWidget( Title );
  else
    XtUnmapWidget( Title );
}


void show_gameover( int mode )
{
  if( mode )
    XtMapWidget( Gameover );
  else
    XtUnmapWidget( Gameover );
}

void show_score( int mult, int score )
{
  char buf[32];

  if( mult )
    sprintf(buf,"%4d*%3d\n=%7d",score,mult,score*mult );
  else
    sprintf(buf,"%8d\n        ",score );

  XtVaSetValues( Score,XtNlabel,buf,NULL );

  if( mult == 0 && score > High_score ){
    High_score = score;
    sprintf(buf,"%8d",High_score );
    XtVaSetValues( Highscore,XtNlabel,buf,NULL );
   }
}

void show_level( int l )
{
  char buf[32];

  sprintf(buf,"%8d",l );
  XtVaSetValues( Level,XtNlabel,buf,NULL );
}

    
/* メイン */

int main( int argc,char **argv )
{
  static XtActionsRec a_table[] = {
    {"start",(XtActionProc)key_start},
    {"quit",(XtActionProc)key_quit},
    {"move_right", (XtActionProc)key_right},
    {"move_left",(XtActionProc)key_left},
    {"rotate",(XtActionProc)key_rotate},
    {"fall_start",(XtActionProc)key_fall_on},
    {"fall_end",(XtActionProc)key_fall_off},
    {"color_up",(XtActionProc)key_color_up},
    {"color_down",(XtActionProc)key_color_down},
  };

  Widget game,w;

  srandom( getpid() ^ time(NULL) );
  if( (Myname = argv[0]) == NULL )
    Myname = "koken";

  XtSetLanguageProc( NULL,NULL,NULL );

  Top = XtVaAppInitialize( &App,"Koken",NULL,0,
			  &argc,argv,DefaultResources,NULL );

  game = XtVaCreateManagedWidget( "game",formWidgetClass,Top,NULL );

  Title = XtVaCreateManagedWidget( "title",labelWidgetClass,game,
				  NULL );

  Gameover = XtVaCreateManagedWidget( "gameover",labelWidgetClass,game,
				     XtNmappedWhenManaged,FALSE,
				     NULL );

  Scr = XtVaCreateManagedWidget( "scr",widgetClass,game,
				XtNwidth,32*8,
				XtNheight,32*13,
				NULL );

  XtVaCreateManagedWidget("nextLabel",labelWidgetClass,game,
			  NULL );

  Next = XtVaCreateManagedWidget( "next",widgetClass,game,
				 XtNwidth,64,
				 XtNheight,64,
				 NULL );

  XtVaCreateManagedWidget( "hiscLabel",labelWidgetClass,game,
			  NULL );

  Highscore = XtVaCreateManagedWidget( "hisc",labelWidgetClass,game,
				  XtNlabel,"00000000",
				  NULL );

  XtVaCreateManagedWidget( "scoreLabel",labelWidgetClass,game,
			  NULL );

  Score = XtVaCreateManagedWidget( "score",labelWidgetClass,game,
				  XtNlabel,"00000000\n        ",
				  NULL );

  XtVaCreateManagedWidget( "levelLabel",labelWidgetClass,game,
			  NULL );

  Level = XtVaCreateManagedWidget( "level",labelWidgetClass,game,
				  XtNlabel,"00000000 ",
				  NULL );


  XtAddEventHandler(Scr,ExposureMask,FALSE,(XtEventHandler)expose_scr,NULL );
  XtAddEventHandler(Next,ExposureMask,FALSE,(XtEventHandler)expose_next,NULL );

  XtAppAddActions( App,a_table,XtNumber(a_table) );

  XtRealizeWidget( Top );
  init_graph(Scr,Next);

  Title_mode = 1;

  load_highscore();

  init_game();

  set_timer( 10 );
  XtAppMainLoop( App );

  return 0;
}
