/* 
 *  call-seq:
 *     new(size, depth=0, flags=0)  ->  Surface
 *
 *  Create and initialize a new Surface object. 
 *
 *  A Surface is a grid of image data which you blit (i.e. copy) onto other
 *  Surfaces. Since the Rubygame display is also a Surface (see the Screen 
 *  class), Surfaces can be blit to the screen; this is the most common way
 *  to display images on the screen.
 *
 *  Currently, you must create a display window (see Screen#set_mode) before
 *  creating a new Surface.
 *
 *  This function takes these arguments:
 *  size::  requested surface size; an array of the form [width, height].
 *  depth:: requested color depth (in bits per pixel). If depth is 0 (default),
 *          use the color depth of the current Screen mode.
 *--
 *          automatically choose a color depth: either the depth of the Screen
 *          mode (if one has been set), or the greatest color depth available
 *          on the system.
 *++
 *  flags:: an Array or Bitwise-OR'd list of zero or more of the following 
 *          flags (located in the Rubygame module, e.g. Rubygame::SWSURFACE).
 *          This argument may be omitted, in which case the Surface 
 *          will be a normal software surface (this is not necessarily a bad
 *          thing).
 *          SWSURFACE::   (default) request a software surface.
 *          HWSURFACE::   request a hardware-accelerated surface (using a 
 *                        graphics card), if available. Creates a software
 *                        surface if hardware surfaces are not available.
 *          SRCCOLORKEY:: request a colorkeyed surface. #set_colorkey will
 *                        also enable colorkey as needed. For a description
 *                        of colorkeys, see #set_colorkey.
 *          SRCALPHA::    request an alpha channel. #set_alpha will
 *                        also enable alpha. as needed. For a description
 *                        of alpha, see #alpha.
 */
VALUE rbgm_surface_new(int argc, VALUE *argv, VALUE class)
{
        VALUE self;
        SDL_Surface *self_surf;
        SDL_PixelFormat* pixformat;
        Uint32 flags, Rmask, Gmask, Bmask, Amask;
        int w, h, depth, counter;
        

        if( SDL_GetVideoSurface() )
        {
                /* Pixel format is retrieved from the video surface. */
                pixformat = (SDL_GetVideoSurface())->format;
        }
        else
        {
                rb_raise(eSDLError,"Cannot create Surface before the Screen mode is set!");
                /* The following code causes an inexplicable segfault? :(  -j */
                /* pixformat = SDL_GetVideoInfo()->vfmt; */ 
        }

        Rmask = pixformat->Rmask;
        Gmask = pixformat->Gmask;
        Bmask = pixformat->Bmask;
        Amask = pixformat->Amask;

        if( (argc > 1) && (argv[1] != Qnil) && (argv[1] != 0) )
        {
                /* TODO: We might want to check that the requested depth makes sense. */
                depth = NUM2INT(argv[1]);
        }
        else
        {
                depth = pixformat->BitsPerPixel;
        }
                

        /* Get width and height for new surface from argv[0] */
        Check_Type(argv[0],T_ARRAY);

        if(RARRAY(argv[0])->len >= 2)
        {
                w = NUM2INT(rb_ary_entry(argv[0],0));
                h = NUM2INT(rb_ary_entry(argv[0],1));
        }
        else
                rb_raise(rb_eArgError,"wrong dimensions for Surface size (%d for 2)",\
                        RARRAY(argv[0])->len);
        

        if(argc > 2 && argv[2] != Qnil)
        {
                switch( TYPE(argv[2]) ){
                        case T_ARRAY:;
                                for(counter=0;  counter < RARRAY(argv[2])->len; counter += 1)
                    {
                      flags |= NUM2UINT(  rb_ary_entry( argv[2],counter )  );
                    }
                                break;
                        case T_FIXNUM:;
                                flags = NUM2UINT( argv[2] );
                                break;
                        default:;
                                rb_raise(rb_eArgError,"Wrong type for argument `flags' (wanted Fixnum or Array).");
                }
        }

        /* Finally, we can create the new Surface! Or try, anyway... */
        self_surf = SDL_CreateRGBSurface(flags,w,h,depth,Rmask,Gmask,Bmask,Amask);

        if( self_surf == NULL )
                rb_raise(eSDLError,"Could not create new surface: %s",SDL_GetError());


        /* Wrap the new surface in a crunchy candy VALUE shell. */
        self = Data_Wrap_Struct( cSurface,0,SDL_FreeSurface,self_surf );
        /* The default initialize() does nothing, but may be overridden. */
        rb_obj_call_init(self,argc,argv);
        return self;
}