#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#if defined(__WIN__)
#include <windows.h>
#else
#include "port.h"
#endif
#include "cd_sys.h"
#include "cd_file.h"
#include "lc89510.h"
#include "cdda_mp3.h"
#include "star_68k.h"
#include "rom.h"
#include "mem_s68k.h"

struct _file_track Tracks[100];

char cp_buf[2560];
char Track_Played;

int
FILE_Init (void)
{
  MP3_Init ();
  Unload_ISO ();

  return 0;
}


void
FILE_End (void)
{
  Unload_ISO ();
}


int
Load_ISO (char *buf, char *iso_name)
{
  FILE *File_Size;
  int i, j, num_track, Cur_LBA;
  FILE *tmp_file;
  char tmp_name[1024], tmp_ext[10];
  char exts[20][16] = {
    "%02d.mp3", " %02d.mp3", "-%02d.mp3", "_%02d.mp3", " - %02d.mp3",
    "%d.mp3", " %d.mp3", "-%d.mp3", "_%d.mp3", " - %d.mp3",
    "%02d.wav", " %02d.wav", "-%02d.wav", "_%02d.wav", " - %02d.wav",
    "%d.wav", " %d.wav", "-%d.wav", "_%d.wav", " - %2d.wav"
  };

  Unload_ISO ();

  if (Detect_Format (iso_name) == SEGACD_IMAGE + 1)
    Tracks[0].Type = TYPE_BIN;
  else if (Detect_Format (iso_name) == SEGACD_IMAGE)
    Tracks[0].Type = TYPE_ISO;
  else
    return -2;

  File_Size = fopen (iso_name, "rb");
  fseek (File_Size, 0, SEEK_END);
  Tracks[0].Lenght = ftell (File_Size);
  fseek (File_Size, 0, SEEK_SET);

  if (Tracks[0].Type == TYPE_ISO)
    Tracks[0].Lenght >>= 11;	// size in sectors
  else
    Tracks[0].Lenght /= 2352;	// size in sectors

  fclose (File_Size);

  Tracks[0].F = fopen (iso_name, "rb");

  if (Tracks[0].F == NULL)
    {
      Tracks[0].Type = 0;
      Tracks[0].Lenght = 0;
      return -1;
    }

  if (Tracks[0].Type == TYPE_ISO)
    fseek (Tracks[0].F, 0x100, SEEK_SET);
  else
    fseek (Tracks[0].F, 0x110, SEEK_SET);

  fread (buf, 1, 0x200, Tracks[0].F);
  fseek (Tracks[0].F, 0, SEEK_SET);

  SCD.TOC.First_Track = 1;

  SCD.TOC.Tracks[0].Num = 1;
  SCD.TOC.Tracks[0].Type = 1;	// DATA

  SCD.TOC.Tracks[0].MSF.M = 0;
  SCD.TOC.Tracks[0].MSF.S = 2;
  SCD.TOC.Tracks[0].MSF.F = 0;

#ifdef DEBUG_CD
  fprintf (debug_SCD_file, "\nTrack 0 - %02d:%02d:%02d ",
	   SCD.TOC.Tracks[0].MSF.M, SCD.TOC.Tracks[0].MSF.S,
	   SCD.TOC.Tracks[0].MSF.F);
  if (SCD.TOC.Tracks[0].Type)
    fprintf (debug_SCD_file, "DATA\n");
  else
    fprintf (debug_SCD_file, "AUDIO\n");
#endif

  Cur_LBA = Tracks[0].Lenght;	// Size in sectors

  strcpy (tmp_name, iso_name);

  for (num_track = 2, i = 0; i < 100; i++)
    {
      for (j = 0; j < 20; j++)
	{
	  tmp_name[strlen (iso_name) - 4] = 0;
	  sprintf (tmp_ext, exts[j], i);


	  strcat (tmp_name, tmp_ext);
	  tmp_file = fopen (tmp_name, "rb");

	  if (tmp_file)
	    {
	      float fs;



	      fseek (tmp_file, 0, SEEK_END);
	      fs = (float) ftell (tmp_file);
	      fseek (tmp_file, 0, SEEK_SET);

	      Tracks[num_track - SCD.TOC.First_Track].F = tmp_file;

	      SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].Num = num_track;
	      SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].Type = 0;	// AUDIO

	      LBA_to_MSF (Cur_LBA,
			  &(SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].
			    MSF));

#ifdef DEBUG_CD
	      fprintf (debug_SCD_file, "Track %i - %02d:%02d:%02d ",
		       num_track - SCD.TOC.First_Track,
		       SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].MSF.M,
		       SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].MSF.S,
		       SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].MSF.F);
	      if (SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].Type)
		fprintf (debug_SCD_file, "DATA\n");
	      else
		fprintf (debug_SCD_file, "AUDIO\n");
