/*
//
//   WonderSwanColor  MML Player    By melt
//
*/

#include <stdio.h>
#include <string.h>
#include <sys/bios.h>
#include <sys/libwwc.h>
#include <sys/fcntl.h>
#include <il_sound.h>

#include <LOGO.h>

/*  MML Player History

Ver 0.01  2001-01-09 ロゴ表示まで完成
    0.10       01-10 一応曲再生が可能に
    0.30             セレクター搭載
    0.31             時計表示追加
    0.32             電池消耗を少なくなるようにセレクタを変更
    0.33             曲名部にゴミが出るバグを解消
    0.34       01-31 申し込みように調整

                    "ＭｕｓｉｃＰｌａｙｅｒ Ｖ０．３０" */
#define  VERVIEW    "ＭＭＬ-Ｐｌａｙｅｒ Ｖ０．３４"

#define  TITLEWAIT  4
#define  BOOTWAIT   50
#define  TITLEYPOS  4

#define  MAXFILE    20

void print_overs(int, int, int, char);

SoundIL soundIL;
extern BYTE *_heap;


/*
//  サウンドドライバーの初期化
*/
void sound_init() {
  if(open_sound_il(&soundIL) != E_FS_SUCCESS) {
    return;
  }
  sounddrv_init();
  sound_open();
}



/*
//  起動音再生
*/
void sound01() {  /* 起動音 */
  parse_mml(_heap, "#3 O5 @E5 A16>A2", 0);
  bgm_play(_heap, PLAY_SINGLE);
}



/*
//  タイプ音再生
*/
void sound02() {  /* タイプ音 */
  parse_mml(_heap, "#3 @N0 @E3 @B0 @5 O10 C32", 0);
  bgm_play(_heap, PLAY_SINGLE);
}



/*
//  サウンドドライバー終了
*/
void sound_stop() {
  sound_close();
  sounddrv_release();
}



/* 16Color Font 関係  Thanks : http://www2.big.or.jp/~smoug/wonderwitch/ */
int wwc_font_color = 15;
/* 色を指定する */
void wwc_font_set_color(int c) {
  wwc_font_color = c;
}
/* キャラクターchar_no番に文字chを定義する(16色カラーモード） */
void wwc_font_set_text(int char_no, unsigned int ch) {
  static BYTE buff2[8];     /* モノクロデータバッファ */
  static BYTE buff16[8*4];  /* １６色カラーデータバッファ */
  int i, j;
  
  text_get_fontdata(ch, buff2);
  for(i=0; i<8; i++) {
    for(j=0; j<4; j++) {
      buff16[i*4+j] = (wwc_font_color&(1<<j)) ? buff2[i] : 0;
    }
  }
  wwc_font_set_colordata(char_no, 1, buff16);
}
/* １文字描画（１６色カラーモード） */
void wwc_text_put_char(int x, int y, unsigned int ch) {
  int no;
  
  /* 16,15 - 18,??  Logo */
  no = y*28+x+8;
  if (y > 15) {  /* Logoの位置はキャンセル */
    no = no - (y-15)*14;
  }
  wwc_font_set_text(no+42, ch);
  screen_fill_char(SCREEN1, x, y, 1, 1, no+42);
}
/* 2バイト文字の第1バイトかどうかチェック */
int isKanji1(char c) {
  if ( (c >=0x81 && c <=0x9f) || (c >=0xe0 && c <= 0xef) ) return 1;
  return 0;
}
/* 2バイト文字の第2バイトかどうかチェック */
int isKanji2(char c) {
  if ( (c >=0x40 && c <=0x7e) || (c >=0x80 && c <= 0xfc) ) return 1;
  return 0;
}
/* 文字列描画（１６色モード） */
int wwc_text_put_string( int x, int y, char far *str ) {
  int len = 0;
  unsigned ch;
  
  while ( *str != '\0' ) {
    if ( isKanji1( *str ) ) {
      ch = *str++;
      ch = (ch<<8) | *str++;
    } else {
      ch = *str++;
    }
    wwc_text_put_char(x+len, y, ch);
    ++len;
  }
  return len;
}



/*
//  文字を表示し、flg==1なら打音をだし、waitタイミング待つ
*/
void prn_overs(int x, int y, unsigned wait, int flg, char c) {
  sys_wait(wait);
  text_put_char(x, y, c);
  cursor_set_location(x+1, y, 1, 1); 
  if (flg == 1) {
    sound02();
  }
}



