/*
   track.c - Implements the Track API
   See README for Copyright and License
*/

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include "lfm_helper.h"

void LASTFM_free_track_info(LASTFM_TRACK_INFO *a){
	if(!a)return;
	if(a->name)free(a->name);
	if(a->artist)free(a->artist);
	if(a->album)free(a->album);
	free(a);
	return;
}

static void free_LASTFM_TRACK_INFO(LASTFM_TRACK_INFO *a, void *n){
	LASTFM_free_track_info(a);
}

LASTFM_TRACK_INFO *_new_LASTFM_TRACK_INFO(){
	LASTFM_TRACK_INFO *a;
	a = malloc(sizeof(LASTFM_TRACK_INFO));
	a->name   = NULL;
	a->artist = NULL;
	a->album  = NULL;
	a->time      = 0;
	a->playcount = 0;
	a->match     = 0;
	return a;
}

void LASTFM_free_track_info_list(LFMList *list){
	LFMList_foreach(list,(LFMFunc)free_LASTFM_TRACK_INFO,NULL);
	LFMList_free(list);
}

void LASTFM_print_track_info(FILE *out, LASTFM_TRACK_INFO *a){
	if(a == NULL) return;
	fprintf(out,"name        = %s\n",a->name);
	fprintf(out,"artist      = %s\n",a->artist);
	fprintf(out,"album       = %s\n",a->album);
	fprintf(out,"playcount   = %i\n",a->playcount);
	fprintf(out,"time        = %lu\n",a->time);
	fprintf(out,"match       = %f\n",a->match);
}

int LASTFM_track_update_now_playing(LASTFM_SESSION *s,
		char *title,char *album, char *artist,
		unsigned int length, unsigned short trackno,
		unsigned int mbtrack_id, LFMList **result){
	WebData *wpage=NULL;
	char api_sig[MD5_BUFFER];
	char *q_artist,*q_album,*q_title;
	int rv = LASTFM_STATUS_ERROR;
	XMLNode *xml = NULL, *xi = NULL,*xj = NULL;
	LFMList *out = NULL;
	LASTFM_TRACK_INFO *r;

	if(s == NULL) return LASTFM_STATUS_INVALID;

	if(  strisspace(title) ||  strisspace(artist) ){
		sprintf(s->status,"Failed: Title and Artist fields are mandatory");
		return LASTFM_STATUS_INVALID;
	}

	if( strisspace(s->session_key) ){
		sprintf(s->status,"Failed: Requires authentication");
		return LASTFM_STATUS_INVALID;
	}

	/* Do not escape params yet */
	char *temp = NULL;
	int temp_size;
	temp_size = asprintf(&temp,
		"album%sapi_key%sartist%sduration%u"
		"method%ssk%strack%strackNumber%u%s",
		album,s->api_key,artist,length,		
		"track.updatenowplaying",s->session_key,title,
		trackno,s->secret);

	if(temp_size == -1) return LASTFM_INTERNAL_ERROR;
	
	string2MD5(temp,api_sig);
	free(temp);

	q_artist =  curl_easy_escape(s->curl,artist,0);
	q_album =  curl_easy_escape(s->curl,album,0);
	q_title =  curl_easy_escape(s->curl,title,0);

	temp_size = asprintf(&temp,
		"album=%s&api_key=%s&api_sig=%s&artist=%s"
		"&duration=%u"
		"&method=%s&track=%s"
		"&trackNumber=%u&sk=%s",
		q_album,s->api_key,api_sig,q_artist,
		length,
		"track.updatenowplaying",q_title,
		trackno,s->session_key);

	curl_free(q_artist);
	curl_free(q_album);
	curl_free(q_title);

	if(temp_size == -1) return LASTFM_INTERNAL_ERROR;

	/* POST */
	wpage = lfm_helper_post_page(s->curl,s,API_ROOT,temp);
	free(temp);
		
	xml = tinycxml_parse(wpage->page);
	if(lfm_helper_get_status(s,xml)) goto done;

	rv = LASTFM_STATUS_OK;

	if(result == NULL) goto done;
	
	xi = xmlnode_get(xml, CCA{"lfm","nowplaying",NULL},NULL,NULL);

	for(;xi;xi=xi->next){
		r = _new_LASTFM_TRACK_INFO();
		LFMList_append(&out,r);

		xj = xmlnode_get(xi, CCA{"nowplaying","track",NULL},NULL,NULL);
		if(xj && xj->content)
			r->name = unescape_HTML(strdup(xj->content));
		
		xj = xmlnode_get(xi, CCA{"nowplaying","artist",NULL},NULL,NULL);
		if(xj && xj->content)
			r->artist = unescape_HTML(strdup(xj->content));

		xj = xmlnode_get(xi, CCA{"nowplaying","album",NULL},NULL,NULL);
		if(xj && xj->content)
			r->album = unescape_HTML(strdup(xj->content));

	}
	*result = out;

	done:
	s->fraction = -1;
	xmlnode_free(xml);
	lfm_helper_free_page(wpage);
	return rv;
}

