/////////////////////////////////////////////////////////////////////////
// $Id: nogui.cc,v 1.15 2002/03/16 11:30:06 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA



#include "bochs.h"
#include "icon_bochs.h"
#define LOG_THIS bx_gui.
#include <XBApp.h>
#include "wchar.h"

#define XFONT_TRUETYPE
#include <xfont.h>

extern byte*				g_pBlitBuff ;
extern LPDIRECT3DTEXTURE8	g_Texture;
extern unsigned g_theWidth, g_theHeight ;
static unsigned pitch;
static unsigned x_tilesize = 0, y_tilesize = 0;
extern XFONT*      m_pConsoleTTF;    // Pointer to the Arial TrueTypeFont
extern D3DPalette			*m_pd3dPalette ;
extern LPDIRECT3DDEVICE8     m_pd3dDevice;        // The D3D rendering device
extern D3DCOLOR *g_palette ;
extern int       g_palchanged ;
unsigned int textmode ;

// This file defines stubs for the GUI interface, which is a
// place to start if you want to port bochs to a platform, for
// which there is no support for your native GUI, or if you want to compile
// bochs without any native GUI support (no output window or
// keyboard input will be possible).
// Look in 'x.cc', 'beos.cc', and 'win32.cc' for specific
// implementations of this interface.  -Kevin



// ::SPECIFIC_INIT()
//
// Called from gui.cc, once upon program startup, to allow for the
// specific GUI code (X11, BeOS, ...) to be initialized.
//
// th: a 'this' pointer to the gui class.  If a function external to the
//     class needs access, store this pointer and use later.
// argc, argv: not used right now, but the intention is to pass native GUI
//     specific options from the command line.  (X11 options, BeOS options,...)
//
// tilewidth, tileheight: for optimization, graphics_tile_update() passes
//     only updated regions of the screen to the gui code to be redrawn.
//     These define the dimensions of a region (tile).
// headerbar_y:  A headerbar (toolbar) is display on the top of the
//     VGA window, showing floppy status, and other information.  It
//     always assumes the width of the current VGA mode width, but
//     it's height is defined by this parameter.

  void
bx_gui_c::specific_init(bx_gui_c *th, int argc, char **argv, unsigned tilewidth, unsigned tileheight,
                     unsigned headerbar_y)
{
  th->put("NGUI");
  UNUSED(th);
  UNUSED(argc);
  UNUSED(argv);
  UNUSED(tilewidth);
  UNUSED(tileheight);
  UNUSED(headerbar_y);

  UNUSED(bochs_icon_bits);  // global variable

  if (bx_options.Oprivate_colormap->get ()) {
    BX_INFO(("private_colormap option ignored."));
    }

  g_theWidth = 640;
  g_theHeight = 400 ;
//  dimension_y = 800 ;
  x_tilesize = tilewidth;
  y_tilesize = tileheight;

	RECT rectSource;
	rectSource.top = 0;
	rectSource.left = 0;
	rectSource.bottom = g_theHeight - 1;
	rectSource.right  = g_theWidth  - 1 ;

	// Lock the rect in our texture
	D3DLOCKED_RECT d3dlr;
	g_Texture->LockRect(0, &d3dlr, &rectSource, 0);

	pitch = d3dlr.Pitch ;

	g_Texture->UnlockRect( 0 ) ;

	textmode = 0 ;

}


// ::HANDLE_EVENTS()
//
// Called periodically (vga_update_interval in .bochsrc) so the
// the gui code can poll for keyboard, mouse, and other
// relevant events.
void g_handleevents() ;

  void
bx_gui_c::handle_events(void)
{
	  //g_handleevents() ;
}


// ::FLUSH()
//
// Called periodically, requesting that the gui code flush all pending
// screen update requests.

  void
bx_gui_c::flush(void)
{
}


// ::CLEAR_SCREEN()
//
// Called to request that the VGA region is cleared.  Don't
// clear the area that defines the headerbar.

  void
