#define EX
#include "main.h"
#include "setup.h"
#include "ex.h"
#include "pixmap.h"
#include "digit.h"

/* ウィンドウを作成 */
void x_create_window(Window pwin,WINATTR *win)
{
  XSizeHints sizehints;
  XSetWindowAttributes values;
  unsigned long inputmask;

  win->win = XCreateSimpleWindow(disp,pwin,win->offset_x,win->offset_y,
				 win->width,win->height,win->bo,
				 col[Fore].pixel,col[Back].pixel);

  XStoreName(disp,win->win,win->title);
  values.bit_gravity = NorthWestGravity;
  XChangeWindowAttributes(disp,win->win,CWBitGravity,&values);

  sizehints.flags = PMinSize|PMaxSize;
  sizehints.min_width = sizehints.max_width = win->width;
  sizehints.min_height = sizehints.max_height = win->height;
  XSetWMNormalHints(disp,win->win,&sizehints);

  inputmask=EnterWindowMask|ExposureMask;
#ifdef USE_PAD
  if(!upad) inputmask|=KeyPressMask|KeyReleaseMask;
#else
  inputmask|=KeyPressMask|KeyReleaseMask;
#endif
  if(pwin==root) inputmask|=LeaveWindowMask;

  XSelectInput(disp,win->win,inputmask);

  if(priv_cmap) XSetWindowColormap(disp,win->win,cmap);

  win->pix =
    XCreatePixmap(disp,win->win,win->width,win->height,XDefaultDepth(disp,0));

  set_col(Back);
  XFillRectangle(disp,win->win,gc,0,0,win->width,win->height);
  XFillRectangle(disp,win->pix,gc,0,0,win->width,win->height);
}

/* GC を作成 */
void create_GC()
{
  XGCValues gcval;

  gcval.graphics_exposures=0;
  gc = XCreateGC(disp,root,GCGraphicsExposures,&gcval);

  gcval.function=GXor;
  or_gc = XCreateGC(disp,root,GCGraphicsExposures|GCFunction,&gcval);

  gcval.function=GXand;
  and_gc = XCreateGC(disp,root,GCGraphicsExposures|GCFunction,&gcval);
}

/* カラーマップとカラーを設定 */
void color_init()
{
  int i;

  if(priv_cmap)
    cmap = XCreateColormap(disp,root,DefaultVisual(disp,0),AllocNone);
  else
    cmap = DefaultColormap(disp,DefaultScreen(disp));

  for(i=0;i<COLORS;i++)
  {
    if( XAllocNamedColor(disp,cmap,colors[i],&col[i],&rgb) == 0 )
    {
      fprintf(stderr,"Can't Allocate color: %s\n",colors[i]);
    }
  } 
}

/* font を読み込む */
void load_font(XFontStruct *fp,char *fontname)
{
  XFontStruct *p;

  if( (p = XLoadQueryFont(disp,fontname)) == NULL )
  {
    fprintf(stderr,"Can't load font '%s'\n",fontname);
    return;
  }

  memcpy(fp,p,sizeof(XFontStruct));
}