int LASTFM_track_scrobble(LASTFM_SESSION *s,
		char *title, char *album, char *artist,
		time_t start_time,unsigned int length, unsigned int trackno,
		unsigned int mbtrack_id, LFMList **result){
	WebData *wpage=NULL;
	char api_sig[MD5_BUFFER];
	char *q_artist,*q_album,*q_title;
	LFMList *out = NULL;
	LASTFM_TRACK_INFO *r;
	int rv = LASTFM_STATUS_ERROR;
	XMLNode *xml,*xi,*xj;

	if(s == NULL) return LASTFM_STATUS_INVALID;

	if( strisspace(title) ||  strisspace(artist) ){
		sprintf(s->status,"Failed: Title and Artist fields are mandatory");
		return LASTFM_STATUS_INVALID;
	}

	if( start_time == 0){
		sprintf(s->status,"Failed: Start Time is mandatory");
		return LASTFM_STATUS_INVALID;
	}

	if( strisspace(s->session_key) ){
		sprintf(s->status,"Failed: Requires authentication");
		return LASTFM_STATUS_INVALID;
	}

	/* Signiture requires raw params */
	char *temp = NULL;
	int temp_size;
	temp_size = asprintf(&temp,
		"album%sapi_key%sartist%sduration%u"
		"method%ssk%stimestamp%lutrack%strackNumber%u%s",
		album,s->api_key,artist,length,		
		"track.scrobble",s->session_key,start_time,title,
		trackno,s->secret);

	if(temp_size == -1) return LASTFM_INTERNAL_ERROR;
	
	string2MD5(temp,api_sig);
	free(temp);

	q_artist =  curl_easy_escape(s->curl,artist,0);
	q_album  =  curl_easy_escape(s->curl,album,0);
	q_title  =  curl_easy_escape(s->curl,title,0);

	temp_size = asprintf(&temp,
		"album=%s&api_key=%s&api_sig=%s&artist=%s"
		"&duration=%u"
		"&method=track.scrobble&timestamp=%lu&track=%s"
		"&trackNumber=%u&sk=%s",
		q_album,s->api_key,api_sig,q_artist,
		length,
		start_time,q_title,
		trackno,s->session_key);

	curl_free(q_artist);
	curl_free(q_album);
	curl_free(q_title);

	if(temp_size == -1) return LASTFM_INTERNAL_ERROR;

	/* POST */
	wpage = lfm_helper_post_page(s->curl,s,API_ROOT,temp);
	free(temp);

	xml = tinycxml_parse(wpage->page);
	if(lfm_helper_get_status(s,xml)) goto done;

	rv = LASTFM_STATUS_OK;

	if(result == NULL) goto done;
	
	xi = xmlnode_get(xml, CCA{"lfm","scrobbles","scrobble",NULL},NULL,NULL);

	for(;xi;xi=xi->next){
		r = _new_LASTFM_TRACK_INFO();
		LFMList_append(&out,r);

		xj = xmlnode_get(xi, CCA{"scrobble","track",NULL},NULL,NULL);
		if(xj && xj->content)
			r->name = unescape_HTML(strdup(xj->content));
		
		xj = xmlnode_get(xi, CCA{"scrobble","artist",NULL},NULL,NULL);
		if(xj && xj->content)
			r->artist = unescape_HTML(strdup(xj->content));

		xj = xmlnode_get(xi, CCA{"scrobble","album",NULL},NULL,NULL);
		if(xj && xj->content)
			r->album = unescape_HTML(strdup(xj->content));

	}
	*result = out;

	done:
	s->fraction = -1;
	xmlnode_free(xml);
	lfm_helper_free_page(wpage);
	return rv;
}

