#include <boost/shared_array.hpp>
#include <errno.h>
#include "image_v4linput.h"

#include "colourspace.h"

using namespace boost;
using namespace std;

namespace mimas {


template<>
void image_v4linput< rgba< unsigned char > >::read
  (image< rgba< unsigned char > > &img ) throw (mimasexception)
{
  // State-variable never becomes false. Input from video4linux only comes
  // to an end by an error.
  assert( state == true );

  shared_array< unsigned char > buffer;
  void *src = NULL;
  
  if ( map != MAP_FAILED ) {
    video_mmap vmap;
    vmap.frame = 0;
    vmap.width = win.width;
    vmap.height = win.height;
    vmap.format = pic.palette;

    MMERROR( xioctl( VIDIOCMCAPTURE, &vmap ) == 0, mimasexception, ,
             "Error initiating capture of image: " << strerror( errno ) );

    MMERROR( xioctl( VIDIOCSYNC, &vmap ) == 0, mimasexception, ,
             "Error on synchronising with capture of image: "
             << strerror( errno ) );

    src = map;
  } else {
    int size;
    switch ( pic.palette ) {
    case VIDEO_PALETTE_RGB24:
      size = 3 * win.width * win.height;
      break;
    case VIDEO_PALETTE_YUV420P:
      size = win.width * win.height * 3 / 2;
      break;
    case VIDEO_PALETTE_UYVY:
    case VIDEO_PALETTE_YUV422:
      size = win.width * win.height * 2;
      break;
    default:
      assert( false );
      MMERROR( false, mimasexception, ,
               "Software error in colour-grabbing code. Encountered "
               "unsupported palette number " << pic.palette << "." );
    };
    buffer = shared_array< unsigned char >( new unsigned char[ size ] );
    src = (void *)buffer.get();
    MMERROR( ::read( fd, src, size ) != -1, mimasexception, ,
             "Error reading from device: " << strerror( errno ) );
  };

  img.init( win.width, win.height );

#ifndef NDEBUG
  std::cerr << img.rawData() << ' '
            << img.getSize() << ' '
            << img.getWidth() << ' ' << img.getHeight() << std::endl;

#endif
  switch ( pic.palette ) {
  case VIDEO_PALETTE_RGB24:
    rgb_to_rgba( (const char *)src, win.width, win.height,
                 (char *)img.rawData() );
    break;
  case VIDEO_PALETTE_YUV420P:
    yuv420p_to_rgba( (const char *)src, win.width, win.height,
                     (char *)img.rawData() );
    break;
  case VIDEO_PALETTE_UYVY:
  case VIDEO_PALETTE_YUV422:
    uyvy_to_rgba( (const char *)src, win.width, win.height,
                  (char *)img.rawData() );
    break;
  default:
    assert( false );
    MMERROR( false, mimasexception, ,
             "Software error in colour-grabbing code. Encountered "
             "unsupported palette number " << pic.palette << "." );
  };
}

template<>
void image_v4linput< rgba< unsigned char > >::selectPalette(void)
  throw(mimasexception)
{
  boost::array< __u16, 14 > palette;
  palette[  0 ] = VIDEO_PALETTE_YUV420P;// ->RGBA supported
  palette[  1 ] = VIDEO_PALETTE_UYVY;// ->RGBA supported
  palette[  2 ] = VIDEO_PALETTE_YUV422;// -> RGBA supported
  palette[  3 ] = VIDEO_PALETTE_RGB24;// ->RGBA supported
  palette[  4 ] = VIDEO_PALETTE_HI240;
  palette[  5 ] = VIDEO_PALETTE_RGB565;
  palette[  6 ] = VIDEO_PALETTE_RGB555;
  palette[  7 ] = VIDEO_PALETTE_RGB32;
  palette[  8 ] = VIDEO_PALETTE_YUYV;
  palette[  9 ] = VIDEO_PALETTE_YUV420;
  palette[ 10 ] = VIDEO_PALETTE_YUV411;
  palette[ 11 ] = VIDEO_PALETTE_RAW;
  palette[ 12 ] = VIDEO_PALETTE_YUV422P;
  palette[ 13 ] = VIDEO_PALETTE_YUV411P;
  
  pic.brightness = pic.hue = pic.colour = pic.contrast = pic.whiteness  = 32767;
  pic.depth = 24;
  
  int selected = 0;
    
  while ( true ) {
          
    pic.palette = palette[ selected ];
    int r = xioctl( VIDIOCSPICT, &pic );
    if ( r == 0 ) {
#ifndef NDEBUG
      std::cerr << "Using " << ( selected + 1 ) << "th supported option."
                << std::endl;
#endif
      break;
    };
    selected++;
    MMERROR( selected < (signed)palette.size(),
             mimasexception, ,
             "Camera-driver doesn't offer a colour-video-palette known to "
             "mimas." );
  };
  MMERROR( selected < 4, mimasexception, ,
           "Colour-grabbing with video-palette "
           << palette[ selected ] << " (kmando-index " << selected
           << ") not supported by kmando. Please contact the developers." );
}

};