#include <aes.h>
#include <vdi.h>
#include <osbind.h>
#include <stdlib.h>
#include <errno.h>
#include <scancode.h>

typedef struct rsxhdr
{
  int	rsh_vrsn,   rsh_extvrsn;
  long  rsh_object, rsh_tedinfo, rsh_iconblk, rsh_bitblk, rsh_frstr,
        rsh_string, rsh_imdata,  rsh_frimg,   rsh_trindex,
	rsh_nobs,   rsh_ntree,   rsh_nted,    rsh_nib,
	rsh_nbb,    rsh_nstring, rsh_nimages, rsh_rssize;
} RSXHDR;

typedef struct view
{
  int	handle, flip,
	lbc,			/* left-border-count fr Fenster.	*/
	tlc,			/* top-line-count fr Fenster.		*/
	bc,			/* border-count fr Fenster.		*/
	lc,			/* line-count fr Fenster.		*/
	xfac, yfac,		/* Scroll- und Rastereinheiten.		*/
	x, y, w, h,		/* Arbeitsbereich des Fensters.		*/
	hslide, vslide,		/* Puffer fr Sliderpositionen.		*/
	(*key)( struct view *tv, int code, int ks );
  void	(*draw)( struct view *tv, int *clip ),
	(*free)( struct view *tv ),
	(*sclick)( struct view *tv, int mx, int my, int flag );
  char	path[128];		/* Datei-Pfad (Fenstertitel).		*/
  struct view *next;		/* Zeiger auf nchste Fensterstruktur.	*/
  struct view *prev;		/* Zeiger auf vorige Fensterstruktur.	*/
  BASPAG *actpd;		/* Zeiger auf Prozess-Descriptor.	*/

  long   tree;
  char   *addr;
  RSXHDR header;
  char   buf[];			/* Resourcepuffer.			*/
}
VIEW;

#include "1stview.h"
#include "util.h"

static char string2[4], string0[] = "---- XX Bume ----",
	    string_i_to_m[] = " Ix86 -> M68k  ^K",
	    string_m_to_i[] = " M68k -> Ix86  ^K";

#pragma warn -rpt
static OBJECT popup[] =
{
  0,  1,  6, G_BOX,    NONE,   SHADOWED, 0xFF1100L,	       0, 0,18, 4,
  5, -1, -1, G_STRING, NONE,   DISABLED, string0,	       0, 0,18, 1,
  3, -1, -1, G_BUTTON, NONE,   NORMAL,   "<< ^\004",	       0, 1, 7, 1,
  4, -1, -1, G_BUTTON, NONE,   DISABLED, string2,	       7, 1, 4, 1,
  6, -1, -1, G_BUTTON, NONE,   NORMAL,   ">> ^\003",	       11,1, 7, 1,
  2, -1, -1, G_STRING, NONE,   DISABLED, "-- Konvertieren --", 0, 2,18, 1,
  0, -1, -1, G_STRING, LASTOB, NORMAL,   string_m_to_i,        0, 3,18, 1
};
#pragma warn +rpt

static void vdi_trans( int *addr, int w, int h )
{
  MFDB s, d;

  s.fd_addr = addr; s.fd_w = w; s.fd_h = h; s.fd_wdwidth = (w + 15) >> 4;
  s.fd_stand = 1; s.fd_nplanes = 1; s.fd_r1 = 0; *(long *)&s.fd_r2 = 0;
  d = s; vr_trnfm( handle, &s, &d );
}

static void flip_header( RSXHDR *header, char *addr )
{
  flipwords( (char *)header + 4, sizeof(RSXHDR) - 4 );
  if ((char *)header == addr) fliplongs( (int *)header + 2, 17, 0 );
}

