/***************************************************************************
*
* FunktrackerGOLD - By Jason Nunn
*
* Using Curses (ANSI C) NON-preemptive Processing
*
* Snail: 32 Rothdale Road, Moil, Darwin, NT, 0810, Australia
*
* =======================================================
*
* Sequence Editor
*
***************************************************************************/
#include <ncurses.h>
#pragma pack(1)
#include "everything.h"
#include "funktracker.h"
#pragma pack()
#include "fickle.h"
#include "funkgold.h"

/*protos dsp_mixxer.c*/
extern int sample_precision;
extern int bpm_rate;

/*protos funktracker.c*/
#pragma pack(1)
extern tfunk_info funk_info;
extern tfunk_hr *funk_hr_ptr;
#pragma pack()

/*protos from funkmisc.c*/
void find_pats_seqs(void);

/*protos funkgold_main.c*/
extern int ch,maxy;
extern char edit_mode;
extern void display_topbar(void);
extern void update_screen(void);
extern void clear_area(char y1,char x1,char y2,char x2);
extern void byte2str(char *str,unsigned char value);
extern int hex2char(char *str);
extern void get_string(char y, char x,char *str,int maxlen);
extern void ferr_message(char *mess_str);
extern void main_editor_dis_bg(void);
extern void save_song(int song_type);
extern int quit_confirm(void);

/*protos funkgold_trac.c*/
extern void play_song(int play_type);

/*locals*/
unsigned char se_pos_real;
unsigned char se_pos_hl;
unsigned char se_pos_hl_old;

/***************************************************************************
*
***************************************************************************/
void se_display_bg(void)
{
  register int y;
  register int amaxy = maxy - 5;
  char tmpstr[10];

  char *cpu_table[] = {
    "Unknown",
    "IBM PC ?",
    "IBM PC ?",
    "i386 PC",
    "i486 PC",
    "Pentium PC",
    "Linux",
    "FreeBSD",
    "Not Used",
    "Not Used",
    "Not Used",
    "Not Used",
    "Not Used",
    "Not Used",
    "Not Used",
    "Other"
  };

  char *crd_table[] = {
    "SB2.0",
    "SBPRO",
    "GUS var pan",
    "SB1.x",
    "SB16",
    "GUS fix pan",
    "Ripped",
    "PAS",
    "Vox 8 bit",
    "Vox 16 bit",
    "Unused",
    "Unused",
    "Unused",
    "Unused",
    "Unused",
    "Other"
  };

  display_topbar();
  move(1,0);
  attroff(A_REVERSE);
  addstr("Sequence Editor");
  move(1,40);
  addstr("Funk Info");

  move(4,42);
  addstr("FNK Type: ");
  addnstr(funk_hr_ptr->funk_type,4);
  move(5,42);
  addstr("Creation: ");
  sprintf(tmpstr,"%d/",funk_hr_ptr->info[0] & 0x1f);
  addstr(tmpstr);
  sprintf(tmpstr,"%d/",
    ((funk_hr_ptr->info[1] & 1) << 3) + (funk_hr_ptr->info[0] >> 5));
  addstr(tmpstr);
  sprintf(tmpstr,"%d",(funk_hr_ptr->info[1] >> 1) + 1980);
  addstr(tmpstr);
  move(6,42);
  addstr("CPU Type: ");
  addstr(cpu_table[funk_hr_ptr->info[2] >> 4]);
  move(7,42);
  addstr("CRD Type: ");
  addstr(crd_table[funk_hr_ptr->info[2] & 0xf]);
  move(8,42);
  addstr("FNK Size: ");
  sprintf(tmpstr,"%dk",funk_hr_ptr->LZH_check_size >> 10);
  addstr(tmpstr);
  move(9,42);
  addstr("BPM rate: ");
  sprintf(tmpstr,"%d",bpm_rate);
  addstr(tmpstr);
  move(10,42);
  addstr("FNK prec: ");
  if(sample_precision == 16)
    addstr("16");
  else
    addch('8');
  addstr(" bit");

  attron(A_REVERSE);
  for(y = 0;y < (maxy - 8);y++)
  {
    move(y + 3,0);
    addch(' ');
    move(y + 3,4);
    addch(' ');
    move(y + 3,7);
    addch(' ');
    move(y + 3,40);
    addch(' ');
    move(y + 3,65);
    addch(' ');
  }
  move(2,0);
  addstr("Seq  Pt ");
  move(amaxy,0);
  addstr("        ");
  clear_area(2,40,2,65);
  clear_area(amaxy,40,amaxy,65);
}

/***************************************************************************
*
***************************************************************************/
void se_dis_seqentry(unsigned char hlpos)
{
  char bstr[] = "  ";
  register int seq_no = se_pos_real + hlpos,x;

  move(hlpos + 3,1);
  byte2str(bstr,seq_no);
  addstr(bstr);
  if(seq_no == funk_hr_ptr->loop_order)
    addch('*');
  else
    addch(' ');
  move(hlpos + 3,5);
  x = funk_hr_ptr->order_list[seq_no];
  if(x == 0xff)
    addstr("--");
  else
  {
    byte2str(bstr,funk_hr_ptr->order_list[seq_no]);
    addstr(bstr);
  }
}

