//pointer.c:

/*
 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009-2014
 *
 *  This file is part of RoarAudio PlayList Daemon,
 *  a playlist management daemon for RoarAudio.
 *  See README for details.
 *
 *  This file is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 3
 *  as published by the Free Software Foundation.
 *
 *  RoarAudio is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this software; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 *
 */

#include "rpld.h"

enum rpld_pointertype {
 PT_GLOBAL = 0,
 PT_QUEUE,
 PT_CLIENT
};

struct rpld_pointerarray {
 const char * name;
 enum rpld_pointertype type;
 struct rpld_playlist_pointer * pointer;
};

struct rpld_pointerarray g_pointer[POINTER_NUM] = {
 {"DEFAULT",  PT_QUEUE,  NULL},
 {"CURRENT",  PT_QUEUE,  NULL},
 {"STARTUP",  PT_QUEUE,  NULL},
 {"TEMP",     PT_CLIENT, NULL},
 {"FALLBACK", PT_QUEUE,  NULL}
};

#define _chargs(ret) if ( pointer < 0 || pointer >= POINTER_NUM ) { roar_err_set(ROAR_ERROR_INVAL); return (ret); }

char *                   rpld_pointer_get_name(const int pointer, pli_t queue, const int client) {
 char * ret;
 const char * pointer_name;

 _chargs(NULL);

 pointer_name = g_pointer[pointer].name;

#define _SIZE 32

 ret = roar_mm_malloc(_SIZE);

 if ( queue == (pli_t)-1 && client == -1 ) {
  snprintf(ret, _SIZE, "%s", pointer_name);
 } else if ( queue == (pli_t)-1 ) {
  snprintf(ret, _SIZE, "%s[:%i]", pointer_name, client);
 } else if ( client == -1 ) {
  snprintf(ret, _SIZE, "%s[%i]", pointer_name, (int)queue);
 } else {
  snprintf(ret, _SIZE, "%s[%i:%i]", pointer_name, (int)queue, client);
 }

 return ret;
}

int                            rpld_pointer_parse_name(int * pointer, pli_t * queue, int * client, int client_hint, const char * name) {
 size_t i;
 size_t namelen;
 const char * client_info;

 if ( queue == NULL || pointer == NULL || client == NULL || name == NULL ) {
  roar_err_set(ROAR_ERROR_FAULT);
  return -1;
 }

 *queue   = (pli_t)-1;
 *pointer = -1;
 *client  = client_hint;

 if ( client_hint != -1 ) {
  *queue = client_get_queue(client_hint);
 }

 for (i = 0; i < POINTER_NUM; i++) {
  namelen = roar_mm_strlen(g_pointer[i].name);
  if ( !strncasecmp(g_pointer[i].name, name, namelen) ) {
   if ( name[namelen] == 0 ) {
    *pointer = i;
    return 0;
   } else if ( name[namelen] == '[' ) {
    *pointer = i;
    client_info = strstr(name + namelen + 1, ":");
    ROAR_DBG("rpld_pointer_parse_name(*): client_info=%p'%s'", client_info, client_info);
    if ( client_info != NULL )
     *client = atoi(client_info + 1);
    if ( name[namelen+1] == ':' ) {
     *queue = client_get_queue(*client);
    } else {
     *queue   = atoi(name + namelen + 1);
    }
    return 0;
   } else {
    roar_err_set(ROAR_ERROR_ILLSEQ);
    return -1;
   }
  }
 }

 roar_err_set(ROAR_ERROR_NOENT);
 return -1;
}

int                            rpld_pointer_is_set(const int pointer, pli_t queue, const int client) {
 struct rpld_playlist_pointer * plp;
 int ret;

 _chargs(-1);


 plp = rpld_pointer_get(pointer, queue, client);

 ret = plp == NULL ? 0 : 1;

 rpld_plp_unref(plp);

 return ret;
}

struct rpld_playlist_pointer * rpld_pointer_get(const int pointer, pli_t queue, const int client) {
 struct rpld_playlist_pointer * ret = NULL;

 _chargs(NULL);

 roar_err_set(ROAR_ERROR_NOTSUP);

 switch (g_pointer[pointer].type) {
  case PT_GLOBAL:
    ret = g_pointer[pointer].pointer;
    if ( ret == NULL ) {
     roar_err_set(ROAR_ERROR_NOENT);
    } else {
     rpld_plp_ref(g_pointer[pointer].pointer);
    }
   break;
  case PT_CLIENT:
    ret = client_get_pointer(client, pointer);
   break;
  case PT_QUEUE:
    ret = playback_get_pointer(queue, pointer);
   break;
 }

 return ret;
}

struct rpld_playlist_pointer * rpld_pointer_get_by_name(const char * name, int client_hint) {
 pli_t queue;
 int pointer, client;

 if ( rpld_pointer_parse_name(&pointer, &queue, &client, client_hint, name) == -1 )
  return NULL;

 return rpld_pointer_get(pointer, queue, client);
}

int                            rpld_pointer_set(const int pointer, pli_t queue, const int client, struct rpld_playlist_pointer * plp) {
 _chargs(-1);

 roar_err_set(ROAR_ERROR_NOTSUP);

 switch (g_pointer[pointer].type) {
  case PT_GLOBAL:
    if ( g_pointer[pointer].pointer != NULL ) {
     rpld_plp_unref(g_pointer[pointer].pointer);
     g_pointer[pointer].pointer = NULL;
    }

    if ( plp != NULL )
     rpld_plp_ref(plp);

    g_pointer[pointer].pointer = plp;

    return 0;
   break;
  case PT_CLIENT:
    return client_set_pointer(client, pointer, plp);
   break;
  case PT_QUEUE:
    return playback_set_pointer(queue, pointer, plp);
   break;
 }

 return -1;
}

int                            rpld_pointer_set_by_name(const char * name, int client_hint, struct rpld_playlist_pointer * plp) {
 pli_t queue;
 int pointer, client;

 if ( rpld_pointer_parse_name(&pointer, &queue, &client, client_hint, name) == -1 )
  return -1;

 return rpld_pointer_set(pointer, queue, client, plp);
}

struct rpld_playlist_entry   * rpld_pointer_search(const int pointer, pli_t queue, const int client) {
 struct rpld_playlist_pointer * plp = rpld_pointer_get(pointer, queue, client);
 struct rpld_playlist_entry   * ret;

 if ( plp == NULL )
  return NULL;

 ret = rpld_plp_search(plp);

 rpld_plp_unref(plp);

 return ret;
}

//ll