/*
//  AかBが押されたら、１を返す
*/
int check() {
  int key;
  key = key_hit_check();
  if (key & (KEY_A | KEY_B)) {
    return 1;
  }
  return 0;
}



/*
//  日時表示
*/
static int timeview_call = 0;
void timeview(int x, int y, int c) {
  unsigned int hour, min, sec;
  
  timeview_call++;
  if (timeview_call < 200) {
    return;
  }
  timeview_call = 0;
  /* 日時データの取得 */
  hour = rtc_get_datetime(RTC_HOUR);
  min  = rtc_get_datetime(RTC_MIN);
  sec  = rtc_get_datetime(RTC_SEC);
  
  /* 時分秒の表示 */
  wwc_font_set_color(c); /*  0123456789 */
  wwc_text_put_char(x+1, y, 'm');
  wwc_text_put_char(x+4, y, ':');
  wwc_text_put_char(x+7, y, ':');
  if (hour < 12) {
    wwc_text_put_char(x, y, 'A');
  } else {
    wwc_text_put_char(x, y, 'P');
    hour -= 12;
  }
  if (hour > 10) {
    wwc_text_put_char(x+2, y, (int)(hour/10)+0x30);
  } else {
    wwc_text_put_char(x+2, y, ' ');
  }
  wwc_text_put_char(x+3, y, hour-(int)(hour/10)*10+0x30);
  wwc_text_put_char(x+5, y, (int)(min/10)+0x30);
  wwc_text_put_char(x+6, y, min-(int)(min/10)*10+0x30);
  wwc_text_put_char(x+8, y, (int)(sec/10)+0x30);
  wwc_text_put_char(x+9, y, sec-(int)(sec/10)*10+0x30);
}



/*
//  ＲＡＭ上のファイル一覧を得る(最大 MAXFILE 個)
*/
static char flist[MAXFILE][MAXFNAME];
static char finfo[MAXFILE][MAXFINFO];
static int filenum = 0;
void getfilelist() {
  int dirnum;
  struct stat statbuf;
  int i;
  
  filenum = 0;
  chdir("/ram0");
  dirnum = nument(NULL);
  for(i=0; i<dirnum; i++) {
   int result = getent(NULL, i, &statbuf);
   if (result == E_FS_SUCCESS) {
     if (statbuf.count != -1) {
       strcpy(flist[filenum], statbuf.name);
       strcpy(finfo[filenum], statbuf.info);
       if (filenum > MAXFILE) {
         return;
       }
       filenum++;
      }
    }
  }
}



/*
//  有効なファイルのみ残す (先頭行が ;MML であるもの)
*/
void delotherfile() {
  int r;
  int i;
  int ch;
  int flg;
  FILE far *in;
  
  r = filenum;
  filenum = 0;
  for(i=0; i<r; i++) {
    in = fopen(flist[i], "r");
    flg = 0;
    wwc_text_put_string(1, 2, "                ");
    wwc_text_put_string(1, 2, flist[i]);
    while (((ch = fgetc(in)) != EOF) & (flg < 4)) {
      switch (flg) {
       case 0:
         if (ch != ';') {
           flg = 5;
         }
         break;
       case 1:
         if (ch != 'M') {
           flg = 5;
         }
         break;
       case 2:
         if (ch != 'M') {
           flg = 5;
         }
         break;
       case 3:
         if (ch != 'L') {
           flg = 5;
         }
         break;
       default:
         break;
      }
      flg++;
    }
    fclose(in);
    if (flg == 4) {
       strcpy(flist[filenum], flist[i]);
       strcpy(finfo[filenum], finfo[i]);
       filenum++;
     }
  }
  wwc_text_put_string(1, 2, "                ");
}