/***************************************************************************
*
***************************************************************************/
void se_display_all(void)
{
  register int seq_no;

  attroff(A_REVERSE);
  for(seq_no = 0;seq_no < (maxy - 8);seq_no++)
    se_dis_seqentry(seq_no);
  attron(A_REVERSE);
  se_dis_seqentry(se_pos_hl);
  se_pos_hl_old = se_pos_hl;
}

void se_move_hl(void)
{
  attroff(A_REVERSE);
  se_dis_seqentry(se_pos_hl_old);
  attron(A_REVERSE);
  se_dis_seqentry(se_pos_hl);
  se_pos_hl_old = se_pos_hl;
}

/***************************************************************************
*
***************************************************************************/
void se_edit_seq(void)
{
  register int x;
  char str[] = "  ";
  register int seq_no = se_pos_real + se_pos_hl;
  get_string(3 + se_pos_hl,5,str,2);
  x = hex2char(str);
  if(x != -1)
  {
    if(x > 0x7f) x = 0xff;
    funk_hr_ptr->order_list[seq_no] = x;
  }
  se_dis_seqentry(se_pos_hl);
  update_screen();
}

/***************************************************************************
*
***************************************************************************/
void se_cursor_up(void)
{
  if(se_pos_hl > 0)
  {
    se_pos_hl--;
    se_move_hl();
    update_screen();
  }
  else
  {
    if(se_pos_real > 0) se_pos_real--;
    se_display_all();
    update_screen();
  }
}

void se_cursor_down(void)
{
  if(se_pos_hl < (maxy - 9))
  {
    se_pos_hl++;
    se_move_hl();
    update_screen();
  }
  else
  {
    if(se_pos_real < ((256 + 8) - maxy)) se_pos_real++;
    se_display_all();
    update_screen();
  }
}

/***************************************************************************
*
***************************************************************************/
void se_insert_seq(void)
{
  register int x,seq_no = se_pos_real + se_pos_hl;
  for(x = 0xff;x > seq_no;x--)
    funk_hr_ptr->order_list[x] = funk_hr_ptr->order_list[x - 1];
  funk_hr_ptr->order_list[x] = 0xff;
  se_display_all();
  update_screen();
}

void se_delete_seq(void)
{
  register int x,seq_no = se_pos_real + se_pos_hl;
  for(x = seq_no;x < 0xff;x++)
    funk_hr_ptr->order_list[x] = funk_hr_ptr->order_list[x + 1];
  funk_hr_ptr->order_list[0xff] = 0xff;
  se_display_all();
  update_screen();
}

/***************************************************************************
*
***************************************************************************/
void se_edit_bpm(void)
{
  int x;
  char str[] = "    ";

  get_string(9,52,str,3);
  sscanf(str,"%d",&x);
  if((x >= MIN_BPM_RATE) && (x <= MAX_BPM_RATE)) bpm_rate = x;
  attroff(A_REVERSE);
  move(9,52);
  sprintf(str,"%d",bpm_rate);
  addstr(str);
  addch(' ');
  update_screen();
}

/***************************************************************************
*
***************************************************************************/
void se_main(void)
{
  register int sepos;

  switch(ch)
  {
    case FC_GOTO_SAM_EDIT:
      edit_mode = EM_SAMPLE;
      main_editor_dis_bg();
      break;
    case FC_GOTO_PAT_EDIT:
      edit_mode = EM_PATTERN;
      main_editor_dis_bg();
      break;
    case FC_SCREEN_ESCAPE:
      if(quit_confirm()) edit_mode = EM_MAIN;
      break;
    case FC_TRAC_PAT:
      play_song(0);
      main_editor_dis_bg();
      break;
    case FC_TRAC_DGB:
      play_song(1);
      main_editor_dis_bg();
      break;
    case FC_TRAC_PTY:
      play_song(2);
      main_editor_dis_bg();
      break;
    case FC_SAVE_SONG:
      save_song(1);
      break;
    case FC_SAVE_MOD:
      save_song(0);
      break;
    case FC_ARROW_UP:
      se_cursor_up();
      break;
    case FC_ARROW_DN:
      se_cursor_down();
      break;
    case FC_SE_EDIT_ENTRY:
      se_edit_seq();
      break;
    case FC_SE_SET_LOOP:
      sepos = se_pos_real + se_pos_hl;
      find_pats_seqs();
      if(sepos <= funk_info.no_of_sequences)
        funk_hr_ptr->loop_order = se_pos_real + se_pos_hl;
      else
        ferr_message("Illogical Sequence loop position. Select loop within range.");
      se_display_all();
      update_screen();
      break;
    case FC_DEL_ENTRY:
      se_delete_seq();
      break;
    case FC_INS_ENTRY:
      se_insert_seq();
      break;
    case FC_SE_SET_BPM:
      se_edit_bpm();
      break;
  }
}

