/*
 * XFCE plugin for the MOC player
 * 
 * Control the MOC (Media On Console) player from the XFCE panel!
 * 
 * Author: Jakub Krauz
 * E-mail: jakub.krauz@volny.cz
 * Univerzity of West Bohemia
 * Department of Computer Science and Engineering
 * Pilsen, 2012
 */

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>

#include "client.h"
#include "protocol.h"
#include "logger.h"



#define SOCKET_NAME "~/.moc/socket2"   // name of the moc-server socket file


/* Function prototypes */
static char* socket_name();
static int server_connect();


/**
 * Sends a command to the moc server.
 * The command is an integer value according to the defined protocol (see protocol.h).
 * @param command Command (integer value) to be send.
 * @return 0 on succes, value bigger than 0 on error
 */
int send_command(moc_command command)
{
  int server_sock;
  int response;

  server_sock = server_connect();  // connect the moc server
  if (server_sock == -1)
  {
    logit(ERR, "Cannot connect the moc server.");
    return 1;
  }
  if (!ping_server(server_sock))  // ping the server
  {
    logit(ERR, "The moc server was connected, but it does not response to ping.");
    return 2;
  }
  else
    logit(DBG, "Connection to moc server: OK");

  /* send the moc server the requested command */
  switch (command)
  {
    case MOC_PLAY:
      logit(DBG, "command: play");
      send_int(server_sock, CMD_GET_STATE);
      response = get_data_int(server_sock);
      if (response == STATE_STOP)
      {  // moc seems to need CMD_PLAY twice if stopped, don't know why
        send_int(server_sock, CMD_PLAY);
        send_int(server_sock, CMD_PLAY);
      }
      else if (response == STATE_PAUSE)
      {
        send_int(server_sock, CMD_UNPAUSE);
      }
      break;
    case MOC_STOP:
      logit(DBG, "command: stop");
      send_int(server_sock, CMD_STOP);
      break;
    case MOC_PAUSE:
      logit(DBG, "command: pause");
      send_int(server_sock, CMD_PAUSE);
      break;
    case MOC_NEXT:
      logit(DBG, "command: next");
      send_int(server_sock, CMD_NEXT);
      break;
    case MOC_PREV:
      logit(DBG, "command: previous");
      send_int(server_sock, CMD_PREV);
      break;
  }

  close(server_sock);
  return 0;
}


/**
 * Determines the name of the socket file.
 * The string is not malloced so there is no need to free it after calling this function. 
 * @return Name of the socket file.
 */
static char *socket_name()
{
  char *home_dir;
  char *socket_name;
  static char fname[PATH_MAX];

  socket_name = SOCKET_NAME;
  home_dir = getenv("HOME");
  if (home_dir)
    snprintf(fname, sizeof (fname), "%s/%s", home_dir, socket_name + 2);
  else
    snprintf(fname, sizeof (fname), "%s", socket_name);
  logit(DBG, "Using socket name: %s", fname);

  return fname;
}


/**
 * Connect to the mocp server.
 * @return Socket fd on succes, -1 on error.
 */
static int server_connect()
{
  struct sockaddr_un sock_name;
  int sock;

  if ((sock = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
    return -1;
  sock_name.sun_family = AF_LOCAL;
  strcpy(sock_name.sun_path, socket_name());
  if (connect(sock, (struct sockaddr *) &sock_name, SUN_LEN(&sock_name)) == -1)
  {
    close(sock);
    return -1;
  }

  return sock;
}