#endif

	      if (j < 10)
		{
		  // MP3 File
		  Tracks[num_track - SCD.TOC.First_Track].Type = TYPE_MP3;
		  fs /= (float) (MP3_Get_Bitrate (Tracks[num_track - 1].F) >>
				 3);
		  fs *= 75;
		  Tracks[num_track - SCD.TOC.First_Track].Lenght = (int) fs;
		  Cur_LBA += Tracks[num_track - SCD.TOC.First_Track].Lenght;
		}
	      else
		{
		  // WAV File
		  Tracks[num_track - SCD.TOC.First_Track].Type = TYPE_WAV;
		  Tracks[num_track - SCD.TOC.First_Track].Lenght = 1000;
		  Cur_LBA += Tracks[num_track - SCD.TOC.First_Track].Lenght;
		}

	      j = 1000;
	      num_track++;
	    }
	}
    }

/*	
//	Faking some audios tracks if no present

	if (num_track == 2)
	{
		for(; num_track < 95; num_track++)
		{
			SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].Num = num_track;
			SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].Type = 0;			// AUDIO

			LBA_to_MSF(Cur_LBA, &(SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].MSF));

			Cur_LBA += 100;
		}
	}
*/
  SCD.TOC.Last_Track = num_track - 1;

  SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].Num = num_track;
  SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].Type = 0;

  LBA_to_MSF (Cur_LBA,
	      &(SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].MSF));

#ifdef DEBUG_CD
  fprintf (debug_SCD_file, "End CD - %02d:%02d:%02d\n\n",
	   SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].MSF.M,
	   SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].MSF.S,
	   SCD.TOC.Tracks[num_track - SCD.TOC.First_Track].MSF.F);
#endif

  return 0;
}


void
Unload_ISO (void)
{
  int i;

  Track_Played = 99;

  for (i = 0; i < 100; i++)
    {
      if (Tracks[i].F)
	fclose (Tracks[i].F);
      Tracks[i].F = NULL;
      Tracks[i].Lenght = 0;
      Tracks[i].Type = 0;
    }
}