/* 各 window のアトリビュートを設定 */
void set_win_values()
{
  w1attr.offset_x=0;
  w1attr.offset_y=0;
  w1attr.width=SIZE*(6+2+2+1)+SIZE/2;
  w1attr.height=HEIGHT*SIZE+SIZE/2-SIZE;
  w1attr.bo=1;
  strcpy(w1attr.title,TITLE);

  w2attr.offset_x=SIZE/2;
  w2attr.offset_y=SIZE/2;
  w2attr.width=SIZE*6+1;
  w2attr.height=(HEIGHT-2)*SIZE+SIZE/2+1;
  w2attr.bo=1;
  strcpy(w2attr.title,"main");

  nextattr.offset_x=SIZE*7;
  nextattr.offset_y=SIZE;
  nextattr.width=SIZE*2;
  nextattr.height=SIZE*2;
  nextattr.bo=1;
  strcpy(nextattr.title,"next");

  sgwattr.offset_x=SIZE*7;
  sgwattr.offset_y=w2attr.offset_x+w2attr.height-70;
  sgwattr.width=68;
  sgwattr.height=68;
  sgwattr.bo=1;
  strcpy(sgwattr.title,"star");

  scrwattr.offset_x=SIZE*7;
  scrwattr.offset_y=150;
  scrwattr.width=16*8;
  scrwattr.height=17;
  scrwattr.bo=1;
  strcpy(scrwattr.title,"score");

  csmwattr.offset_x=SIZE*7;
  csmwattr.offset_y=190;
  csmwattr.width=16*5;
  csmwattr.height=17;
  csmwattr.bo=1;
  strcpy(csmwattr.title,"cosmo");

  linwattr.offset_x=SIZE*7;
  linwattr.offset_y=230;
  linwattr.width=16*4;
  linwattr.height=17;
  linwattr.bo=1;
  strcpy(linwattr.title,"line");

  levwattr.offset_x=SIZE*7;
  levwattr.offset_y=270;
  levwattr.width=16*3;
  levwattr.height=17;
  levwattr.bo=1;
  strcpy(levwattr.title,"level");
}

/* X window system のイニシャライズ */
void x_init()
{
  if( (disp = XOpenDisplay(display))==NULL )
  {
    fprintf(stderr,"%s: Cannot open display (%s)\n",av[0],display);
    exit(-1);
  }

  set_win_values();

  root = RootWindow(disp,0);

/* カラーを設定 */
  color_init();

/* GC を作成 */
  create_GC();

/* font の設定 */
  load_font(&fonts[FNT10],FN10);
  load_font(&fonts[FNT14],BT14);
  load_font(&fonts[FNT24],BN24);
  load_font(&fonts[FNT34],BN34);

/* ウィンドウを作る */
  x_create_window(root,&w1attr);
  x_create_window(w1attr.win,&w2attr);
  x_create_window(w1attr.win,&nextattr);
  x_create_window(w1attr.win,&sgwattr);
  x_create_window(w1attr.win,&scrwattr);
  x_create_window(w1attr.win,&csmwattr);
  x_create_window(w1attr.win,&linwattr);
  x_create_window(w1attr.win,&levwattr);

  mwin=w2attr.pix;

  key=0;
  pushedkey=0;
  qp_f=0;

/* 裏ウィンドウ(pixmap) を作成 */
  make_pixmaps();
}

/* X の終了 */
void x_end()
{
  if(disp!=NULL)
  {
    XAutoRepeatOn(disp);
    XCloseDisplay(disp);
  }
}

/* 変更された部分を可視ウィンドウにコピー */
void x_flush()
{
  if(miny<0) miny=0;
  if(minx<maxx)
    XCopyArea(disp,mwin,w2attr.win,gc,minx,miny,maxx-minx,maxy-miny,minx,miny);

  minx=w2attr.width;
  miny=w2attr.height;
  maxx=0;
  maxy=0;

  XFlush(disp);
}

/* キーリピートを on */
void keyrepeaton()
{
  XAutoRepeatOn(disp);
}

/* キーリピートを off */
void keyrepeatoff()
{
  XAutoRepeatOff(disp);
}

/* 再描画 */
void manage_expose(XExposeEvent *exevent)
{
  Window source_win;

       if(exevent->window == w1attr.win   ) source_win=w1attr.pix;
  else if(exevent->window == w2attr.win   ) source_win=w2attr.pix;
  else if(exevent->window == nextattr.win ) source_win=nextattr.pix;
  else if(exevent->window == sgwattr.win  ) source_win=sgwattr.pix;
  else if(exevent->window == scrwattr.win ) source_win=scrwattr.pix;
  else if(exevent->window == csmwattr.win ) source_win=csmwattr.pix;
  else if(exevent->window == linwattr.win ) source_win=linwattr.pix;
  else if(exevent->window == levwattr.win ) source_win=levwattr.pix;
  else return;

  XCopyArea(disp,source_win,exevent->window,gc,
	    exevent->x,exevent->y,exevent->width,exevent->height,
	    exevent->x,exevent->y);
}