static void flip_resource( RSXHDR *header, char *addr, int flag )
{
  OBJECT  *op;
  TEDINFO *tp;
  ICONBLK *ip;
  BITBLK  *bp;
  long    i, s;

  op = (OBJECT *)(addr + header->rsh_object);
  for (i = header->rsh_nobs; --i >= 0; ++op)
  {
    flipwords( (char *)op, sizeof( OBJECT ) );
    fliplongs( (int *)&op->ob_spec, 1, 0 );
  }
  tp = (TEDINFO *)(addr + header->rsh_tedinfo);
  for (i = header->rsh_nted; --i >= 0; ++tp)
  {
    flipwords( (char *)tp, sizeof( TEDINFO ) );
    fliplongs( (int *)tp, 3, 0 );
  }
  ip = (ICONBLK *)(addr + header->rsh_iconblk);
  for (i = header->rsh_nib; --i >= 0; ++ip)
  {
    if (flag == 0)
    {
      s = (long)ip->ib_wicon * ip->ib_hicon >> 3;
      flipwords( addr + (long)ip->ib_pmask, s );
      flipwords( addr + (long)ip->ib_pdata, s );
    }
    flipwords( (char *)ip, sizeof( ICONBLK ) );
    fliplongs( (int *)ip, 3, 0 );

    if (flag)
    {
      s = (long)ip->ib_wicon * ip->ib_hicon >> 3;
      flipwords( addr + (long)ip->ib_pmask, s );
      flipwords( addr + (long)ip->ib_pdata, s );
  } }
  bp = (BITBLK *)(addr + header->rsh_bitblk);
  for (i = header->rsh_nbb; --i >= 0; ++bp)
  {
    if (flag == 0)
      flipwords( addr + (long)bp->bi_pdata, (long)bp->bi_wb * bp->bi_hl );

    flipwords( (char *)bp, sizeof( BITBLK ) );
    fliplongs( (int *)bp, 1, 0 );

    if (flag)
      flipwords( addr + (long)bp->bi_pdata, (long)bp->bi_wb * bp->bi_hl );
  }
  fliplongs( (int *)(addr + header->rsh_frstr), header->rsh_nstring, 1 );
  fliplongs( (int *)(addr + header->rsh_frimg), header->rsh_nimages, 1 );
  fliplongs( (int *)(addr + header->rsh_trindex), header->rsh_ntree, 1 );
}

static void fix_objects( RSXHDR *header, char *addr, int flag )
{
  OBJECT  *tree, *op;
  TEDINFO *tp;
  ICONBLK *ip;
  BITBLK  *bp;
  long    k, offset;

  if (flag)
    { flip_header( header, addr ); flip_resource( header, addr, 1 ); }
  op = tree = (OBJECT *)(addr + header->rsh_object);
  for (k = 0; k < header->rsh_nobs; ++k)
  {
    offset = op->ob_spec.index;
    switch (op->ob_type & 0xFF)
    {
      case G_BUTTON:
      case G_STRING:
      case G_TITLE:
	op->ob_spec.free_string = addr + offset; break;
      case G_TEXT:
      case G_BOXTEXT:
      case G_FTEXT:
      case G_FBOXTEXT:
	op->ob_spec.tedinfo = tp = (TEDINFO *)(addr + offset);
	tp->te_ptext = addr + (long)tp->te_ptext;
	tp->te_ptmplt = addr + (long)tp->te_ptmplt;
	tp->te_pvalid = addr + (long)tp->te_pvalid; break;
      case G_IMAGE:
	op->ob_spec.bitblk = bp = (BITBLK *)(addr + offset);
	bp->bi_pdata = (int *)(addr + (long)bp->bi_pdata);
	vdi_trans( bp->bi_pdata, bp->bi_wb << 3, bp->bi_hl ); break;
      case G_ICON:
	op->ob_spec.iconblk = ip = (ICONBLK *)(addr + offset);
	ip->ib_pmask = (int *)(addr + (long)ip->ib_pmask);
	ip->ib_pdata = (int *)(addr + (long)ip->ib_pdata);
	ip->ib_ptext = addr + (long)ip->ib_ptext;
	vdi_trans( ip->ib_pmask, ip->ib_wicon, ip->ib_hicon );
	vdi_trans( ip->ib_pdata, ip->ib_wicon, ip->ib_hicon ); break;
      case G_USERDEF:
      case G_CICON:
	op->ob_flags = HIDETREE;
    }
    rsrc_obfix( tree, (int)k ); ++op;
} }

static void convert_resource( VIEW *tv )
{
  RSXHDR *header;
  char   *addr;
  long   len;
  int    fh;

  graf_mouse( BUSYBEE, 0 );
  if ((fh = Fopen( tv->path, 2 )) < 0)
    { graf_mouse( ARROW, 0 ); form_error( -fh - 31 ); return; }
  header = &tv->header; addr = tv->addr; len = Fseek( 0, fh, 2 );
  len -= Fseek( tv->buf - addr, fh, 0 );
  Fread( fh, len, tv->buf ); Fseek( 0, fh, 0 );
  flip_resource( header, addr, tv->flip );
  if (tv->flip == 0) flip_header( header, addr );
  if ((char *)header == addr) Fwrite( fh, sizeof(RSXHDR), header );
  else
  { { int *p = (int *)header;
      int count = 18; do *p++ = (int)*((long *)header)++; while (--count);
    }
    Fwrite( fh, sizeof(RSHDR), &tv->header );
    {
      unsigned *p = (unsigned *)addr;
      int count = 18; do *--(long *)header = *--p; while (--count);
  } }
  Fwrite( fh, len, tv->buf ); Fclose( fh );
  fix_objects( header, addr, tv->flip ^= 1 ); graf_mouse( ARROW, 0 );
}

