/*
 * Simple main() routine for stand-alone frontends.
 *
 *
 */

#include <termios.h>
#include <unistd.h>

#if 0
static void xine_log_cb(void *data, int section)
{
  fprintf(stderr, "xine: log section %d\n",section);
}

static void print_xine_log(xine_t *xine)
{
  int i, j;
  int logs = xine_get_log_section_count(xine);
  const char * const * names = xine_get_log_names(xine);
  for(i=0; i<logs; i++) {
    const char * const * lines = xine_get_log(xine, i);
    if(lines[0]) {
      printf("\nLOG: %s\n",names[i]);
      j=-1;
      while(lines[++j] && *lines[++j] )
	printf("  %2d: %s", j, lines[j]);
    }
  }
}
#endif

/* static data */
pthread_t kbd_thread;
struct termios tm, saved_tm;
volatile int terminate_key_pressed = 0;

void *kbd_receiver_thread(void *fe) 
{
  struct pollfd pfd;
  char ch;
  int err;

  terminate_key_pressed = 0;

  /* Set stdin to deliver keypresses without buffering whole lines */
  tcgetattr(STDIN_FILENO, &saved_tm);
  if (tcgetattr(STDIN_FILENO, &tm) == 0) {
    tm.c_iflag = 0;
    tm.c_lflag &= ~(ICANON | ECHO);
    tm.c_cc[VMIN] = 0;
    tm.c_cc[VTIME] = 0;
    tcsetattr(STDIN_FILENO, TCSANOW, &tm);
  }

  do {
    errno = 0;
    pfd.fd = STDIN_FILENO;
    pfd.events = POLLIN;
    err = poll(&pfd, 1, 250);
    if(err==1) {
      if(1 == read(STDIN_FILENO, &ch, 1)) {
	if(ch == 'q' || ch == 'Q' /*|| ch == 27*/) {
	  terminate_key_pressed = 1;
	  break;
	} else {
	  /* forward keyboard input to server */
	  uint64_t code = ch;
	  char str[64];
	  while(poll(&pfd,1,0) == 1 && read(STDIN_FILENO,&ch,1) == 1)
	    code = (code<<8) & ch;
	  snprintf(str, sizeof(str), "%016LX", code);
	  if(find_input((fe_t*)fe))
	    process_xine_keypress(((fe_t*)fe)->input, "KBD", str, 0, 0);
	}
      }
    }
    
  } while(err >= 0 || errno == EINTR);

  LOGMSG("Keyboard thread terminated");
  tcsetattr(STDIN_FILENO, TCSANOW, &saved_tm);
  pthread_exit(NULL);
  return NULL; /* never reached */
}

static char *strcatrealloc(char *dest, const char *src)
{
  int l;

  if (!src || !*src) 
    return dest;

  l = (dest ? strlen(dest) : 0) + strlen(src) + 1;
  if(dest) {
    dest = (char *)realloc(dest, l);
    strcat(dest, src);
  } else {
    dest = (char*)malloc(l);
    strcpy(dest, src);
  } 
  return dest;
}