/* キーが押された */
void keypress(XKeyEvent *kevent)
{
  key=XLookupKeysym(kevent,0);
  if(key==keys.quit||key==keys.pause) qp_f=key;
  pushedkey++;
}

/* キーが離された */
void keyrelease(XKeyEvent *kevent)
{
  pushedkey--;
  if(pushedkey==0) key=0;
}

/* イベントを監視 */
int get_event(int f)
{
  event.type=0;

#ifdef USE_PAD
  if(upad)
  {
    key=pad();
    if(event.type!=0) return True;
    f=0;
  }
#endif

  if(f==0 && XPending(disp)==0) return False;

label:

  XNextEvent(disp,&event);

  switch(event.type)
  {
    case KeyPress:	keypress((XKeyEvent *)&event); break;
    case KeyRelease:	keyrelease((XKeyEvent *)&event);
                        if(XPending(disp)>0) goto label;
			break;
    case EnterNotify:	keyrepeatoff(); break;
    case LeaveNotify:	keyrepeaton(); break;
    case Expose:	manage_expose((XExposeEvent *)&event); break;
  }

  return True;
}

/* Game 画面を作成 */
void mk_sgw()
{
  XCopyArea(disp,background,sgwattr.pix,gc,
	    sgwattr.offset_x,sgwattr.offset_y,
	    sgwattr.width+2,sgwattr.height+2,-1,-1);
  XCopyArea(disp,mask ,sgwattr.pix,and_gc,
	    sp[STAR_BW].x,sp[STAR_BW].y,
	    sp[STAR_BW].width,sp[STAR_BW].height,
	    1,1);
  XCopyArea(disp,chara,sgwattr.pix, or_gc,
	    sp[STAR_BW].x,sp[STAR_BW].y,
	    sp[STAR_BW].width,sp[STAR_BW].height,
	    1,1);

  set_col(Fore);
  XDrawLine(disp,sgwattr.pix,gc, 1,44, 1,64);
  XDrawLine(disp,sgwattr.pix,gc, 2,43,22,43);
  XDrawLine(disp,sgwattr.pix,gc, 2,65,22,65);
  XDrawLine(disp,sgwattr.pix,gc,23,42,44,21);
  XDrawLine(disp,sgwattr.pix,gc,23,64,44,43);
  XDrawLine(disp,sgwattr.pix,gc,45,20,65,20);
  XDrawLine(disp,sgwattr.pix,gc,45,42,65,42);
  XDrawLine(disp,sgwattr.pix,gc,66,21,66,41);

  set_col(Back);
  XDrawLine(disp,sgwattr.pix,gc, 2,44, 2,64);
  XDrawLine(disp,sgwattr.pix,gc, 2,44,22,44);
  XDrawLine(disp,sgwattr.pix,gc, 2,64,22,64);
  XDrawLine(disp,sgwattr.pix,gc,23,43,44,22);
  XDrawLine(disp,sgwattr.pix,gc,23,63,44,42);
  XDrawLine(disp,sgwattr.pix,gc,45,21,65,21);
  XDrawLine(disp,sgwattr.pix,gc,45,41,65,41);
  XDrawLine(disp,sgwattr.pix,gc,65,21,65,41);

  XDrawLine(disp,sgwattr.pix,gc, 0,44, 0,64);
  XDrawLine(disp,sgwattr.pix,gc, 2,42,22,42);
  XDrawLine(disp,sgwattr.pix,gc, 2,66,22,66);
  XDrawLine(disp,sgwattr.pix,gc,23,41,44,20);
  XDrawLine(disp,sgwattr.pix,gc,23,65,44,44);
  XDrawLine(disp,sgwattr.pix,gc,45,19,65,19);
  XDrawLine(disp,sgwattr.pix,gc,45,43,65,43);
  XDrawLine(disp,sgwattr.pix,gc,67,21,67,41);

  XCopyArea(disp,sgwattr.pix,sgwattr.win,gc,
	    0,0,sgwattr.width,sgwattr.height,0,0);
}