int LASTFM_track_get_correction(LASTFM_SESSION *s, char *artist, char *track, 
							LFMList **result){
	
	WebData *wpage=NULL;
	LFMList *out = NULL;
	int rv = LASTFM_STATUS_ERROR;
	XMLNode *xml = NULL,*xi = NULL,*xj = NULL;
	char *q_track = NULL, *q_artist = NULL;
	char *buffer = NULL;
	LASTFM_TRACK_INFO *t = NULL;


	if(s == NULL) return LASTFM_STATUS_INVALID;

	if( strisspace(track) ||  strisspace(artist) ){
		sprintf(s->status,"Failed: Title and Artist fields are mandatory");
		return LASTFM_STATUS_INVALID;
	}

	q_track  = curl_easy_escape(s->curl,track,0);
	q_artist = curl_easy_escape(s->curl,artist,0);

	buffer = malloc(LARGE_BUFFER);

	snprintf(buffer,LARGE_BUFFER,
		"%s?method=track.getcorrection"
		"&api_key=%s&artist=%s&track=%s",
		API_ROOT,s->api_key,q_artist,q_track);

	curl_free(q_artist);
	curl_free(q_track);

	wpage = lfm_helper_get_page(buffer,s);
	free(buffer);

	xml = tinycxml_parse(wpage->page);
	if(lfm_helper_get_status(s,xml))goto done;

	rv = LASTFM_STATUS_OK;

	xi = xmlnode_get(xml, CCA { "lfm","corrections","correction",NULL },NULL,NULL);

	for(;xi;xi=xi->next){
		t = _new_LASTFM_TRACK_INFO();
		LFMList_append(&out,t);
		
		xj = xmlnode_get(xi,CCA {"correction","track","name",NULL},NULL,NULL);
		if(xj && xj->content)
			t->name = unescape_HTML(strdup(xj->content));

		xj = xmlnode_get(xi,CCA {"correction","track","artist","name",NULL},NULL,NULL);
		if(xj && xj->content)
			t->artist = unescape_HTML(strdup(xj->content));
	}

	*result = out;

	done:
	s->fraction = -1;
	xmlnode_free(xml);
	lfm_helper_free_page(wpage);
	return rv;
}

int LASTFM_track_love(LASTFM_SESSION *s, const char *title, const char *artist){
	WebData *wpage=NULL;
	char api_sig[MD5_BUFFER];
	char *q_artist,*q_title;
	int rv;
	XMLNode *xml;
	xml = NULL;

	if(s == NULL) return LASTFM_STATUS_INVALID;

	if(strisspace(title) ||  strisspace(artist) ){
		sprintf(s->status,"Failed: Title and Artist fields are mandatory");
		return LASTFM_STATUS_INVALID;
	}

	if( strisspace(s->session_key) ){
		sprintf(s->status,"Failed: Requires authentication");
		return LASTFM_STATUS_INVALID;
	}

	/* Signiture requires raw params */
	char *temp = NULL;
	int temp_size;
	temp_size = asprintf(&temp,
		"api_key%sartist%smethod%ssk%strack%s%s",
		s->api_key,artist,"track.love",s->session_key,
		title,s->secret);

	if(temp_size == -1) return LASTFM_INTERNAL_ERROR;
	
	string2MD5(temp,api_sig);
	free(temp);

	q_artist =  curl_easy_escape(s->curl,artist,0);
	q_title =  curl_easy_escape(s->curl,title,0);

	temp_size = asprintf(&temp,
		"api_key=%s&api_sig=%s&artist=%s"
		"&method=%s&track=%s&sk=%s",
		s->api_key,api_sig,q_artist,
		"track.love",q_title,s->session_key);

	curl_free(q_artist);
	curl_free(q_title);

	/* POST */
	wpage = lfm_helper_post_page(s->curl,s,API_ROOT,temp);
	free(temp);

	xml = tinycxml_parse(wpage->page);
	if(lfm_helper_get_status(s,xml)){
		rv = LASTFM_STATUS_ERROR;
	}else{
		rv = LASTFM_STATUS_OK;	
	}
	
	s->fraction = -1;
	xmlnode_free(xml);
	lfm_helper_free_page(wpage);
	return rv;
}