int
FILE_Read_One_LBA_CDC (void)
{
  int where_read;

  if (CDD.Control & 0x0100)	// DATA
    {
      if (Tracks[0].F == NULL)
	return -1;

      if (SCD.Cur_LBA < 0)
	where_read = 0;
      else if (SCD.Cur_LBA >= Tracks[0].Lenght)
	where_read = Tracks[0].Lenght - 1;
      else
	where_read = SCD.Cur_LBA;

      if (Tracks[0].Type == TYPE_ISO)
	where_read <<= 11;
      else
	where_read = (where_read * 2352 + 16);

//              memset(cp_buf, 0, 2048);

      fseek (Tracks[0].F, where_read, SEEK_SET);
      fread (cp_buf, 1, 2048, Tracks[0].F);

#ifdef DEBUG_CD
      fprintf (debug_SCD_file, "\n\nRead file CDC 1 data sector :\n");
#endif
    }
  else				// AUDIO
    {
      int rate, channel;

      if (Tracks[SCD.Cur_Track - SCD.TOC.First_Track].Type == TYPE_MP3)
	{
	  MP3_Update (cp_buf, &rate, &channel, 0);
	  Write_CD_Audio ((short *) cp_buf, rate, channel, 588);
	}

#ifdef DEBUG_CD
      fprintf (debug_SCD_file, "\n\nRead file CDC 1 audio sector :\n");
#endif
    }

  // Update CDC stuff

  CDC_Update_Header ();

  if (CDD.Control & 0x0100)	// DATA track
    {
      if (CDC.CTRL.B.B0 & 0x80)	// DECEN = decoding enable
	{
	  if (CDC.CTRL.B.B0 & 0x04)	// WRRQ : this bit enable write to buffer
	    {
	      // CAUTION : lookahead bit not implemented

	      SCD.Cur_LBA++;

	      CDC.WA.N = (CDC.WA.N + 2352) & 0x7FFF;	// add one sector to WA
	      CDC.PT.N = (CDC.PT.N + 2352) & 0x7FFF;

	      memcpy (&CDC.Buffer[CDC.PT.N + 4], cp_buf, 2048);
	      memcpy (&CDC.Buffer[CDC.PT.N], &CDC.HEAD, 4);

#ifdef DEBUG_CD
	      fprintf (debug_SCD_file, "\nRead -> WA = %d  Buffer[%d] =\n",
		       CDC.WA.N, CDC.PT.N & 0x3FFF);
	      fprintf (debug_SCD_file, "Header 1 = %.2X %.2X %.2X %.2X\n",
		       CDC.HEAD.B.B0, CDC.HEAD.B.B1, CDC.HEAD.B.B2,
		       CDC.HEAD.B.B3);
//                              fwrite(Buf_Read, 1, 2048, debug_SCD_file);
//                              fprintf(debug_SCD_file, "\nCDC buffer =\n");
//                              fwrite(&CDC.Buffer[CDC.PT.N], 1, 2052, debug_SCD_file);
	      fprintf (debug_SCD_file,
		       "Header 2 = %.2X %.2X %.2X %.2X --- %.2X %.2X\n\n",
		       CDC.Buffer[(CDC.PT.N + 0) & 0x3FFF],
		       CDC.Buffer[(CDC.PT.N + 1) & 0x3FFF],
		       CDC.Buffer[(CDC.PT.N + 2) & 0x3FFF],
		       CDC.Buffer[(CDC.PT.N + 3) & 0x3FFF],
		       CDC.Buffer[(CDC.PT.N + 4) & 0x3FFF],
		       CDC.Buffer[(CDC.PT.N + 5) & 0x3FFF]);
#endif
	    }

	  CDC.STAT.B.B0 = 0x80;

	  if (CDC.CTRL.B.B0 & 0x10)	// determine form bit form sub header ?
	    {
	      CDC.STAT.B.B2 = CDC.CTRL.B.B1 & 0x08;
	    }
	  else
	    {
	      CDC.STAT.B.B2 = CDC.CTRL.B.B1 & 0x0C;
	    }

	  if (CDC.CTRL.B.B0 & 0x02)
	    CDC.STAT.B.B3 = 0x20;	// ECC done
	  else
	    CDC.STAT.B.B3 = 0x00;	// ECC not done

	  if (CDC.IFCTRL & 0x20)
	    {
	      if (Int_Mask_S68K & 0x20)
		sub68k_interrupt (5, -1);

#ifdef DEBUG_CD
	      fprintf (debug_SCD_file, "CDC - DEC interrupt\n");
#endif

	      CDC.IFSTAT &= ~0x20;	// DEC interrupt happen
	      CDC_Decode_Reg_Read = 0;	// Reset read after DEC int
	    }
	}
    }
  else
    {
      SCD.Cur_LBA++;

      CDC.WA.N = (CDC.WA.N + 2352) & 0x7FFF;	// add one sector to WA
      CDC.PT.N = (CDC.PT.N + 2352) & 0x7FFF;

      if (CDC.CTRL.B.B0 & 0x80)	// DECEN = decoding enable
	{
	  if (CDC.CTRL.B.B0 & 0x04)	// WRRQ : this bit enable write to buffer
	    {
	      // CAUTION : lookahead bit not implemented

	      memcpy (&CDC.Buffer[CDC.PT.N], cp_buf, 2352);
	    }

	  CDC.STAT.B.B0 = 0x80;

	  if (CDC.CTRL.B.B0 & 0x10)	// determine form bit form sub header ?
	    {
	      CDC.STAT.B.B2 = CDC.CTRL.B.B1 & 0x08;
	    }
	  else
	    {
	      CDC.STAT.B.B2 = CDC.CTRL.B.B1 & 0x0C;
	    }

	  if (CDC.CTRL.B.B0 & 0x02)
	    CDC.STAT.B.B3 = 0x20;	// ECC done
	  else
	    CDC.STAT.B.B3 = 0x00;	// ECC not done

	  if (CDC.IFCTRL & 0x20)
	    {
	      if (Int_Mask_S68K & 0x20)
		sub68k_interrupt (5, -1);

#ifdef DEBUG_CD
	      fprintf (debug_SCD_file, "CDC - DEC interrupt\n");
#endif

	      CDC.IFSTAT &= ~0x20;	// DEC interrupt happen
	      CDC_Decode_Reg_Read = 0;	// Reset read after DEC int
	    }
	}
    }

  return 0;
}


int
FILE_Play_CD_LBA (void)
{
  int Track_LBA_Pos;

#ifdef DEBUG_CD
  fprintf (debug_SCD_file, "Play FILE Comp\n");
#endif

  if (Tracks[SCD.Cur_Track - SCD.TOC.First_Track].F == NULL)
    {
      return 1;
    }

  Track_LBA_Pos = SCD.Cur_LBA - Track_to_LBA (SCD.Cur_Track);
  if (Track_LBA_Pos < 0)
    Track_LBA_Pos = 0;

  if (Tracks[SCD.Cur_Track - SCD.TOC.First_Track].Type == TYPE_MP3)
    {
      MP3_Play (SCD.Cur_Track - SCD.TOC.First_Track, Track_LBA_Pos);
    }
  else if (Tracks[SCD.Cur_Track - SCD.TOC.First_Track].Type == TYPE_WAV)
    {
      return 2;
    }
  else
    {
      return 3;
    }

  return 0;
}