void mk_mwin()
{
  int i,j;

  XCopyArea(disp,background,mwin,gc,
	    w2attr.offset_x,w2attr.offset_y,
	    w2attr.width+2,w2attr.height+2,-1,-1);

  set_col(Line);
  for(i=0;i<=7;i++) XDrawLine(disp,mwin,gc,i*SIZE,0,i*SIZE,HEIGHT*SIZE);
  for(j=0;j<HEIGHT;j++)
    XDrawLine(disp,mwin,gc,0,j*SIZE+SIZE/2,6*SIZE,j*SIZE+SIZE/2);
}

void mk_nextwin()
{
  int i;

  XCopyArea(disp,background,nextattr.pix,gc,
	    nextattr.offset_x+1,nextattr.offset_y+1,
	    nextattr.width,nextattr.height,0,0);

  set_col(Line);
  for(i=0;i<3;i++)
  {
    XDrawLine(disp,nextattr.pix,gc,0,i*SIZE,SIZE*2,i*SIZE);
    XDrawLine(disp,nextattr.pix,gc,i*SIZE,0,i*SIZE,SIZE*2);
  }
}

void mk_scr_etc()
{
  set_font(FNT14);
  set_col(Fore);
  
  XDrawString(disp,w1attr.pix,gc,scrwattr.offset_x,scrwattr.offset_y-3,
	      "SCORE",5);
  XDrawString(disp,w1attr.pix,gc,csmwattr.offset_x,csmwattr.offset_y-3,
	      "COSMO",5);
  XDrawString(disp,w1attr.pix,gc,linwattr.offset_x,linwattr.offset_y-3,
	      "LINE",4);
  XDrawString(disp,w1attr.pix,gc,levwattr.offset_x,levwattr.offset_y-3,
	      "LEVEL",5);

  XCopyArea(disp,background,scrwattr.pix,gc,
	    scrwattr.offset_x+1,scrwattr.offset_y+1,
	    scrwattr.width,scrwattr.height,0,0);
  XCopyArea(disp,background,csmwattr.pix,gc,
	    csmwattr.offset_x+1,csmwattr.offset_y+1,
	    csmwattr.width,csmwattr.height,0,0);
  XCopyArea(disp,background,linwattr.pix,gc,
	    linwattr.offset_x+1,linwattr.offset_y+1,
	    linwattr.width,linwattr.height,0,0);
  XCopyArea(disp,background,levwattr.pix,gc,
	    levwattr.offset_x+1,levwattr.offset_y+1,
	    levwattr.width,levwattr.height,0,0);

  put_scr(-1);
  put_kill_cosmo(-1);
  put_line(-1);
  put_level(-1);
}

void mk_game_window()
{
  minx=0;
  miny=0;
  maxx=w2attr.width;
  maxy=w2attr.height;

  XCopyArea(disp,background,w1attr.pix,gc,0,0,w1attr.width,w1attr.height,0,0);

  mk_nextwin();
  mk_mwin();
  mk_sgw();
  mk_scr_etc();

  XCopyArea(disp,w1attr.pix,w1attr.win,gc,0,0,w1attr.width,w1attr.height,0,0);

  XMapWindow(disp,w2attr.win);
  XMapWindow(disp,nextattr.win);
  XMapWindow(disp,sgwattr.win);
  XMapWindow(disp,scrwattr.win);
  XMapWindow(disp,csmwattr.win);
  XMapWindow(disp,linwattr.win);
  XMapWindow(disp,levwattr.win);

  x_flush();
}

/* 文字列の横幅を測る */
int x_get_word_width(int id,char *word)
{
  return XTextWidth(&fonts[id],word,strlen(word));
}