static OBJECT *set_tree( VIEW *tv, int flag )
{
  OBJECT *tree;
  long   *poffset;

  poffset = (long *)(tv->addr + tv->header.rsh_trindex);
  tree = (OBJECT *)(tv->addr + poffset[tv->tree]);
  if (flag)
  {
    tree->ob_x = tv->x - (tv->lbc << 3);
    tree->ob_y = tv->y - (tv->tlc << 3);
  }
  else
  {
    tv->bc = (tree->ob_width + 7) >> 3;
    tv->lc = (tree->ob_height + 7) >> 3;
  }
  return tree;
}

static void new_tree( VIEW *tv, int flag )
{
  if (flag) { if (++tv->tree >= tv->header.rsh_ntree) tv->tree = 0; }
  else if (--tv->tree < 0) tv->tree += tv->header.rsh_ntree;
  set_tree( tv, 0 ); new_redraw();
}

static void draw_resource( VIEW *tv, int *clip )
{
  OBJECT *tree;
  int    xe, ye;

  tree = set_tree( tv, 1 );
  xe = tree->ob_x + tree->ob_width;
  ye = tree->ob_y + tree->ob_height;
  if (xe <= clip[2] || ye <= clip[3] || tree->ob_type == G_IBOX)
  {
    vr_recfl( handle, clip );
    if (xe <= clip[0] || ye <= clip[1]) return;
  }
  objc_draw( tree, ROOT, MAX_DEPTH, clip[0], clip[1],
	     clip[2] - clip[0] + 1, clip[3] - clip[1] + 1 );
}

static void free_resource() { }

#pragma warn -par
static int key_resource( VIEW *tv, int code, int ks )
{
  switch (code)
  {
    case CNTRL_CL: new_tree( tv, 0 ); return 0;
    case CNTRL_CR: new_tree( tv, 1 ); return 0;
    case CNTRL_K:  convert_resource( tv ); return 0;
  }
  return 1;
}
#pragma warn +par

static void sclick_resource( VIEW *tv, int mx, int my, int flag )
{
  if (flag) return;
  popup[2].ob_state =
  popup[4].ob_state = tv->header.rsh_ntree == 1 ? DISABLED : NORMAL;
  itostring( (int)tv->header.rsh_ntree, string0 + 7, 3 );
  itoa( (int)tv->tree + 1, string2, 10 );
#ifdef __TOS__
  popup[6].ob_spec.free_string = tv->flip ? string_i_to_m : string_m_to_i;
#else
  popup[6].ob_spec.free_string = tv->flip ? string_m_to_i : string_i_to_m;
#endif
  switch (popup_menu( popup, 3, mx, my, objc_draw ))
  {
    case 2: new_tree( tv, 0 ); break;
    case 4: new_tree( tv, 1 ); break;
    case 6: convert_resource( tv );
} }

VIEW *load_resource( int fh, long len )
{
  VIEW *rv;
  char *buf;

  if ((rv = Malloc( sizeof(VIEW) + len )) == 0)
    { Fclose( fh ); form_error( EINVMEM ); return 0; }
  buf = (char *)&rv->header; len -= Fread( fh, sizeof(RSHDR), buf );
#ifdef __TOS__
  if (rv->header.rsh_vrsn != 0x0003)
#else
  if (rv->header.rsh_vrsn != 0x0300)
#endif
  {
    unsigned *src = (unsigned *)(buf += sizeof(RSHDR));
    long *des = (long *)(buf + sizeof(RSHDR));
    int count = 18; do *--des = *--src; while (--count);
  }
  rv->addr = buf; Fread( fh, len, buf + sizeof(RSHDR) ); Fclose( fh );
  if (rv->header.rsh_ntree == 0)
    { Mfree( rv ); form_error( ENOENT ); return 0; }
  fix_objects( &rv->header, buf,
	       rv->flip = rv->header.rsh_ntree & 0xFF00FF00L ? 1 : 0 );
  if (popup->ob_next == 0) { --popup->ob_next; fix_tree( popup, 6 ); }
  rv->xfac = rv->yfac = 8; rv->tree = 0; set_tree( rv, 0 );
  rv->w = rv->bc << 3; rv->h = rv->lc << 3;
  rv->draw = draw_resource; rv->free = free_resource;
  rv->key = key_resource; rv->sclick = sclick_resource;
  return rv;
}