bx_gui_c::clear_screen(void)
{
     //BX_INFO(("clearscreen")) ;
	memset( g_pBlitBuff, 0, g_theHeight*pitch ) ;
  
}



// ::TEXT_UPDATE()
//
// Called in a VGA text mode, to update the screen with
// new content.
//
// old_text: array of character/attributes making up the contents
//           of the screen from the last call.  See below
// new_text: array of character/attributes making up the current
//           contents, which should now be displayed.  See below
//
// format of old_text & new_text: each is 4000 bytes long.
//     This represents 80 characters wide by 25 high, with
//     each character being 2 bytes.  The first by is the
//     character value, the second is the attribute byte.
//     I currently don't handle the attribute byte.
//
// cursor_x: new x location of cursor
// cursor_y: new y location of cursor

  void
bx_gui_c::text_update(Bit8u *old_text, Bit8u *new_text,
                      unsigned long cursor_x, unsigned long cursor_y,
                      Bit16u cursor_state, unsigned nrows)
{
	UNUSED(old_text);
	UNUSED(new_text);
	UNUSED(cursor_x);
	UNUSED(cursor_y);
	UNUSED(cursor_state);
	UNUSED(nrows);

     //BX_INFO(("textupdate")) ;

	WCHAR wstr[400] ;
	char  str[100] ;
	//char  buf[100*1024] ;
	char  color ;
	char  curr_color ;
	char  bkcolor ;
	char  curr_bkcolor ;
	byte *bufptr ;


	HRESULT res ;

	wstr[1] = L'\0' ;

	curr_color = 999 ;

	if ( textmode==0 )
	{
		
		//BX_INFO( ( "textmode=1\r\n" ) ) ;
		*(g_palette+0) = 0xFF000000 ;
		*(g_palette+1) = 0xFF0000A8;
		*(g_palette+2) = 0xFF00A800;
		*(g_palette+3) = 0xFF00A8A8;
		*(g_palette+4) = 0xFFA80000;
		*(g_palette+5) = 0xFFA800A8;
		*(g_palette+6) = 0xFFA85400;
		*(g_palette+7) = 0xFFA8A8A8;
		*(g_palette+8) = 0xFF545454;
		*(g_palette+9) = 0xFF5454FC;
		*(g_palette+10) = 0xFF54FC54;
		*(g_palette+11) = 0xFF54FCFC;
		*(g_palette+12) = 0xFFFC5454;
		*(g_palette+13) = 0xFFFC54FC;
		*(g_palette+14) = 0xFFFCFC54;
		*(g_palette+15) = 0xFFFCFCFC;
		g_palchanged = 1 ;

		textmode = 1 ;
	}

	for ( int y = 0 ; y < nrows ; y++ )
	{
		for ( int x = 0 ; x < 80 ; x++ )
		{
			wstr[0] = btowc( new_text[ y*160 + x*2 ] ) ;
			color = new_text[ y*160 + x*2 + 1 ] ;
			bkcolor = ((color>>4) & 0x0F)  ;
			color = color & 0x0F ;

			if ( curr_color != color )
			{
				//BX_INFO( ( "text color %u, bkg color %u\r\n", color, bkcolor ) ) ;

				m_pConsoleTTF->SetTextColor( ( color  << 24) ) ;
				//m_pConsoleTTF->SetTextColor( ( 14  << 24) ) ;
			}

			bufptr = g_pBlitBuff + y*13*pitch + x*8 ;
			for ( int cy = y*13 ; cy < y*13 + 16 ; cy++ )
			{
				memset( bufptr, bkcolor, 8 ) ;
				//memset( bufptr, x, 8 ) ;
				bufptr += pitch ;
			}
			curr_color = color ;

			res = m_pConsoleTTF->TextOutToMemory( g_pBlitBuff, pitch, g_theWidth, g_theHeight, D3DFMT_A8, wstr, -1, x*8, y*13 ) ;
		}
	}

	if ( (cursor_y*80 + cursor_x) < nrows*80 )
	{
		wstr[0] = btowc( new_text[ cursor_y*160 + cursor_x*2 ] ) ;
		color = new_text[ cursor_y*160 + cursor_x*2 + 1 ] ;
		bkcolor = ((color>>4)+8) & 0x0F  ;
		color = (color+8) & 0x0F ;

	
		if ( curr_color != color )
		{
			//BX_INFO( ( "text color %u, bkg color %u\r\n", color, bkcolor ) ) ;

			m_pConsoleTTF->SetTextColor( ( color  << 24) ) ;
			//m_pConsoleTTF->SetTextColor( ( 14  << 24) ) ;
		}

		bufptr = g_pBlitBuff + cursor_y*13*pitch + cursor_x*8 ;
		for ( int cy = cursor_y*13 ; cy < cursor_y*13 + 16 ; cy++ )
		{
			memset( bufptr, bkcolor, 8 ) ;
			//memset( bufptr, x, 8 ) ;
			bufptr += pitch ;
		}
		curr_color = color ;

		res = m_pConsoleTTF->TextOutToMemory( g_pBlitBuff, pitch, g_theWidth, g_theHeight, D3DFMT_A8, wstr, -1, cursor_x*8, cursor_y*13 ) ;
	
	}
}

  int
