/*
   lastfm.c - Main library initialisation
   See README for Copyright and License
*/

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "lfm_helper.h"

const char *LASTFM_IMAGE_SIZES[] =	
	{"original", "mega", "extralarge","large","medium","small",NULL };
	// Biggest to smallest

const char *LASTFM_PERIOD_STRINGS[] = 
	{ "7day", "3month", "6month", "12month","overall",NULL };

int VERBOSE;

void LFMList_append(LFMList **list, void *data){
	LFMList *i,*j,*node;

	node = malloc(sizeof(LFMList));
	node->next = NULL;
	node->data = data;
	
	if(*list == NULL){
		*list = node;
	}else{
		for(i=*list;i;i=i->next) j = i;
		j->next = node;
	}
}

void LFMList_prepend(LFMList **list, void *data){
	LFMList *node;

	node = malloc(sizeof(LFMList));
	node->next = NULL;
	node->data = data;

	if(*list == NULL){
		*list = node;
	}else{
		node->next = *list;
		*list = node;
	}
}

void LFMList_foreach(LFMList *list, LFMFunc func, void *udata){
	LFMList *i;
	for(i=list;i;i=i->next){
		func(i->data,udata);
	}
}

void LFMList_free(LFMList *list){
	LFMList *i,*j;
	for(i=list;i;){
		j=i->next;
		free(i);
		i = j;
	}
}

int LFM_progress_cb(void *data, double dltotal, double dlnow, 
					double ultotal, double ulnow){
	LASTFM_SESSION *s = data;
	double fraction=0;
//	printf("progress: dl=%.0f/%.0f ul=%.0f/%.0f\n",dlnow,dltotal,ulnow,ultotal);
	if( dltotal && !ultotal){
		fraction = dlnow/dltotal;		
	}else if( ultotal && !dltotal){
		fraction = ulnow/ultotal;
	}
	s->fraction = fraction; 
	return 0;
}

void LASTFM_set_verbose(int flag){
	VERBOSE = flag;
}

void LASTFM_status(LASTFM_SESSION *s, const char **status, 
					const int **error_code, 
					const char **error_text){
	if(s == NULL) return;
	if(status)
		*status = s->status;
	if(error_code)
		*error_code = &(s->error_code);
	if(error_text)
		*error_text = s->error_text;
}

double LASTFM_progress(LASTFM_SESSION *s){
	if(s == NULL) return -1;
	return s->fraction;
}


LASTFM_SESSION *LASTFM_init( const char *api_key,const char *secret)
{
	LASTFM_SESSION *session;
	VERBOSE = 0;

	session = malloc(sizeof(LASTFM_SESSION));

	strncpy(session->api_key,api_key,MD5_BUFFER-1);
	session->api_key[MD5_BUFFER-1]=0;

	strncpy(session->secret,secret,MD5_BUFFER-1);
	session->secret[MD5_BUFFER-1]=0;

	session->curl          = NULL;
	session->fraction      = -1;
	session->status[0]     = 0;
	session->error_code    = 0;
	session->error_text[0] = 0;
	session->auth_token[0] = 0;
	session->session_key[0]= 0;
	session->session_id[0] = 0;
	session->username      = NULL;
	session->playing_url   = NULL;
	session->submission_url=NULL;

	curl_global_init(CURL_GLOBAL_ALL);

	/* Setup a CURL handle */
	session->curl = curl_easy_init();
        curl_easy_setopt(session->curl,CURLOPT_COOKIEFILE," ");
        curl_easy_setopt(session->curl,CURLOPT_POST , 1 ) ;
	// Allow redirection
        curl_easy_setopt(session->curl,CURLOPT_FOLLOWLOCATION, 1); 
	curl_easy_setopt(session->curl,CURLOPT_WRITEFUNCTION, write_cb);
	
	/* progress bar */
	curl_easy_setopt(session->curl,CURLOPT_NOPROGRESS,0);
	curl_easy_setopt(session->curl,CURLOPT_PROGRESSFUNCTION,LFM_progress_cb);
	curl_easy_setopt(session->curl,CURLOPT_PROGRESSDATA,session);

	return session;
}

int LASTFM_login(LASTFM_SESSION *s, const char *user, const char *pass){
	char pass_hash[MD5_BUFFER];
	string2MD5(pass,pass_hash);

	return LASTFM_login_MD5(s,user,pass_hash);
}

int LASTFM_login_MD5(LASTFM_SESSION *s,const char *user,const char *pass_hash){
	WebData *wpage = NULL;
	XMLNode *xml = NULL,*i = NULL;
	char api_sig[MD5_BUFFER];
	char *buffer;
	
	buffer = malloc(LARGE_BUFFER);

	/* Store the password  */
	strcpy(s->password,pass_hash);

	/* Build an authToken  */
	snprintf(buffer,LARGE_BUFFER,"%s%s",user,pass_hash);
	string2MD5(buffer,s->auth_token);

	/* Store the username */
	s->username = strdup(user);
	
	/* Build an api_sig */
	snprintf(buffer,LARGE_BUFFER,
		"api_key%sauthToken%smethod%susername%s%s",
		s->api_key,
		s->auth_token,
		"auth.getmobilesession",
		s->username,
		s->secret);

	string2MD5(buffer,api_sig);
		
	/* Build the final url */
	snprintf(buffer,LARGE_BUFFER,
		"%s?method=%s&username=%s&authToken=%s&api_key=%s&api_sig=%s",
			API_ROOT,
			"auth.getmobilesession",
			s->username,
			s->auth_token,
			s->api_key,
			api_sig);

	/* Fetch the webpage */
	wpage = lfm_helper_get_page(buffer,s);	
	free(buffer);

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

	/* Get the key */
	i = xmlnode_get(xml,(const char *[]) { "lfm","session","key",NULL} , NULL,NULL);
	if(i)
		strcpy(s->session_key,i->content);

	out:
	s->fraction =-1;
	xmlnode_free(xml);
	lfm_helper_free_page(wpage);
	return (i==NULL);
}

int LASTFM_dinit(LASTFM_SESSION *s){
	if(s == NULL)return 1;

	if(s->username)free(s->username);
	if(s->submission_url)free(s->submission_url);
	if(s->playing_url)free(s->playing_url);
	if(s->curl)curl_easy_cleanup(s->curl);

	curl_global_cleanup();
	free(s);
	return 0;
}

void LASTFM_print_session(FILE *out, LASTFM_SESSION *s){
	fprintf(out,"status = %s\n",s->status);
	fprintf(out,"username = %s\n",s->username);
	fprintf(out,"api_key = %s\n",s->api_key);
	fprintf(out,"secret = %s\n",s->secret);
	fprintf(out,"auth_token = %s\n",s->auth_token);
	fprintf(out,"sk = %s\n",s->session_key);
	fprintf(out,"session_id = %s\n",s->session_id);
	fprintf(out,"Now-Playing URL = %s\n",s->playing_url);
	fprintf(out,"Submission URL = %s\n",s->submission_url);
}

