function photoUrl(photo, size) {
	return 'http://farm'+photo.farm+'.static.flickr.com/'+photo.server+'/'+photo.id+'_'+photo.secret+((size) ? '_'+size : '') +'.jpg';
}

function buddyicon(photo) {
	return 'http://farm' + photo.iconfarm +'.static.flickr.com/'+ photo.iconserver + '/buddyicons/' + photo.owner + '.jpg';
}

function flickrPhotoPage(userId, photoId) {
	return 'http://www.flickr.com/photos/'+userId+'/' + photoId;
}

function Flickr(config) {

	this.config = {base_url: 'http://api.flickr.com/services/rest/?&jsoncallback=?&format=json'};
	$.extend(this.config, config);
	var This = this;
	this.default_parms = {
			format:'json',
			api_key:this.config.api_key,
			_callback:'?'
	};
	
	this.isConsole = function() {
		return (console && console.firebug);
	}
	
	this.get = function(method, params, callback) {
		var parms =  $.extend({}, this.default_parms, {method: method}, params);
		//if (this.isConsole())
		//	console.log(parms);
		$.getJSON(this.config.base_url, parms , this.wrapCallback(callback));
	}
	
	
	this.handleFailure = function(url, response) {
		if (This.isConsole()) {
			console.warn(url, response);
		}
	}
	
	this.wrapCallback = function(callback) {
		return function(response) {
			if (response.stat=='ok') {
				callback(response);
			}
			else if (response.stat='fail') {
				This.handleFailure(this.url, response);
			}
		}
	}
	
	this.activity_userComments = function(params, callback) {
		return this.get('flickr.activity.userComments', params, callback);
	}

	this.activity_userPhotos = function(params, callback) {
		return this.get('flickr.activity.userPhotos', params, callback);
	}

	this.auth_checkToken = function(params, callback) {
		return this.get('flickr.auth.checkToken', params, callback);
	}

	this.auth_getFrob = function(params, callback) {
		return this.get('flickr.auth.getFrob', params, callback);
	}

	this.auth_getFullToken = function(params, callback) {
		return this.get('flickr.auth.getFullToken', params, callback);
	}

	this.auth_getToken = function(params, callback) {
		return this.get('flickr.auth.getToken', params, callback);
	}

	this.blogs_getList = function(params, callback) {
		return this.get('flickr.blogs.getList', params, callback);
	}

	this.blogs_postPhoto = function(params, callback) {
		return this.get('flickr.blogs.postPhoto', params, callback);
	}

	this.contacts_getList = function(params, callback) {
		return this.get('flickr.contacts.getList', params, callback);
	}

	this.contacts_getPublicList = function(params, callback) {
		return this.get('flickr.contacts.getPublicList', params, callback);
	}

	this.favorites_add = function(params, callback) {
		return this.get('flickr.favorites.add', params, callback);
	}

	this.favorites_getList = function(params, callback) {
		return this.get('flickr.favorites.getList', params, callback);
	}

	this.favorites_getPublicList = function(params, callback) {
		return this.get('flickr.favorites.getPublicList', params, callback);
	}

	this.favorites_remove = function(params, callback) {
		return this.get('flickr.favorites.remove', params, callback);
	}

	this.groups_browse = function(params, callback) {
		return this.get('flickr.groups.browse', params, callback);
	}

	this.groups_getInfo = function(params, callback) {
		return this.get('flickr.groups.getInfo', params, callback);
	}

	this.groups_search = function(params, callback) {
		return this.get('flickr.groups.search', params, callback);
	}

	this.groups_pools_add = function(params, callback) {
		return this.get('flickr.groups.pools.add', params, callback);
	}

	this.groups_pools_getContext = function(params, callback) {
		return this.get('flickr.groups.pools.getContext', params, callback);
	}

	this.groups_pools_getGroups = function(params, callback) {
		return this.get('flickr.groups.pools.getGroups', params, callback);
	}

	this.groups_pools_getPhotos = function(params, callback) {
		return this.get('flickr.groups.pools.getPhotos', params, callback);
	}

	this.groups_pools_remove = function(params, callback) {
		return this.get('flickr.groups.pools.remove', params, callback);
	}

	this.interestingness_getList = function(params, callback) {
		return this.get('flickr.interestingness.getList', params, callback);
	}

	this.people_findByEmail = function(params, callback) {
		return this.get('flickr.people.findByEmail', params, callback);
	}

	this.people_findByUsername = function(params, callback) {
		return this.get('flickr.people.findByUsername', params, callback);
	}

	this.people_getInfo = function(params, callback) {
		return this.get('flickr.people.getInfo', params, callback);
	}

	this.people_getPublicGroups = function(params, callback) {
		return this.get('flickr.people.getPublicGroups', params, callback);
	}

	this.people_getPublicPhotos = function(params, callback) {
		return this.get('flickr.people.getPublicPhotos', params, callback);
	}

	this.people_getUploadStatus = function(params, callback) {
		return this.get('flickr.people.getUploadStatus', params, callback);
	}

	this.photos_addTags = function(params, callback) {
		return this.get('flickr.photos.addTags', params, callback);
	}

	this.photos_delete = function(params, callback) {
		return this.get('flickr.photos.delete', params, callback);
	}

	this.photos_getAllContexts = function(params, callback) {
		return this.get('flickr.photos.getAllContexts', params, callback);
	}

	this.photos_getContactsPhotos = function(params, callback) {
		return this.get('flickr.photos.getContactsPhotos', params, callback);
	}

	this.photos_getContactsPublicPhotos = function(params, callback) {
		return this.get('flickr.photos.getContactsPublicPhotos', params, callback);
	}

	this.photos_getContext = function(params, callback) {
		return this.get('flickr.photos.getContext', params, callback);
	}

	this.photos_getCounts = function(params, callback) {
		return this.get('flickr.photos.getCounts', params, callback);
	}

	this.photos_getExif = function(params, callback) {
		return this.get('flickr.photos.getExif', params, callback);
	}

	this.photos_getFavorites = function(params, callback) {
		return this.get('flickr.photos.getFavorites', params, callback);
	}

	this.photos_getInfo = function(params, callback) {
		return this.get('flickr.photos.getInfo', params, callback);
	}

	this.photos_getNotInSet = function(params, callback) {
		return this.get('flickr.photos.getNotInSet', params, callback);
	}

	this.photos_getPerms = function(params, callback) {
		return this.get('flickr.photos.getPerms', params, callback);
	}

	this.photos_getRecent = function(params, callback) {
		return this.get('flickr.photos.getRecent', params, callback);
	}

	this.photos_getSizes = function(params, callback) {
		return this.get('flickr.photos.getSizes', params, callback);
	}

	this.photos_getUntagged = function(params, callback) {
		return this.get('flickr.photos.getUntagged', params, callback);
	}

	this.photos_getWithGeoData = function(params, callback) {
		return this.get('flickr.photos.getWithGeoData', params, callback);
	}

	this.photos_getWithoutGeoData = function(params, callback) {
		return this.get('flickr.photos.getWithoutGeoData', params, callback);
	}

	this.photos_recentlyUpdated = function(params, callback) {
		return this.get('flickr.photos.recentlyUpdated', params, callback);
	}

	this.photos_removeTag = function(params, callback) {
		return this.get('flickr.photos.removeTag', params, callback);
	}

	this.photos_search = function(params, callback) {
		return this.get('flickr.photos.search', params, callback);
	}

	this.photos_setContentType = function(params, callback) {
		return this.get('flickr.photos.setContentType', params, callback);
	}

	this.photos_setDates = function(params, callback) {
		return this.get('flickr.photos.setDates', params, callback);
	}

	this.photos_setMeta = function(params, callback) {
		return this.get('flickr.photos.setMeta', params, callback);
	}

	this.photos_setPerms = function(params, callback) {
		return this.get('flickr.photos.setPerms', params, callback);
	}

	this.photos_setSafetyLevel = function(params, callback) {
		return this.get('flickr.photos.setSafetyLevel', params, callback);
	}

	this.photos_setTags = function(params, callback) {
		return this.get('flickr.photos.setTags', params, callback);
	}

	this.photos_comments_addComment = function(params, callback) {
		return this.get('flickr.photos.comments.addComment', params, callback);
	}

	this.photos_comments_deleteComment = function(params, callback) {
		return this.get('flickr.photos.comments.deleteComment', params, callback);
	}

	this.photos_comments_editComment = function(params, callback) {
		return this.get('flickr.photos.comments.editComment', params, callback);
	}

	this.photos_comments_getList = function(params, callback) {
		return this.get('flickr.photos.comments.getList', params, callback);
	}

	this.photos_geo_getLocation = function(params, callback) {
		return this.get('flickr.photos.geo.getLocation', params, callback);
	}

	this.photos_geo_getPerms = function(params, callback) {
		return this.get('flickr.photos.geo.getPerms', params, callback);
	}

	this.photos_geo_removeLocation = function(params, callback) {
		return this.get('flickr.photos.geo.removeLocation', params, callback);
	}

	this.photos_geo_setLocation = function(params, callback) {
		return this.get('flickr.photos.geo.setLocation', params, callback);
	}

	this.photos_geo_setPerms = function(params, callback) {
		return this.get('flickr.photos.geo.setPerms', params, callback);
	}

	this.photos_licenses_getInfo = function(params, callback) {
		return this.get('flickr.photos.licenses.getInfo', params, callback);
	}

	this.photos_licenses_setLicense = function(params, callback) {
		return this.get('flickr.photos.licenses.setLicense', params, callback);
	}

	this.photos_notes_add = function(params, callback) {
		return this.get('flickr.photos.notes.add', params, callback);
	}

	this.photos_notes_delete = function(params, callback) {
		return this.get('flickr.photos.notes.delete', params, callback);
	}

	this.photos_notes_edit = function(params, callback) {
		return this.get('flickr.photos.notes.edit', params, callback);
	}

	this.photos_transform_rotate = function(params, callback) {
		return this.get('flickr.photos.transform.rotate', params, callback);
	}

	this.photos_upload_checkTickets = function(params, callback) {
		return this.get('flickr.photos.upload.checkTickets', params, callback);
	}

	this.photosets_addPhoto = function(params, callback) {
		return this.get('flickr.photosets.addPhoto', params, callback);
	}

	this.photosets_create = function(params, callback) {
		return this.get('flickr.photosets.create', params, callback);
	}

	this.photosets_delete = function(params, callback) {
		return this.get('flickr.photosets.delete', params, callback);
	}

	this.photosets_editMeta = function(params, callback) {
		return this.get('flickr.photosets.editMeta', params, callback);
	}

	this.photosets_editPhotos = function(params, callback) {
		return this.get('flickr.photosets.editPhotos', params, callback);
	}

	this.photosets_getContext = function(params, callback) {
		return this.get('flickr.photosets.getContext', params, callback);
	}

	this.photosets_getInfo = function(params, callback) {
		return this.get('flickr.photosets.getInfo', params, callback);
	}

	this.photosets_getList = function(params, callback) {
		return this.get('flickr.photosets.getList', params, callback);
	}

	this.photosets_getPhotos = function(params, callback) {
		return this.get('flickr.photosets.getPhotos', params, callback);
	}

	this.photosets_orderSets = function(params, callback) {
		return this.get('flickr.photosets.orderSets', params, callback);
	}

	this.photosets_removePhoto = function(params, callback) {
		return this.get('flickr.photosets.removePhoto', params, callback);
	}

	this.photosets_comments_addComment = function(params, callback) {
		return this.get('flickr.photosets.comments.addComment', params, callback);
	}

	this.photosets_comments_deleteComment = function(params, callback) {
		return this.get('flickr.photosets.comments.deleteComment', params, callback);
	}

	this.photosets_comments_editComment = function(params, callback) {
		return this.get('flickr.photosets.comments.editComment', params, callback);
	}

	this.photosets_comments_getList = function(params, callback) {
		return this.get('flickr.photosets.comments.getList', params, callback);
	}

	this.places_find = function(params, callback) {
		return this.get('flickr.places.find', params, callback);
	}

	this.places_findByLatLon = function(params, callback) {
		return this.get('flickr.places.findByLatLon', params, callback);
	}

	this.places_getChildrenWithPhotosPublic = function(params, callback) {
		return this.get('flickr.places.getChildrenWithPhotosPublic', params, callback);
	}

	this.places_getInfo = function(params, callback) {
		return this.get('flickr.places.getInfo', params, callback);
	}

	this.places_getInfoByUrl = function(params, callback) {
		return this.get('flickr.places.getInfoByUrl', params, callback);
	}

	this.places_placesForUser = function(params, callback) {
		return this.get('flickr.places.placesForUser', params, callback);
	}

	this.places_resolvePlaceId = function(params, callback) {
		return this.get('flickr.places.resolvePlaceId', params, callback);
	}

	this.places_resolvePlaceURL = function(params, callback) {
		return this.get('flickr.places.resolvePlaceURL', params, callback);
	}

	this.prefs_getContentType = function(params, callback) {
		return this.get('flickr.prefs.getContentType', params, callback);
	}

	this.prefs_getGeoPerms = function(params, callback) {
		return this.get('flickr.prefs.getGeoPerms', params, callback);
	}

	this.prefs_getHidden = function(params, callback) {
		return this.get('flickr.prefs.getHidden', params, callback);
	}

	this.prefs_getPrivacy = function(params, callback) {
		return this.get('flickr.prefs.getPrivacy', params, callback);
	}

	this.prefs_getSafetyLevel = function(params, callback) {
		return this.get('flickr.prefs.getSafetyLevel', params, callback);
	}

	this.reflection_getMethodInfo = function(params, callback) {
		return this.get('flickr.reflection.getMethodInfo', params, callback);
	}

	this.reflection_getMethods = function(params, callback) {
		return this.get('flickr.reflection.getMethods', params, callback);
	}

	this.tags_getClusterPhotos = function(params, callback) {
		return this.get('flickr.tags.getClusterPhotos', params, callback);
	}

	this.tags_getClusters = function(params, callback) {
		return this.get('flickr.tags.getClusters', params, callback);
	}

	this.tags_getHotList = function(params, callback) {
		return this.get('flickr.tags.getHotList', params, callback);
	}

	this.tags_getListPhoto = function(params, callback) {
		return this.get('flickr.tags.getListPhoto', params, callback);
	}

	this.tags_getListUser = function(params, callback) {
		return this.get('flickr.tags.getListUser', params, callback);
	}

	this.tags_getListUserPopular = function(params, callback) {
		return this.get('flickr.tags.getListUserPopular', params, callback);
	}

	this.tags_getListUserRaw = function(params, callback) {
		return this.get('flickr.tags.getListUserRaw', params, callback);
	}

	this.tags_getRelated = function(params, callback) {
		return this.get('flickr.tags.getRelated', params, callback);
	}

	this.test_echo = function(params, callback) {
		return this.get('flickr.test.echo', params, callback);
	}

	this.test_login = function(params, callback) {
		return this.get('flickr.test.login', params, callback);
	}

	this.test_null = function(params, callback) {
		return this.get('flickr.test.null', params, callback);
	}

	this.urls_getGroup = function(params, callback) {
		return this.get('flickr.urls.getGroup', params, callback);
	}

	this.urls_getUserPhotos = function(params, callback) {
		return this.get('flickr.urls.getUserPhotos', params, callback);
	}

	this.urls_getUserProfile = function(params, callback) {
		return this.get('flickr.urls.getUserProfile', params, callback);
	}

	this.urls_lookupGroup = function(params, callback) {
		return this.get('flickr.urls.lookupGroup', params, callback);
	}

	this.urls_lookupUser = function(params, callback) {
		return this.get('flickr.urls.lookupUser', params, callback);
	}
	
};

