#include <errno.h>
#include <stdio.h>
#include <Pt.h>
#include <Ph.h>
#include <photon/Pg.h>
#include <gf/gf.h>

void	print_gf_format( gf_format_t format )
{
			if( format == GF_FORMAT_BYTE )
			{
				printf( "\tGF_FORMAT_BYTE\n" );
			}
			if( format == GF_FORMAT_PAL8 )
			{
				printf( "\tGF_FORMAT_PAL8\n" );
			}
			if( format == GF_FORMAT_PACK_ARGB1555 )
			{
				printf( "\tGF_FORMAT_PACK_ARGB1555\n" );
			}
			if( format == GF_FORMAT_PKLE_ARGB1555 )
			{
				printf( "\tGF_FORMAT_PKLE_ARGB1555 \n" );
			}
			if( format == GF_FORMAT_PKBE_ARGB1555 )
			{
				printf( "\tGF_FORMAT_PKBE_ARGB1555\n" );
			}
			if( format == GF_FORMAT_PACK_RGB565 )
			{
				printf( "\tGF_FORMAT_PACK_RGB565\n" );
			}
			if( format == GF_FORMAT_PKLE_RGB565 )
			{
				printf( "\tGF_FORMAT_PKLE_RGB565\n" );
			}
			if( format == GF_FORMAT_PKBE_RGB565 )
			{
				printf( "\tGF_FORMAT_PKBE_RGB565\n" );
			}
			if( format == GF_FORMAT_BGR888 )
			{
				printf( "\tGF_FORMAT_BGR888\n" );
			}
			if( format == GF_FORMAT_BGRA8888 )
			{
				printf( "\tGF_FORMAT_BGRA8888\n" );
			}
			if( format == GF_FORMAT_ARGB8888 )
			{
				printf( "\tGF_FORMAT_ARGB8888\n" );
			}
			if( format == GF_FORMAT_PACK_YUV_UYVY )
			{
				printf( "\tGF_FORMAT_PACK_YUV_UYVY\n" );
			}
			if( format == GF_FORMAT_PKLE_YUV_UYVY )
			{
				printf( "\tGF_FORMAT_PKLE_YUV_UYVY\n" );
			}
			if( format == GF_FORMAT_PKBE_YUV_UYVY )
			{
				printf( "\tGF_FORMAT_PKBE_YUV_UYVY\n" );
			}
			if( format == GF_FORMAT_PACK_YUV_YUY2 )
			{
				printf( "\tGF_FORMAT_PACK_YUV_YUY2\n" );
			}
			if( format == GF_FORMAT_PKLE_YUV_YUY2 )
			{
				printf( "\tGF_FORMAT_PKLE_YUV_YUY2\n" );
			}
			if( format == GF_FORMAT_PKBE_YUV_YUY2 )
			{
				printf( "\tGF_FORMAT_PKBE_YUV_YUY2\n" );
			}
			if( format == GF_FORMAT_PACK_YUV_YVYU )
			{
				printf( "\tGF_FORMAT_PACK_YUV_YVYU\n" );
			}
			if( format == GF_FORMAT_PKLE_YUV_YVYU )
			{
				printf( "\tGF_FORMAT_PKLE_YUV_YVYU\n" );
			}
			if( format == GF_FORMAT_PKBE_YUV_YVYU )
			{
				printf( "\tGF_FORMAT_PKBE_YUV_YVYU\n" );
			}
			if( format == GF_FORMAT_PACK_YUV_V422 )
			{
				printf( "\tGF_FORMAT_PACK_YUV_V422\n" );
			}
			if( format == GF_FORMAT_PKLE_YUV_V422 )
			{
				printf( "\tGF_FORMAT_PKLE_YUV_V422\n" );
			}
			if( format == GF_FORMAT_PKBE_YUV_V422 )
			{
				printf( "\tGF_FORMAT_PKBE_YUV_V422 \n" );
			}
			if( format == GF_FORMAT_PACK_YUV_NV12 )
			{
				printf( "\tGF_FORMAT_PACK_YUV_NV12\n" );
			}
			if( format == GF_FORMAT_PACK_YUV_AYUV )
			{
				printf( "\tGF_FORMAT_PACK_YUV_AYUV\n" );
			}
			if( format == GF_FORMAT_PLANAR_YUV_YVU9 )
			{
				printf( "\tGF_FORMAT_PLANAR_YUV_YVU9\n" );
			}
			if( format == GF_FORMAT_PLANAR_YUV_YV12 )
			{
				printf( "\tGF_FORMAT_PLANAR_YUV_YV12\n" );
			}
			if( format == GF_FORMAT_PLANAR_YUV_420 )
			{
				printf( "\tGF_FORMAT_PLANAR_YUV_420\n" );
			}

}

