/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#define FORBIDDEN_SYMBOL_EXCEPTION_chdir

#include "dc.h"
#include "dcutils.h"
#include <ronin/gddrive.h>


int getCdState()
{
  unsigned int param[4];
  gdGdcGetDrvStat(param);
  return param[0];
}

extern "C" {
  int dummy_cdfs_get_volume_id(char *, unsigned int) {
    return -1;
  }
  int cdfs_get_volume_id(char *, unsigned int) __attribute__ ((weak, alias ("dummy_cdfs_get_volume_id")));
}

DiscLabel::DiscLabel() {
  if (cdfs_get_volume_id(buf, 32) < 0)
    memset(buf, '*', 32);
}

bool DiscLabel::operator==(const DiscLabel &other) const {
  return !memcmp(buf, other.buf, 32);
}

void DiscLabel::get(char *p) const {
  memcpy(p, buf, 32);
  p[32] = 0;
}


void draw_solid_quad(float x1, float y1, float x2, float y2,
		     int c0, int c1, int c2, int c3)
{
  struct polygon_list mypoly;
  struct packed_colour_vertex_list myvertex;

  mypoly.cmd =
	TA_CMD_POLYGON|TA_CMD_POLYGON_TYPE_OPAQUE|TA_CMD_POLYGON_SUBLIST|
	TA_CMD_POLYGON_STRIPLENGTH_2|TA_CMD_POLYGON_PACKED_COLOUR|
	TA_CMD_POLYGON_GOURAUD_SHADING;
  mypoly.mode1 = TA_POLYMODE1_Z_ALWAYS|TA_POLYMODE1_NO_Z_UPDATE;
  mypoly.mode2 =
	TA_POLYMODE2_BLEND_SRC|TA_POLYMODE2_FOG_DISABLED;
  mypoly.texture = 0;

  mypoly.red = mypoly.green = mypoly.blue = mypoly.alpha = 0;

  ta_commit_list(&mypoly);

  myvertex.cmd = TA_CMD_VERTEX;
  myvertex.ocolour = 0;
  myvertex.z = 0.5;
  myvertex.u = 0.0;
  myvertex.v = 0.0;

  myvertex.colour = c0;
  myvertex.x = x1;
  myvertex.y = y1;
  ta_commit_list(&myvertex);

  myvertex.colour = c1;
  myvertex.x = x2;
  ta_commit_list(&myvertex);

  myvertex.colour = c2;
  myvertex.x = x1;
  myvertex.y = y2;
  ta_commit_list(&myvertex);

  myvertex.colour = c3;
  myvertex.x = x2;
  myvertex.cmd |= TA_CMD_VERTEX_EOS;
  ta_commit_list(&myvertex);
}

void draw_trans_quad(float x1, float y1, float x2, float y2,
		     int c0, int c1, int c2, int c3)
{
  struct polygon_list mypoly;
  struct packed_colour_vertex_list myvertex;

  mypoly.cmd =
	TA_CMD_POLYGON|TA_CMD_POLYGON_TYPE_TRANSPARENT|TA_CMD_POLYGON_SUBLIST|
	TA_CMD_POLYGON_STRIPLENGTH_2|TA_CMD_POLYGON_PACKED_COLOUR|
	TA_CMD_POLYGON_GOURAUD_SHADING;
  mypoly.mode1 = TA_POLYMODE1_Z_ALWAYS|TA_POLYMODE1_NO_Z_UPDATE;
  mypoly.mode2 =
	TA_POLYMODE2_BLEND_SRC_ALPHA|TA_POLYMODE2_BLEND_DST_INVALPHA|
	TA_POLYMODE2_FOG_DISABLED|TA_POLYMODE2_ENABLE_ALPHA;
  mypoly.texture = 0;

  mypoly.red = mypoly.green = mypoly.blue = mypoly.alpha = 0;

  ta_commit_list(&mypoly);

  myvertex.cmd = TA_CMD_VERTEX;
  myvertex.ocolour = 0;
  myvertex.z = 0.5;
  myvertex.u = 0.0;
  myvertex.v = 0.0;

  myvertex.colour = c0;
  myvertex.x = x1;
  myvertex.y = y1;
  ta_commit_list(&myvertex);

  myvertex.colour = c1;
  myvertex.x = x2;
  ta_commit_list(&myvertex);

  myvertex.colour = c2;
  myvertex.x = x1;
  myvertex.y = y2;
  ta_commit_list(&myvertex);

  myvertex.colour = c3;
  myvertex.x = x2;
  myvertex.cmd |= TA_CMD_VERTEX_EOS;
  ta_commit_list(&myvertex);
}

DiscSwap::DiscSwap(const char *label, unsigned int argb_) : argb(argb_) {
  x = 320 - 7 * strlen(label);
  lab.create_texture(label);
}

void DiscSwap::run()
{
  int wasopen = 0;
  for (;;) {
	int s = getCdState();
	if (s >= 6)
	  wasopen = 1;
	if (s > 0 && s < 6 && wasopen) {
	  cdfs_reinit();
	  chdir("/");  // Expect this one to fail with ERR_DISKCHG
	  chdir("/");  // but this one to succeed
	  return;
	}

	ta_begin_frame();
	background();
	ta_commit_end();
	lab.draw(x, 200.0, argb);
	ta_commit_frame();

	interact();
  }
}

namespace DC_Flash {

  static int syscall_info_flash(int sect, int *info)
  {
	return (*(int (**)(int, void*, int, int))0x8c0000b8)(sect,info,0,0);
  }

  static int syscall_read_flash(int offs, void *buf, int cnt)
  {
	return (*(int (**)(int, void*, int, int))0x8c0000b8)(offs,buf,cnt,1);
  }

  static int flash_crc(const char *buf, int size)
  {
	int i, c, n = -1;
	for(i=0; i<size; i++) {
	  n ^= (buf[i]<<8);
	  for(c=0; c<8; c++)
	if(n & 0x8000)
	  n = (n << 1) ^ 4129;
	else
	  n <<= 1;
	}
	return (unsigned short)~n;
  }

  int flash_read_sector(int partition, int sec, unsigned char *dst)
  {
	int s, r, n, b, bmb, got=0;
	int info[2];
	char buf[64];
	char bm[64];

	if((r = syscall_info_flash(partition, info))<0)
	  return r;

	if((r = syscall_read_flash(info[0], buf, 64))<0)
	  return r;

	if(memcmp(buf, "KATANA_FLASH", 12) ||
	   buf[16] != partition || buf[17] != 0)
	  return -2;

	n = (info[1]>>6)-1-((info[1] + 0x7fff)>>15);
	bmb = n+1;
	for(b = 0; b < n; b++) {
	  if(!(b&511)) {
	if((r = syscall_read_flash(info[0] + (bmb++ << 6), bm, 64))<0)
	  return r;
	  }
	  if(!(bm[(b>>3)&63] & (0x80>>(b&7)))) {
	if((r = syscall_read_flash(info[0] + ((b+1) << 6), buf, 64))<0)
	  return r;
	else if((s=READ_LE_UINT16(buf+0)) == sec &&
		flash_crc(buf, 62) == READ_LE_UINT16(buf+62)) {
	  memcpy(dst+(s-sec)*60, buf+2, 60);
	  got=1;
	}
	  }
	}
	return got;
  }

  int get_locale_setting()
  {
	unsigned char data[60];
	if (flash_read_sector(2,5,data) == 1)
	  return data[5];
	else
	  return -1;
  }

} // End of namespace DC_Flash