// Last.Fm Records 3.1
 //released 2009-07-11

//Copyright 2008-2009 Jeroen Smeets
 //http://jeroensmeets.net/

 //Released under GPL license, with an additional remark:
 //If you release this code as part of your own package,
 //you have to change the API key. For more info, see
// http://www.last.fm/api/account

var lastFmRecords = (function() {

// private, reachable through public setters
var _user;
var _period = 'recenttracks';
var _count = 6;
var _styletype = ''; // can be highslide, lightbox
var _refreshmin = 3;
var _placeholder = 'lastfmrecords';
var _defaultthumb = 'http://cdn.last.fm/depth/catalogue/noimage/cover_85px.gif';
var _debug = false;
var _gmt_offset = '+1';

/////////////
// private //
/////////////

var _imgs_found = [];

// capitals to pretend these are constant
var _LASTFM_APIKEY = 'fbfa856cc3af93c43359b57921b1e64e';
var _LASTFM_WS_URL = 'http://ws.audioscrobbler.com/2.0/';

// last.fm added a default album image, and I don't like it
var _LASTFM_DEFAULTIMG = 'http://cdn.last.fm/flatness/catalogue/noimage/2/default_album_medium.png';

function _logStatus(text) {
if (_debug)
if ('undefined' != typeof console)
if ('function' == typeof console.log)
if ('object' == typeof text)
console.log(text);
else
console.log('last.fm.records: ' + text);
};

function _getLastFMData() {
var _method = false;
switch(_period) {
case 'lovedtracks':
_method = 'user.getlovedtracks';
break;
case 'topalbums':
_method = 'user.gettopalbums';
break;
case 'overall':
case '7day':
case '3month':
case '6month':
case '12month':
_method = 'user.gettopalbums&period=' + _period;
break;
default:
_method = 'user.getrecenttracks';
}
_logStatus('gettings last.fm info for period ' + _period + ' (method in last.fm api is ' + _method + ')');
jQuery.getJSON(
_LASTFM_WS_URL + '?method=' + _method + '&user=' + _user + '&api_key=' + _LASTFM_APIKEY + '&limit=50&format=json&callback=?',
lastFmRecords.processLastFmData
);
};

function _getArtistData(_artistmbid) {
// alert(_LASTFM_WS_URL + '?method=artist.getinfo&mbid=' + _artistmbid + '&api_key=' + _LASTFM_APIKEY + '&format=json');
jQuery.getJSON(
_LASTFM_WS_URL + '?method=artist.getinfo&mbid=' + _artistmbid + '&api_key=' + _LASTFM_APIKEY + '&format=json&callback=?',
lastFmRecords.processArtistData
);
};

function _errorInLastFmResponse(data) {
var _errorfound = false;
var _errormsg;
jQuery.each(data, function(tag, val) {
if ('error' == tag) {
_errorfound = true;
_errormsg = ' (' + val + ')';
}
if (_errorfound && ('message' == tag)) {
_errormsg = val + _errormsg;
}
});

if (_errorfound) {
_logStatus('last.fm reported error: ' + _errormsg);
}

return _errorfound;
 }

 function _findLargestImage(_imgarray) {
 // _imgarray is an array returned by last.fm that looks like

 // "image":[{"#text":"http:\/\/images.amazon.com\/images\/P\/B00004YYTW.02._SCMZZZZZZZ_.jpg","size":"small"},
 // {"#text":"http:\/\/images.amazon.com\/images\/P\/B00004YYTW.02._SCMZZZZZZZ_.jpg","size":"medium"},
 // {"#text":"http:\/\/images.amazon.com\/images\/P\/B00004YYTW.02._SCMZZZZZZZ_.jpg","size":"large"}
 // ]

 _biggestYet = false;

 jQuery.each(_imgarray, function(j, _img) {
 if ('large' == _img.size) {
 _biggestYet = _img['#text'];
 // biggest found, get out of this loop
 return false;
 } else if ('medium' == _img.size) {
 _biggestYet = _img['#text'];
 } else if (('small' == _img.size) && ('' == _biggestYet)) {
 _biggestYet = _img['#text'];
 }
 });

 return (_LASTFM_DEFAULTIMG == _biggestYet) ? false : _biggestYet;
 }

 function _processLastFmData(data) {
 // error in response?
 if (_errorInLastFmResponse(data)) {
 return false;
 }

 // get the cd data from the json
 switch(_period) {
 case 'recenttracks':
 data = data.recenttracks.track;
 break;
 case 'lovedtracks':
 data = data.lovedtracks.track;
 break;
 default:
 data = data.topalbums.album;
 }

 if (!data) {
 _logStatus('No return data from Last.fm');
 return false;
 }

 // loop through tracks
 // jQuery('track', data).each( function(key) {
 jQuery.each(data, function(i, _json) {
 if (i > _count) {
 return false;
 }
 var track = [];
 track.cdcover = _json.image ? _findLargestImage(_json.image) : false;
 track.artistname = _json.artist['#text'] || _json.artist.name;
 track.artistmbid = _json.artist['mbid'];
 track.name = _json.name;
 track.mbid = _json.mbid;
 track.url = _json.url;
 if ('recenttracks' == _period) {
 if ('true' == _json.nowplaying) {
 track.time = 'listening now';
 } else {
 //track.time = _getTimeAgo(_json.date['#text'], _gmt_offset);
 }
 } else {
 track.time = '';
 }

 _showCover(i, track);
 });

 if (_refreshmin > 0) {
 setTimeout('lastFmRecords.refreshCovers();', _refreshmin * 60000);
 }
 };

 function _showCover(_id, _track) {
 // store last.fm data about this track in (well, near, thanks to jQuery) the image
 jQuery.each(_track, function(tag, val) {
 jQuery('#lastfmcover' + _id).data(tag, val);
 });

 // always set title of image
 var _title = _track.name + ' by ' + _track.artistname;
 if ('' != _track.time) {

 }
 jQuery('#lastfmcover' + _id).attr('title', _title);
 if ('' == _track.cdcover) {
 // no cover for cd, do we have an image for the artist?
 if (_imgs_found[_track.artistmbid] && ('*' != _imgs_found[_track.artistmbid])) {
 // yes, use that url
 jQuery('#lastfmcover' + _id).attr('src', _imgs_found[_track.artistmbid]);
 } else {
 // nope, let's ask last.fm.
 if ('*' != _imgs_found[_track.artistmbid]) {
 _logStatus('cover for ' + _track.name + ' not found, trying to find image of artist ' + _track.artistname);
 // Setting a star to know we're already looking for this one
 _imgs_found[_track.artistmbid] = '*';
 _getArtistData(_track.artistmbid);
 }

 jQuery('#lastfmcover' + _id).attr('src', _defaultthumb);
 jQuery('#lastfmcover' + _id).addClass(_track.artistmbid);

 }
 } else {
 // point src and href of parent a to the image
 // and make link clickable
 jQuery('#lastfmcover' + _id).attr('src', _track.cdcover).parent('a').attr('href', _track.url).unbind('click', lastFmRecords.dontFollowLink);
 }
 };

 function _processArtistData(data) {
 // error in response?
 if (_errorInLastFmResponse(data)) {
 return false;
 }

 // data = data.artist;
 jQuery.each(data, function(i, _json) {
 _imgurl = _findLargestImage(_json.image);
 _mbid = _json.mbid;
 // find images that need to be changed
 jQuery('.' + _mbid).each( function() {
 // point src and href of parent a to the image
 // and make link clickable
 jQuery(this).attr('src', _imgurl).removeClass(_mbid).parent('a').attr('href', _json.url).unbind('click', lastFmRecords.dontFollowLink);
 });

 // remember we have an url for this artist
 _imgs_found[_mbid] = _imgurl;

 // stop looping
 return false;
 });
 };

 // this code is just too complex, I know. Suggestions?
 function _getTimeAgo(_t, gmt_offset) {
 // difference between then and now
 var _diff = new Date() - new Date(_t);
 // take into account the timezone difference
 _diff = _diff - (gmt_offset * 60000 * 60);

 var _d = [];
 // how many years in the difference? not many, I hope ;-)
 _d.ye = parseInt(_diff / (1000 * 60 * 60 * 24 * 365));
 _d.da = parseInt(_diff / (1000 * 60 * 60 * 24)) - (_d.ye * 365);
 _d.ho = parseInt(_diff / (1000 * 60 * 60)) - (_d.ye * 365 * 24) - (_d.da * 24);
 _d.mi = parseInt(_diff / (1000 * 60)) - (_d.ye * 365 * 24 * 60) - (_d.da * 24 * 60) - (_d.ho * 60);

 var _meantime = [];
 if (_d.ye > 0) { _meantime.push(_d.ye + ' year' + _getPluralS(_d.ye)); }
 if (_d.da > 0) { _meantime.push(_d.da + ' day' + _getPluralS(_d.da)); }
 if (_d.ho > 0) { _meantime.push(_d.ho + ' hour' + _getPluralS(_d.ho)); }
 if (_d.mi > 0) { _meantime.push(_d.mi + ' minute' + _getPluralS(_d.mi)) };

 // TODO: replace last comma with 'and'
 //return _meantime.join(', ') + ' ago';
 };

 function _getPluralS(_c) {
 return (1 == _c) ? '' : 's';
 }

 ////////////
 // public //
 ////////////

 return {

 addStyle: function(styletype) {
 _logStatus('function addStyle not supported yet');
 },

 setUser: function(orUsername) {
 // TODO: validation
 _user = orUsername;
 },

 setPeriod: function(orPeriod) {
 // TODO: just todo ;-)
 _period = orPeriod;
 },

 setCount: function(orCount) {
 var _pI = parseInt(orCount);
 if (_pI > 0) {
 _count = _pI;
 }
 },

 setStyle: function(orStyle) {
 // TODO: validation
 _styletype = orStyle;
 },

 setPlaceholder: function(orPlaceholder) {
 // TODO: validate
 _placeholder = orPlaceholder;
 },

 setDefaultThumb: function(orDefaultThumb) {
 // TODO: validate
 _defaultthumb = orDefaultThumb;
 },

 setRefreshMinutes: function(orRefresh) {
 var _pI = parseInt(orRefresh);
 if (_pI > 0) {
 _refreshmin = _pI;
 }
 },

 setTimeOffset: function(orOffset) {
 _gmt_offset = parseInt(orOffset);
 },

 debug: function() {
 _debug = true;
 },

 dontFollowLink: function() {
 // made it a function so I can unbind it
 return false;
 },

 init: function(_settings) {
 _logStatus('initializing');

 if (_settings.placeholder) { this.setPlaceholder(_settings.placeholder); }
 if (jQuery("div#" + _placeholder).length < 1) {
 _logStatus('error: placeholder for cd covers not found');
 return false;
 }

 if (_settings.username) { this.setUser(_settings.username) }
 if (_settings.period) { this.setPeriod(_settings.period); }
 if (_settings.defaultthumb) { this.setDefaultThumb(_settings.defaultthumb); }
 if (_settings.count) { this.setCount(_settings.count); }
 if (_settings.refresh) { this.setRefreshMinutes(_settings.refresh); }
 if (_settings.offset) { this.setTimeOffset(_settings.offset); }
 if (_settings.styletype) { this.setStyle(_settings.styletype); }

 // no need to refresh when period isn't Recent tracks
 if ('recenttracks' != _period) {
 _refreshmin = 0;
 }

 // add an ul to placeholder div
 var _ol = jQuery("<ol></ol>").appendTo("div#" + _placeholder);
 if (!_ol) {
 _logStatus('error: placeholder for cd covers not found');
 }

 // add temporary cd covers
 _logStatus('adding temporary cd covers');
 var _img, _li;
 for (var i = 0; i < _count; i++) {
 _li = jQuery('<li></li>');

 _a = jQuery('<a></a>').bind('click', lastFmRecords.dontFollowLink).attr('href', '').appendTo(_li);
 // highslide?
 if ('highslide' == _styletype) {
 _a.click( function() { return hs.expand(this); });
 }

 if ('lightbox' == _styletype) {
 _a.attr('rel', 'lightbox');
 }

 _img = jQuery('<img></img>').attr('src', _defaultthumb).attr('id', 'lastfmcover' + i).appendTo(_a);
 _em = jQuery('<em class="overlay"></em>').appendTo(_a);
 _li.appendTo(_ol);
 }

 _getLastFMData();
 },

 refreshCovers: function() {
 _logStatus('Checking to see if there\'s anything new in your list.');
 _getLastFMData();
 },

 processLastFmData: function(data) {
 // handle it internally
 _processLastFmData(data);
 },

 processArtistData: function(data) {
 // handle it internally
 _processArtistData(data);
 }

 };

})();