int main( int argc, char **argv )
{
int					ret;
unsigned int		i, j;
gf_dev_t			pdev;
gf_dev_info_t		ginfo;
gf_display_t		pdisplay;
gf_display_info_t	dinfo;
gf_layer_t			player;
gf_layer_info_t		linfo;
gf_format_t			need_format;
gf_surface_t		psurface;
gf_surface_info_t	sinfo;
const unsigned		order[] = { 0, 1, 2, 3 };
gf_chroma_t			*gfchroma = NULL;
gf_color_t			gfchromacolor = 0;
gf_color_t			gfsurfacecolor;
uint8_t				red, green, blue, alpha;
gf_palette_t		layer_palette;

	gfchroma = (gf_chroma_t*)malloc( sizeof(gf_chroma_t) );
	if( !gfchroma )
	{
		printf( "can't malloc chroma: %s\n", strerror(errno) );
		exit(0);
	}

	memset( gfchroma, 0, sizeof(*gfchroma) );

	red = 0xf0;
	green = 0x00;
	blue = 0xf0;
	alpha = 0x00;

	gfchromacolor = (alpha << 24) | (red << 16) | (green << 8 ) | (blue << 0 );

	red = 0;
	green = 0;
	blue = 0;
	alpha = 0;

	gfsurfacecolor = (alpha << 24) | (red << 16) | (green << 8 ) | (blue << 0 );

	layer_palette.ncolors = 1;
	layer_palette.colors = &gfsurfacecolor;

	ret = gf_dev_attach( &pdev, GF_DEVICE_INDEX(0), &ginfo );

	if( ret != GF_ERR_OK )
	{
		printf( "dev: error %d\n", ret );
		exit( ret );
	}

	printf( "displays number %d\n", ginfo.ndisplays  );

	for( i = 0; i < ginfo.ndisplays;  )
	{
		ret = gf_display_attach( &pdisplay, pdev, i, &dinfo );
		printf( "display: number %d\n", i );
		if( ret == GF_ERR_OK )
		{
			printf( "display: attached\n" );
			printf( "display: resolution %dX%d, refresh = %dHz\n",dinfo.xres,dinfo.yres,dinfo.refresh);
			printf( "display: layers %d\n",dinfo.nlayers);
			printf( "display: format 0x%08X, named ",dinfo.format);
			print_gf_format( dinfo.format );
			break;
		}
		else
		{
			printf( "display: attach error %d\n", ret );
			gf_dev_detach( pdev );
			exit( ret );
		}
		i ++;
	}

	gf_modeinfo_t   mode;

	for( i = 0; ; i ++ )
	{
		ret = gf_display_query_mode( pdisplay, i, &mode );

		if( ret != GF_ERR_OK )
		{
			break;
		}
		printf( "mode %d primary format: ", i );
		print_gf_format( mode.primary_format );
		if( mode.flags & GF_MODE_GENERIC != GF_MODE_GENERIC )
		{
			printf( "resolution: %dx%d, refresh %d\n", mode.xres, mode.yres, mode.refresh[0] );
		}
	}


	ret = gf_display_set_layer_order( pdisplay, order, GF_LAYER_UPDATE_NO_WAIT_IDLE );
	printf( "layer order: %d\n", ret );

	need_format = dinfo.format;

	need_format = GF_FORMAT_PACK_YUV_UYVY;
//	need_format = GF_FORMAT_PACK_YUV_YUY2;
//	need_format = GF_FORMAT_BGRA8888;

	for( i = 0; i < dinfo.nlayers;  )
	{
		ret = gf_layer_attach( 
								&player,
								pdisplay,
								i,
								0 
								| GF_LAYER_ATTACH_NODEFAULTS
								| GF_LAYER_ATTACH_PASSIVE
								//| GF_LAYER_ATTACH_NOAUTODISABLE
							 );

		if( ret != GF_ERR_OK )
		{
			printf( "layer %d: attach error %d\n", i, ret );
			if( ret == GF_ERR_INUSE )
			{
				printf( "layer %d is IN_USE\n", i );
				i ++;
				continue;
			}
			else
			{
				printf( "layer %d error %d. BREAK\n", i, ret );
				break;
			}
		}

		for( j = 0; j < 16; )
		{
			ret = gf_layer_query( player, j, &linfo );

			printf( "--------------------------------------\n" );

			if( ret != GF_ERR_OK )
			{
				printf( "layer %d reg %d: query error %d\n", i, j, ret );
				j ++;
				break;
			}

			printf( "layer %d, reg %d: caps 0x%08X, chroma 0x%08X alpha=0x%08X\n", i, j, linfo.caps, linfo.chromakey_caps, linfo.alpha_valid_flags );
			printf( "order caps 0x%08X\n", linfo.order_caps );
			printf( "format 0x%08X:\n", linfo.format );
			
			print_gf_format( linfo.format );

			if( linfo.caps & GF_LAYER_CAP_MAIN_DISPLAY == GF_LAYER_CAP_MAIN_DISPLAY )
			{
				printf( "layer %d: MAIN layer, continue...", i );
				j ++;
				break;
			}

			if( linfo.format == need_format )
			{
				printf( "Will use this!\n" );
				break;
			}

			j ++;
		}

		printf( "--------------------------------------\n" );

		gf_layer_detach( player );

		if( linfo.format == need_format )
		{
			break;
		}

		i ++;
	}

	unsigned upflags;
	
	upflags =	0
				//| GF_LAYER_UPDATE_NO_WAIT_IDLE
				//| GF_LAYER_UPDATE_NO_WAIT_VSYNC
				;

	ret = gf_layer_attach( 
							&player, 
							pdisplay, 
							i,
							0
							//| GF_LAYER_ATTACH_NODEFAULTS
							//| GF_LAYER_ATTACH_PASSIVE 
							//| GF_LAYER_ATTACH_NOAUTODISABLE
						);

	if( ret != GF_ERR_OK )
	{
		printf( "layer_attach %d ret = %d\n", i, ret );	
		gf_display_detach( pdisplay );
		gf_dev_detach( pdev );

		exit(0);
	}

	printf( "Attached to layer: %d\n", i );

	gf_layer_disable( player );
	gf_layer_update( player, upflags );

	ret = 

	gf_surface_create_layer	(	&psurface, 
								&player, 1, 
								0, 
								//640, 512,
								dinfo.xres/2, dinfo.yres/2,
								need_format, 
								NULL, //&layer_palette, 
								0
								| GF_SURFACE_CREATE_PAGE_ALIGNED
								//| GF_SURFACE_CREATE_SHAREABLE
								| GF_SURFACE_CREATE_PHYS_CONTIG
								| GF_SURFACE_CREATE_CPU_LINEAR_ACCESSIBLE
								| GF_SURFACE_CREATE_CPU_FAST_ACCESS
								//| GF_SURFACE_CREATE_2D_ACCESSIBLE
								//| GF_SURFACE_CREATE_3D_ACCESSIBLE
								//| GF_SURFACE_CREATE_VG_ACCESSIBLE
							);

	if( ret != GF_ERR_OK )
	{
		printf( "can't create surface: %d\n", ret );
		gf_layer_detach( player );
		gf_display_detach( pdisplay );
		gf_dev_detach( pdev );
		exit(0);
	}

	if( NULL == gf_surface_get_info( psurface, &sinfo ) )
	{
		printf( "can't get surface info: %d\n", ret );
		gf_surface_free( psurface );
		gf_layer_detach( player );
		gf_display_detach( pdisplay );
		gf_dev_detach( pdev );
		exit(0);
	}

	printf( "surface: sid = %d, w=%d, h=%d, stride=%d, flags=0x%08X\n", sinfo.sid, sinfo.w, sinfo.h, sinfo.stride, sinfo.flags );
	printf( "surface: paddr=0x%08X vaddr=0x%08X\n", sinfo.paddr, sinfo.vaddr );
	printf( "format:" );
	print_gf_format( sinfo.format );

	gf_context_t pcontext;
	ret = gf_context_create( &pcontext );

	if( ret != GF_ERR_OK )
	{
		printf( "can't create context: %d\n", ret );
		gf_surface_free( psurface );
		gf_layer_detach( player );
		gf_display_detach( pdisplay );
		gf_dev_detach( pdev );
		exit(0);
	}

	if( (ret=gf_context_set_surface( pcontext, psurface )) != GF_ERR_OK)
	{
		printf( "can't set context surface: %d\n", ret );
	}

	gfchroma->mode = 0
					//| GF_CHROMA_OP_SRC_MATCH 
					| GF_CHROMA_OP_DST_MATCH
					| GF_CHROMA_OP_DRAW
					//| GF_CHROMA_OP_NO_DRAW
					;
	gfchroma->color0 = gfchromacolor;

	printf( "chromacolor=0x%08X, mode=0x%08X\n", gfchroma->color0, gfchroma->mode );

	gf_layer_set_chroma( player, gfchroma );
	ret = gf_layer_update( player, upflags );
	printf( "chroma update: %d\n", ret );

	gf_layer_set_surfaces( player, &psurface, 1 );
	ret = gf_layer_update( player, upflags );
	printf( "set_surfaces update: %d\n", ret );

	gf_layer_set_src_viewport( player, 0, 0, dinfo.xres/2, dinfo.yres/2 );
	ret = gf_layer_update( player, upflags );
	printf( "src_viewport update: %d\n", ret );

	gf_layer_set_dst_viewport( player, dinfo.xres-sinfo.w, dinfo.yres-sinfo.h-200, dinfo.xres, dinfo.yres-200 );
	ret = gf_layer_update( player, upflags );
	printf( "dst_viewport update: %d\n", ret );

	gf_layer_enable( player );
	ret = gf_layer_update( player, upflags );
	printf( "enable update: %d\n", ret );

	gf_layer_state_t	pstate;

	ret = gf_layer_query_state( player, &pstate );

	if( ret != GF_ERR_OK )
	{
		printf( "layer state error: %d\n", ret );
		gf_layer_disable( player );
		gf_layer_update( player, upflags );
		gf_context_unset_surface( pcontext );
		gf_surface_free( psurface );
		gf_context_free( pcontext );
		gf_layer_detach( player );
		gf_display_detach( pdisplay );
		gf_dev_detach( pdev );
		exit(0);
	}

	printf( "src: %d,%d,%d,%d dst: %d,%d,%d,%d\n",	pstate.src_vp.x1, pstate.src_vp.y1, pstate.src_vp.x2, pstate.src_vp.y2,
													pstate.dst_vp.x1, pstate.dst_vp.y1, pstate.dst_vp.x2, pstate.dst_vp.y2 );

	printf( "en: %d, chroma: m=0x%02X, c0=0x%08X, c1=0x%08X, msk=0x%08X\n", pstate.enabled, pstate.chroma.mode, pstate.chroma.color0,
																			pstate.chroma.color1, pstate.chroma.mask );

	short x = 0, y = 0;

	gf_draw_begin( pcontext );
	gf_context_set_fgcolor(pcontext,gfchromacolor);
	gf_draw_rect(pcontext,0,0,640,512);
	gf_draw_end( pcontext );

	for( i = 0; i < 100; i ++ )
	{
		gf_draw_begin( pcontext );

		gf_context_set_fgcolor(pcontext,gfchromacolor);
		gf_draw_rect(pcontext,0,0,640,512);

		gf_context_set_fgcolor(pcontext,0xF0F0F0);
		gf_draw_rect(pcontext,10+x,10+y,50+x,50+y);

		gf_context_set_fgcolor(pcontext,0x0F0F0F);
		gf_draw_rect(pcontext,20+x,20+y,40+x,40+y);

		gf_draw_end( pcontext );

		x = i*5;
		y = i*5;

		delay( 100 );
	}

	gf_layer_disable( player );
	gf_layer_update( player, upflags );
	gf_context_unset_surface( pcontext );
	gf_surface_free( psurface );
	gf_context_free( pcontext );
	gf_layer_detach( player );
	gf_display_detach( pdisplay );
	gf_dev_detach( pdev );

	free( gfchroma );

	printf( "normal exit...\n" );

	exit(0);
	return 0;
}