int main(int argc, char *argv[])
{
  char *mrl = NULL, *gdrv = NULL, *adrv = NULL, *adev = NULL;
  int ftcp = 0, fudp = 0, frtp = 0;
  int fullscreen = 0, width = 720, height = 576;
  int xmajor, xminor, xsub;
  int i, err;
  frontend_t *fe = NULL;
  extern fe_creator_f fe_creator;
  char *static_post_plugins = NULL;
  void *p;

  xine_get_version(&xmajor, &xminor, &xsub);  
  printf("%s %s  (build with xine-lib %d.%d.%d, using xine-lib %d.%d.%d)\n\n",
	 strrchr(argv[0],'/')+1, FE_VERSION_STR,
	 XINE_MAJOR_VERSION, XINE_MINOR_VERSION, XINE_SUB_VERSION,
	 xmajor, xminor, xsub);

  /* Parse arguments */
  for(i=1; i<argc; i++) {
    if(!strncmp(argv[i], "--help", 6)) {
      printf("\n"
	     "Usage: %s [options] [xvdr:[udp:|tcp:|rtp:]//host:port] \n"
	     "\n"
	     "Available options:\n"
	     "   --help                       \n"
	     "   --fullscreen                 \n"
	     "   --width x                    \n"
	     "   --height x                   \n"
	     "   --lirc [devicename]          \n"
	     "   --video videodriver          \n",
	     strrchr(argv[0],'/')+1);
      printf("   --audio audiodriver[:device] \n"
	     "   --verbose                    \n"
	     "   --silent                     \n"
	     "   --syslog                     \n"
	     "   --tcp                        \n"
	     "   --udp                        \n"
	     "   --rtp                        \n"
	       "   --post name[:arg=val[,arg=val]]\n");
      exit(0);
    } else if(!strncmp(argv[i], "--fullscreen", 12)) {
      fullscreen=1;
	printf("Fullscreen mode\n");
    } else if(!strncmp(argv[i], "--verbose", 9)) {
      verbose_xine_log = 1;
      SysLogLevel = 3;
      printf("Verbose mode\n");
    } else if(!strncmp(argv[i], "--silent", 8)) {
      verbose_xine_log = 0;
      SysLogLevel = 1;
    } else if(!strncmp(argv[i], "--tcp", 5)) {
      ftcp = 1;
    } else if(!strncmp(argv[i], "--udp", 5)) {
      fudp = 1;
    } else if(!strncmp(argv[i], "--rtp", 5)) {
      frtp = 1;
    } else if(!strncmp(argv[i], "--syslog", 8)) {
      LogToSysLog = 1;
      openlog(strrchr(argv[0],'/')+1, LOG_PID|LOG_CONS, LOG_USER);
    } else if(!strncmp(argv[i], "--video", 3)) {
      if(argc > ++i) { 
	gdrv = strdup(argv[i]);
	printf("Video driver: %s\n",gdrv);
      }
    } else if(!strncmp(argv[i], "--audio", 3)) {
      if(argc > ++i) {
	adrv = strdup(argv[i]);
	adev = strchr(adrv, ':');
	if(adev)
	  *(adev++) = 0;
	printf("Audio driver: %s\n",adrv);
	if(adev)
	  printf("Audio device: %s\n",adev);
      }
    } else if(!strncmp(argv[i], "--post", 6)) {
      if(argc > ++i) {
	if(static_post_plugins)
	  strcatrealloc(static_post_plugins, ";");
	strcatrealloc(static_post_plugins, argv[i]);
      }	
    } else if(!strncmp(argv[i], "--height", 8)) {
      if(argc > ++i) height = atoi(argv[i]);
    } else if(!strncmp(argv[i], "--width", 7)) {
      if(argc > ++i) width = atoi(argv[i]);
    } else if(!strncmp(argv[i], "--lirc", 6)) {
      if(argc > i+1 && argv[i+1][0] && argv[i+1][0] != '-') 
	lirc_device_name = strdup(argv[++i]);
      else
	lirc_device_name = strdup("/dev/lircd");
      printf("LIRC device:  %s\n", lirc_device_name);
    } else {
      if(argv[i][0] != '-') {
	mrl = argv[i];
	printf("VDR Server: %s\n", mrl);
      } else {
	fprintf(stderr, "Unknown argument: %s\n", argv[i]);
      }
    }
  }

  /* check xine-lib version */
  if(!xine_check_version(1, 1, 0)) {
    fprintf(stderr,"ERROR: xine-lib is too old, require at least "
	    "xine library version 1.1.0\n");
    return 1;
  }

  /* If server address not given, try to find server automatically */
  if(!mrl || 
     !strcmp(mrl, "xvdr:") ||
     !strcmp(mrl, "xvdr:tcp:") ||
     !strcmp(mrl, "xvdr:udp:") ||
     !strcmp(mrl, "xvdr:rtp:") ||
     !strcmp(mrl, "xvdr:pipe:")) {
    char address[1024] = "";
    int port = -1;
    printf("VDR server not given, searching ...\n");
    if(search_vdr_server(&port, &address[0])) {
      printf("Found VDR server: host %s, port %d\n", address, port);
      if(mrl)
	asprintf(&mrl, "%s//%s:%d", mrl, address, port);
      else
	asprintf(&mrl, "xvdr://%s:%d", address, port);
    } else {
      printf("WARNING:\n"
	     "   MRL not given and server not found from local network.\n"
	     "   Trying to connect to default port on local host.\n");
      mrl = "xvdr://127.0.0.1";
    }
  }

  if(frtp && !strstr(mrl, "rtp:"))
    mrl = strcatrealloc("xvdr:rtp:", strchr(mrl, '/'));
  else if(fudp && !strstr(mrl, "udp:"))
    mrl = strcatrealloc("xvdr:udp:", strchr(mrl, '/'));
  else if(ftcp && !strstr(mrl, "tcp:"))
    mrl = strcatrealloc("xvdr:tcp:", strchr(mrl, '/'));

  printf("Connecting to %s ...\n", mrl);

  /* Create front-end */
  fe = (*fe_creator)();
  if(!fe) {
    printf("Error initializing frontend\n");
    return 3;
  }

  /* Initialize display */
  if(!fe->fe_display_open(fe, width, height, fullscreen, 0, 
			  "", 0, NULL, NULL, 1, 0)) {
    printf("Error opening display\n");
    fe->fe_free(fe);
    return 4;
  }

  /* Initialize xine */
  if(!fe->xine_init(fe, adrv, adev, gdrv, 250, 1, static_post_plugins)) {
    printf("Error initializing xine\n");
    fe->fe_free(fe);
    return 5;
  }

  /* Connect to VDR xineliboutput server */
  printf("Trying to connect to %s\n", mrl);
  if(!fe_xine_open(fe, mrl)) {
    /*print_xine_log(((fe_t *)fe)->xine);*/
    printf("Error opening %s\n", mrl);
    fe->fe_free(fe);
    return 6;
  }

  printf("\n\nPress q to exit\n\n");

  if(!fe->xine_play(fe)) {
    /*print_xine_log(((fe_t *)fe)->xine);*/
    /*printf("Error playing %s//%s:%s\n", argv[1], host, port);*/
    printf("Error playing %s\n", argv[1]);
    fe->fe_free(fe);
    return 7;
  }

  /* Start LIRC forwarding */
  if(lirc_device_name) {
    if ((err = pthread_create (&lirc_thread,
			       NULL, lirc_receiver_thread, 
			       (void*)fe)) != 0) {
      fprintf(stderr, "can't create new thread for lirc (%s)\n", 
	      strerror(err));
    }
  }

  /* Start keyboard listener thread */
  if ((err = pthread_create (&kbd_thread,
			     NULL, kbd_receiver_thread, 
			     (void*)fe)) != 0) {
    fprintf(stderr, "can't create new thread for lirc (%s)\n", 
	    strerror(err));
  }
   
  /* Main loop */

  sleep(2);  /* give input_vdr some time to establish connection */

  while(fe->fe_run(fe) && !fe->xine_is_finished(fe) && !terminate_key_pressed) 
    pthread_yield();

  /* Clean up */

  printf("Terminating...\n");

  if(lirc_device_name) {
    /*free(lirc_device_name);*/    
    lirc_device_name = NULL;
    if(fd_lirc >= 0)
      close(fd_lirc);
    fd_lirc = -1;
    pthread_cancel (lirc_thread);
    pthread_join (lirc_thread, &p);
  }

  pthread_cancel (kbd_thread);
  pthread_join (kbd_thread, &p);

  tcsetattr(STDIN_FILENO, TCSANOW, &saved_tm);

  fe->fe_free(fe); 
  return 0;
}
