#include "dxr3out.hpp"

#ifdef benchmark_output
#include "bench.hpp"
#endif

#include "gettext.hpp"

#include <linux/em8300.h> 
#include <sys/ioctl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

void Dxr3::run()
{
#ifdef benchmark_output
  Bench bench2;
  Bench bench;
#endif

  while (true) {

    drawing = false;
    new_to_draw = false;

    output_done.signal();
    output_ready.wait();
    output_ready.reset();

    if (!locked)
      continue;

    drawing = true;

    locked_mutex.enterMutex();

    UINT8 *frame = reinterpret_cast<UINT8 *>(imlib_image_get_data_for_reading_only());

#ifdef benchmark_output
    bench2.start();
    bench.start();
#endif

    iframe = mpeg_draw(frame);

    if (iframe.data[iframe.size - 1] != 0xb7) {
      /* add sequence end code */
      iframe.data[iframe.size] = 0x00;
      iframe.data[iframe.size + 1] = 0x00;
      iframe.data[iframe.size + 2] = 0x01;
      iframe.data[iframe.size + 3] = 0xb7;
      iframe.size += 4;
    }

#ifdef benchmark_output
    bench.stop();
    bench.print("libavcodec done rendering frame ( = convert + encode)");
#endif

#ifdef benchmark_output
    bench.start();
#endif

    write(fd_video, iframe.data, iframe.size);

#ifdef benchmark_output
    bench.stop();
    bench.print("done writing to mpeg1 frame to the dxr3");
#endif

#ifdef benchmark_output
    bench2.stop();
    bench2.print("dxr3 complete draw");
#endif

    locked_mutex.leaveMutex();
  }
}

void Dxr3::redraw()
{
  if (initialized != 1){
    DebugPrint perror(gettext("Trying to write to an unitialized device"),
		      Print::DEBUGGING, DebugPrint::CRITICAL, "DXR3");
    return;
  }

  locked_mutex.enterMutex();

  write(fd_video, iframe.data, iframe.size); 

  locked_mutex.leaveMutex();
}

void Dxr3::lock()
{
  // setup 4:3 for menu
  system((conf->p_em8300setup_path() + " " + conf->p_tv_mode() + " -s " + conf->p_audio_output_mode()).c_str());
  
  init();

  locked = true;
}

// unlock it for other processes to use, this won't actually
// kill the application 
void Dxr3::unlock()
{
  deinit();
}

void Dxr3::deinit()
{
  locked_mutex.enterMutex();

  locked = false;

  mpeg_deinit();

  if (initialized == -1)
    return;
  
  ::close(fd_video);
  ::close(fd_control);

  fd_video = -1;
  initialized = -1;

  locked_mutex.leaveMutex();
}

Dxr3::Dxr3() : Render_device(), fd_control(-1), fd_video(-1), initialized(-1), locked(false)
{
}

void Dxr3::init()
{
  if (initialized != -1)
    return;

  int ioval;
  em8300_register_t reg;
  
  fd_video = open ("/dev/em8300_mv-0", O_WRONLY);
  if (fd_video < 1){
    DebugPrint perror(gettext("Could not open device: ") + 
		      std::string("/dev/em8300_mv-0"), 
		      Print::DEBUGGING, DebugPrint::INFO, "DXR3");
    std::exit(1);
  }

  fd_control = open ("/dev/em8300-0", O_WRONLY);
  if (fd_control < 1){
    DebugPrint perror(gettext("Could not open device: ") + 
		      std::string("/dev/em8300-0"), 
		      Print::DEBUGGING, DebugPrint::INFO, "DXR3");
    std::exit(1);
  }

  /* Set the playmode to play (just in case another app has set it to something else) */
  ioval = EM8300_PLAYMODE_PLAY;
  if (ioctl(fd_control, EM8300_IOCTL_SET_PLAYMODE, &ioval) < 0) {
    DebugPrint perror(gettext("Unable to set playmode"), 
		      Print::DEBUGGING, DebugPrint::WARNING, "DXR3");
  }
	
  /* Start em8300 prebuffering and sync engine */
  reg.microcode_register = 1;
  reg.reg = 0;
  reg.val = MVCOMMAND_SYNC;
  ioctl(fd_control, EM8300_IOCTL_WRITEREG, &reg);

  /* Clean buffer by syncing it */
  ioval = EM8300_SUBDEVICE_VIDEO;
  ioctl(fd_control, EM8300_IOCTL_FLUSH, &ioval);
  ioval = EM8300_SUBDEVICE_AUDIO;
  ioctl(fd_control, EM8300_IOCTL_FLUSH, &ioval);

  /* Sync the video device to make sure the buffers are empty
   * and set the playback speed to normal. Also reset the
   * em8300 internal clock.
   */
  fsync(fd_video);
  ioval = 0x900;
  ioctl(fd_control, EM8300_IOCTL_SCR_SETSPEED, &ioval);

  // lets see if the dxr3 is set to ntsc
  bool ntsc = false;

  if (conf->p_tv_mode().find("-n") != std::string::npos)
    ntsc = true;

  mpeg_init(ntsc);

  initialized = 1; 

  // LOCK dxr3 so we can output things to it.
  lock();
}