/*
//  Opening Text 表示
*/
void opening() {
  /* カーソル表示 */
  if (check()) { return; }
  text_put_string(0, TITLEYPOS, ">");
  cursor_set_location(1, TITLEYPOS, 1, 1); 
  cursor_display(1);
  if (check()) { return; }
  sys_wait(100);
  if (check()) { return; }
  
  /* OVERS 表示 */
  prn_overs( 2, TITLEYPOS, TITLEWAIT, 1, 'M');
  prn_overs( 3, TITLEYPOS, TITLEWAIT, 1, 'M');
  prn_overs( 4, TITLEYPOS, TITLEWAIT, 1, 'L');
  prn_overs( 5, TITLEYPOS, TITLEWAIT, 1, '-');
  prn_overs( 6, TITLEYPOS, TITLEWAIT, 1, 'P');
  prn_overs( 7, TITLEYPOS, TITLEWAIT, 1, 'l');
  prn_overs( 8, TITLEYPOS, TITLEWAIT, 1, 'a');
  prn_overs( 9, TITLEYPOS, TITLEWAIT, 1, 'y');
  prn_overs(10, TITLEYPOS, TITLEWAIT, 1, 'e');
  prn_overs(11, TITLEYPOS, TITLEWAIT, 1, 'r');
  if (check()) { return; }
  prn_overs(12, TITLEYPOS, 0, 0, ' ');
  prn_overs(13, TITLEYPOS, TITLEWAIT, 1, 'V');
  prn_overs(14, TITLEYPOS, TITLEWAIT, 1, '0');
  prn_overs(15, TITLEYPOS, TITLEWAIT, 1, '.');
  prn_overs(16, TITLEYPOS, TITLEWAIT, 1, '3');
  prn_overs(17, TITLEYPOS, TITLEWAIT, 1, '3');
  prn_overs(18, TITLEYPOS, 0, 0, ' ');
  if (check()) { return; }
  prn_overs(19, TITLEYPOS, TITLEWAIT, 1, 'B');
  prn_overs(20, TITLEYPOS, TITLEWAIT, 1, 'y');
  prn_overs(21, TITLEYPOS, 0, 0, ' ');
  prn_overs(22, TITLEYPOS, TITLEWAIT, 1, 'm');
  prn_overs(23, TITLEYPOS, TITLEWAIT, 1, 'e');
  prn_overs(24, TITLEYPOS, TITLEWAIT, 1, 'l');
  prn_overs(25, TITLEYPOS, TITLEWAIT, 1, 't');
  sys_wait(TITLEWAIT);
  if (check()) { return; }
  
  /* boot */
  text_put_string(0, TITLEYPOS+1, "> boot");
  cursor_set_location(1, TITLEYPOS+1, 1, 1); 
  cursor_display(0);
  prn_overs(6, TITLEYPOS+1, BOOTWAIT, 0, '.');
  if (check()) { return; }
  prn_overs(7, TITLEYPOS+1, BOOTWAIT, 0, '.');
  if (check()) { return; }
  prn_overs(8, TITLEYPOS+1, BOOTWAIT, 0, '.');
  if (check()) { return; }
  sys_wait(70);
  text_put_string(15, TITLEYPOS+1, "OK");
  if (check()) { return; }
  sys_wait(50);
  
  text_screen_init(); 
}



/*
//  fnum 番目のファイルからMMLを読み込む
*/
extern BYTE *_heap;
char mmlbuff[30000];
void readmml(int fnum) {
  int ch;
  int flg;
  char b[2] = " ";
  int num;
  FILE far *in;
  
  strcpy(mmlbuff, "");
  in = fopen(flist[fnum], "r");
  flg = 0;
  num = 0;
  wwc_font_set_color(1);
  wwc_text_put_string(1, 2, "Loading...               ");
  while ((ch = fgetc(in)) != EOF) {
    timeview(18, 0, 9);
    if (flg == 0) {
      if (ch == ';') {
        flg = 1;
      } else {
        if ((ch != '\t') & (ch != ' ') & (ch != '\n') & (ch != '\r')) {
          num++;
          if (num < 30000) {
            b[0] = ch;
            strcat(mmlbuff, b);
          }
        }
      }
    } else {  /* コメント中 */
      if ((ch == '\n') || (ch == '\r')) {
        flg = 0;
      }
    }
  }
  fclose(in);
  wwc_font_set_color(1);
  wwc_text_put_string(1, 2, "Converting.");
  sound_close();
  sounddrv_init();
  sound_open();
  parse_mml(_heap, mmlbuff, 0);
  bgm_play(_heap, PLAY_LOOP);
  wwc_text_put_string(1, 2, "Play :              ");
  wwc_text_put_string(8, 2, finfo[fnum]);
}