bx_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
{
  UNUSED(bytes);
  UNUSED(nbytes);
  return 0;
}

  int
bx_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
{
  UNUSED(text_snapshot);
  UNUSED(len);
  return 0;
}


// ::PALETTE_CHANGE()
//
// Allocate a color in the native GUI, for this color, and put
// it in the colormap location 'index'.
// returns: 0=no screen update needed (color map change has direct effect)
//          1=screen updated needed (redraw using current colormap)

  Boolean
bx_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue)
{
	  static int dopal = 0 ;
  UNUSED(index);
  UNUSED(red);
  UNUSED(green);
  UNUSED(blue);

	//BX_INFO(( "palette change %u", index )) ;

	D3DCOLOR color ;

	g_palchanged = 1 ;

	textmode=0 ;

	color = ( 0xFF << 24 ) | ( (red&0xFF) << 16 ) | ( (green&0xFF) << 8 ) | (blue&0xFF)  ;
	//color = ( red&0xFF << 24 ) | ( (green&0xFF) << 16 ) | ( (blue&0xFF) << 8 ) | (0xFF&0xFF)  ;
	memcpy( g_palette+index, &color, sizeof(color) ) ;
 
	//if ( index == 63 )
	//{
		//for ( int ii = 0 ; ii < 16 ; ii++ )
		//{
			//BX_INFO(( "palette %02u = %08.8X\r\n", ii,*(g_palette+ii) )) ;
		//}
	//}

  return(0);
}


// ::GRAPHICS_TILE_UPDATE()
//
// Called to request that a tile of graphics be drawn to the
// screen, since info in this region has changed.
//
// tile: array of 8bit values representing a block of pixels with
//       dimension equal to the 'tilewidth' & 'tileheight' parameters to
//       ::specific_init().  Each value specifies an index into the
//       array of colors you allocated for ::palette_change()
// x0: x origin of tile
// y0: y origin of tile
//
// note: origin of tile and of window based on (0,0) being in the upper
//       left of the window.

  void
bx_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
{
  UNUSED(tile);
  UNUSED(x0);
  UNUSED(y0);
     //BX_INFO(("tileupdate")) ;

  if ( textmode==1 )
  {
		//BX_INFO( ( "textmode=0\r\n" ) ) ;
		*(g_palette+0) = 0xFF000000;
		*(g_palette+1) = 0xFF0000A8;
		*(g_palette+2) = 0xFF00A800;
		*(g_palette+3) = 0xFF00A8A8;
		*(g_palette+4) = 0xFFA80000;
		*(g_palette+5) = 0xFFA800A8;
		*(g_palette+6) = 0xFFA8A800;
		*(g_palette+7) = 0xFFA8A8A8;
		*(g_palette+8) = 0xFF000054;
		*(g_palette+9) = 0xFF0000FC;
		*(g_palette+10) = 0xFF00A854;
		*(g_palette+11) = 0xFF00A8FC;
		*(g_palette+12) = 0xFFA80054;
		*(g_palette+13) = 0xFFA800FC;
		*(g_palette+14) = 0xFFA8A854;
		*(g_palette+15) = 0xFFA8A8FC;
		g_palchanged = 1 ;
	textmode = 0 ;
  }


  for ( int y = 0 ; y < y_tilesize ; y++ )
  {
	  memcpy( g_pBlitBuff + ((y0+y)*pitch) + x0, tile + (y*x_tilesize), x_tilesize ) ;
  }
}