int LASTFM_track_unlove(LASTFM_SESSION *s, const char *title, const char *artist){
	WebData *wpage=NULL;
	char api_sig[MD5_BUFFER];
	char *q_artist,*q_title;
	int rv;
	XMLNode *xml;
	xml = NULL;

	if(s == NULL) return LASTFM_STATUS_INVALID;

	if(strisspace(title) ||  strisspace(artist) ){
		sprintf(s->status,"Failed: Title and Artist fields are mandatory");
		return LASTFM_STATUS_INVALID;
	}

	if( strisspace(s->session_key) ){
		sprintf(s->status,"Failed: Requires authentication");
		return LASTFM_STATUS_INVALID;
	}

	char *temp = NULL;
	int temp_size;
	temp_size = asprintf(&temp,
		"api_key%sartist%smethod%ssk%strack%s%s",
		s->api_key,artist,"track.unlove",s->session_key,
		title,s->secret);
	if(temp_size == -1) return LASTFM_INTERNAL_ERROR;
	
	string2MD5(temp,api_sig);
	free(temp);

	q_artist =  curl_easy_escape(s->curl,artist,0);
	q_title =  curl_easy_escape(s->curl,title,0);

	temp_size = asprintf(&temp,
		"&api_key=%s&api_sig=%s&artist=%s"
		"&method=%s&track=%s&sk=%s",
		s->api_key,api_sig,q_artist,
		"track.unlove",q_title, s->session_key);

	curl_free(q_artist);
	curl_free(q_title);

	/* POST */
	wpage = lfm_helper_post_page(s->curl,s,API_ROOT,temp);
	free(temp);
		
	xml = tinycxml_parse(wpage->page);
	if(lfm_helper_get_status(s,xml)){
		rv = LASTFM_STATUS_ERROR;
	}else{
		rv = LASTFM_STATUS_OK;	
	}

	s->fraction = -1;
	xmlnode_free(xml);
	lfm_helper_free_page(wpage);
	return rv;
}

int LASTFM_track_get_similar(LASTFM_SESSION *s, const char *track, const char *artist,
			unsigned limit,LFMList **results){
	XMLNode *xml=NULL, *xi, *xj;
	WebData *wpage=NULL;
	LASTFM_TRACK_INFO *t = NULL;
	LFMList *out = NULL; 
	char *buffer;
	char *q_track, *q_artist;
	int rv = LASTFM_STATUS_ERROR;

	if(s == NULL) return LASTFM_STATUS_INVALID;

	if( strisspace(track) || strisspace(artist) ){
		sprintf(s->status,"Failed: Title and Artist fields are mandatory");
		return LASTFM_STATUS_INVALID;
	}

	q_track = curl_easy_escape(s->curl,track,0);
	q_artist = curl_easy_escape(s->curl,artist,0);

	buffer = malloc(LARGE_BUFFER);
	rv = snprintf(buffer,LARGE_BUFFER,
		"%s?method=track.getsimilar"
		"&api_key=%s&artist=%s&track=%s&autocorrect=1",
		API_ROOT,s->api_key,q_artist,q_track);

	curl_free(q_artist);
	curl_free(q_track);

	/* Note: There is no max limit specified in the last.fm docs
	 * http://www.last.fm/api/show?service=319 */
	if(limit){
		rv += snprintf(buffer+rv,LARGE_BUFFER-rv,"&limit=%u",limit);
	}

	wpage = lfm_helper_get_page(buffer,s);
	free(buffer);

	xml = tinycxml_parse(wpage->page);
	if(lfm_helper_get_status(s,xml))goto done;
	rv = LASTFM_STATUS_OK;

	xi = xmlnode_get(xml, CCA { "lfm","similartracks","track",NULL },NULL,NULL);

	for(;xi;xi=xi->next){
		t = _new_LASTFM_TRACK_INFO();
		LFMList_append(&out,t);
		
		xj = xmlnode_get(xi,CCA {"track","name",NULL},NULL,NULL);
		if(xj && xj->content)
			t->name = unescape_HTML(strdup(xj->content));

		xj = xmlnode_get(xi,CCA {"track","artist","name",NULL},NULL,NULL);
		if(xj && xj->content)
			t->artist = unescape_HTML(strdup(xj->content));
		
		xj = xmlnode_get(xi,CCA {"track","playcount",NULL},NULL,NULL);
		if(xj && xj->content)
			t->playcount = atoi(xj->content);

		xj = xmlnode_get(xi,CCA {"track","match",NULL},NULL,NULL);
		if(xj && xj->content)
			t->match = atof(xj->content);
	}

	done:
	s->fraction = -1;
	*results = out;
	xmlnode_free(xml);
	lfm_helper_free_page(wpage);
	return rv;
}
