'use strict';

var xml2js = require('xml2js');
var _ = require('lodash');
var ApiParseError = require('./errors').ApiParseError;
var ApiError = require('./errors').ApiError;
var OAuthError = require('./errors').OAuthError;
var cleaners = require('./cleaners');
var collectionPaths = [

NB: the outermost item to be arrayified must come first

	'artists.artist',
	'chart.chartItem',
	'chart.chartItem.release.download.packages.package',
	'chart.chartItem.release.download.packages.package.formats.format',
	'chart.chartItem.track.download.packages.package',
	'chart.chartItem.track.download.packages.package.formats.format',
	'releases.release',
	'releases.release.download.packages.package',
	'releases.release.download.packages.package.formats.format',
	'searchResults.searchResult',
	'searchResults.searchResult.release.download.packages.package',
	'searchResults.searchResult.release.download.packages.package.formats.format',
	'searchResults.searchResult.track.download.packages.package',
	'searchResults.searchResult.track.download.packages.package.formats.format',
	'recommendations.recommendedItem',
	'recommendations.recommendedItem.release.download.packages.package',
	'recommendations.recommendedItem.release.download.packages.package.formats.format',
	'tags.tag',
	'tracks.track',
	'tracks.track.download.packages.package',
	'tracks.track.download.packages.package.formats.format',
	'track.download.packages.package',
	'track.download.packages.package.formats.format',
	'taggedResults.taggedItem',
	'taggedResults.taggedItem.release.download.packages.package',
	'taggedResults.taggedItem.release.download.packages.package.formats.format',
	'cardTypes.cardType',
	'locker.lockerReleases.lockerRelease',
	'locker.lockerReleases.lockerRelease.lockerTracks.lockerTrack',
	'locker.lockerReleases.lockerRelease.lockerTracks.lockerTrack.downloadUrls.downloadUrl',
	'release.formats.format',
	'release.download.packages.package',
	'release.download.packages.package.formats.format',
	'list.listItems.listItem',
	'list.listItems.listItem.release.download.packages.package',
	'list.listItems.listItem.release.download.packages.package.formats.format',
	'basket.basketItems.basketItem',
	'cards.card'
];

Callback for parsing the XML response return from the API and converting it to JSON and handing control back to the caller.

function parse(response, opts, callback) {
	var parser, jsonParseError, result;

	if (opts.format.toUpperCase() === 'XML') {
		callback(null, response);
		return;
	}

	if (opts.contentType && opts.contentType.indexOf('json') >= 0) {
		try {
			result = JSON.parse(response);
		} catch (e) {
			jsonParseError = e;
		}
		return validateAndCleanResponse(jsonParseError, { response: result });
	}

	parser = new xml2js.Parser({
		mergeAttrs: true,
		explicitArray: false
	});

	parser.parseString(response, validateAndCleanResponse);
	function validateAndCleanResponse(err, result) {
		var cleanedResult;
		var clean, error, apiError;

		function makeParseErr(msg) {
			return new ApiParseError(msg + ' from: ' + opts.url, response);
		}

Unparsable response text

		if (err) {
			return callback(makeParseErr('Unparsable api response'));
		}
		if (!result) {
			return callback(makeParseErr('Empty response'));
		}
		if (!result.response) {
			return callback(makeParseErr('Missing response node'));
		}

Reponse was a 7digital API error object

		if (result.response.status === 'error') {
			error = result.response.error;
			if (/oauth/i.test(error.errorMessage)) {
				return callback(new OAuthError(error,
					error.errorMessage + ': ' + opts.url));
			}

			apiError = new ApiError(error, error.errorMessage + ': '
				+ opts.url);
			apiError.params = opts.params;

			return callback(apiError);
		} else if (result.response.status !== 'ok') {
			return callback(new ApiParseError(
				'Unexpected response status from: ' + opts.url, response));
		}

		clean = _.compose(
			cleaners.renameCardTypes,
			cleaners.ensureCollections.bind(null, collectionPaths),
			cleaners.removeXmlNamespaceKeys,
			cleaners.nullifyNils);

		cleanedResult = clean(result.response);
		return callback(null, cleanedResult);
	}
}

module.exports.parse = parse;
h