// ::DIMENSION_UPDATE()
//
// Called when the VGA mode changes it's X,Y dimensions.
// Resize the window to this size, but you need to add on
// the height of the headerbar to the Y value.
//
// x: new VGA x size
// y: new VGA y size (add headerbar_y parameter from ::specific_init().

  void
bx_gui_c::dimension_update(unsigned x, unsigned y)
{
  UNUSED(x);
  UNUSED(y);

  g_theWidth = x;
  g_theHeight = y;

	RECT rectSource;
	rectSource.top = 0;
	rectSource.left = 0;
	rectSource.bottom = g_theHeight - 1;
	rectSource.right  = g_theWidth  - 1 ;

	// Lock the rect in our texture
	D3DLOCKED_RECT d3dlr;
	g_Texture->LockRect(0, &d3dlr, &rectSource, 0);

	pitch = d3dlr.Pitch ;

	g_Texture->UnlockRect( 0 ) ;

}


// ::CREATE_BITMAP()
//
// Create a monochrome bitmap of size 'xdim' by 'ydim', which will
// be drawn in the headerbar.  Return an integer ID to the bitmap,
// with which the bitmap can be referenced later.
//
// bmap: packed 8 pixels-per-byte bitmap.  The pixel order is:
//       bit0 is the left most pixel, bit7 is the right most pixel.
// xdim: x dimension of bitmap
// ydim: y dimension of bitmap

  unsigned
bx_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
{
  UNUSED(bmap);
  UNUSED(xdim);
  UNUSED(ydim);
  return(0);
}


// ::HEADERBAR_BITMAP()
//
// Called to install a bitmap in the bochs headerbar (toolbar).
//
// bmap_id: will correspond to an ID returned from
//     ::create_bitmap().  'alignment' is either BX_GRAVITY_LEFT
//     or BX_GRAVITY_RIGHT, meaning install the bitmap in the next
//     available leftmost or rightmost space.
// alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT,
//     meaning install the bitmap in the next
//     available leftmost or rightmost space.
// f: a 'C' function pointer to callback when the mouse is clicked in
//     the boundaries of this bitmap.

  unsigned
bx_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
{
  UNUSED(bmap_id);
  UNUSED(alignment);
  UNUSED(f);
  return(0);
}


// ::SHOW_HEADERBAR()
//
// Show (redraw) the current headerbar, which is composed of
// currently installed bitmaps.

  void
bx_gui_c::show_headerbar(void)
{
}


// ::REPLACE_BITMAP()
//
// Replace the bitmap installed in the headerbar ID slot 'hbar_id',
// with the one specified by 'bmap_id'.  'bmap_id' will have
// been generated by ::create_bitmap().  The old and new bitmap
// must be of the same size.  This allows the bitmap the user
// sees to change, when some action occurs.  For example when
// the user presses on the floppy icon, it then displays
// the ejected status.
//
// hbar_id: headerbar slot ID
// bmap_id: bitmap ID

  void
bx_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
{
  UNUSED(hbar_id);
  UNUSED(bmap_id);
}


// ::EXIT()
//
// Called before bochs terminates, to allow for a graceful
// exit from the native GUI mechanism.

  void
bx_gui_c::exit(void)
{
  BX_INFO(("bx_gui_c::exit() not implemented yet."));
}

  void
bx_gui_c::mouse_enabled_changed_specific (Boolean val)
{
}