/*
//  ミュージック画面表示
*/
unsigned data[LOGO_width * LOGO_height];
void music_menu_logo() {
  int i;
  
  wwc_set_color_mode( COLOR_MODE_16COLOR );
  wwc_clear_font();  
  
  /* OVERS Logo 表示 */
  wwc_font_set_colordata(1, LOGO_width * LOGO_height, bmp_LOGO);
  for(i=0; i<16; i++) {
    wwc_palette_set_color(0, i, palette_LOGO[i]);
  }
  display_control(DCM_SCR1); /* スクリーン１だけ表示 */
  screen_fill_char(SCREEN1, 0, 0, 28, 18, 0); /* スクリーン１を初期化 */
  for(i=0; i<LOGO_width*LOGO_height; i++) {
    data[i] = i+1;
  }
  wwc_palette_set_color(0, 0, 0x0FFF);
  screen_set_char(SCREEN1, 14, 15, LOGO_width, LOGO_height, data);
  
  /* タイトル表示 */
  wwc_font_set_color(8);
  wwc_text_put_string(0, 0, VERVIEW);
  wwc_font_set_color(5);
  wwc_text_put_string(0, 16, "Copyright 2001");
  wwc_text_put_string(1, 17, "made by melt");
}



/*
//  ミュージック セレクター
*/
void musicsel() {
  int sel = 0;
  int i;
  int key;
  
  /* 初期メニュー作成 */
  for(i=0; i<12; i++) {
    if (i < filenum) {
      if (i == 0) {
        wwc_font_set_color(8);
        wwc_text_put_string(1, i+3, ">");
      } else {
        wwc_font_set_color(5);
      }
      wwc_text_put_string(2, i+3, finfo[i]);
    }
  }
  
  /* セレクターループ */
  while (1) {
    timeview(18, 0, 9);
    sys_wait(5);
    timeview_call += 40;
    key = key_hit_check();
    if (key & (KEY_START | KEY_Y1 | KEY_Y2 | KEY_Y3 | KEY_Y4 | KEY_B)) {  /* 終了 */
      break;
    }
    if (key & KEY_X1) {  /* 上へ */
      if (sel > 0) {
        wwc_font_set_color(5);
        wwc_text_put_string(2, sel+3, finfo[sel]);
        wwc_text_put_string(1, sel+3, " ");
        sel--;
        wwc_font_set_color(8);
        wwc_text_put_string(2, sel+3, finfo[sel]);
        wwc_text_put_string(1, sel+3, ">");
      }
    }
    if (key & KEY_X3) {  /* 下へ */
      if (sel+1 < filenum) {
        wwc_font_set_color(5);
        wwc_text_put_string(2, sel+3, finfo[sel]);
        wwc_text_put_string(1, sel+3, " ");
        sel++;
        wwc_font_set_color(8);
        wwc_text_put_string(2, sel+3, finfo[sel]);
        wwc_text_put_string(1, sel+3, ">");
      }
    }
    if (key & KEY_A) {  /* 演奏 */
      readmml(sel);
    }
  }
}




void main() {
  /* Sound 初期化 */
  sound_init();
  
  /* Text 初期化 */
  text_screen_init();
  cursor_set_location(0, 0, 1, 1); 
  cursor_set_type(1, 20);
  cursor_display(0);
  
  /* オープニング表示 */
  opening();
  
  /* ミュージック画面表示 */
  music_menu_logo();
  
  /* 演奏データの取得 */
  getfilelist();  /* ファイル一覧 */
  delotherfile();  /* 有効ファイルのみ残す */
  if (filenum == 0) {
    wwc_font_set_color(1);
    wwc_text_put_string(1, 2, "MML Data not found.");
    wwc_font_set_color(5);
    wwc_text_put_string(1, 3, "push any key.");
    key_wait();
    sound_stop();
    return;
  }
  
  wwc_font_set_color(1);
  wwc_text_put_string(1, 2, "MML Data :");
  if (filenum > 9) {
    wwc_text_put_char(11, 2, (int)(filenum/10)+0x30);
    wwc_text_put_char(12, 2, filenum-(int)((filenum/10)*10)+0x30);
  } else {
    wwc_text_put_char(11, 2, filenum+0x30);
  }
  
  /* セレクタ起動 */
  musicsel();
  
  /* サウンドドライバ終了 */
  sound_stop();
}

