/**
 * A class for simplying resource storage
 * @memberof Spyral.Util
 * @class
 */
class Storage {

	constructor(config) {
		this.MAX_LENGTH = 950000; // keep it under 1 megabyte
	}
	
	/**
	 * Store a resource
	 * @name Spyral.Util.Storage.storeResource
	 * @function
	 * @static
	 * @param {String} id 
	 * @param {*} data 
	 * @returns {Promise}
	 */
	static storeResource(id, data) {
		var dataString = JSON.stringify(data);
		
		if (dataString.length > this.MAX_LENGTH) {
			// split into chunks
			var promise = new Promise(function(resolve, reject) {
				var numChunks = Math.ceil(dataString.length / this.MAX_LENGTH);
			
				var chunkIds = [];
				for (var i = 0; i < numChunks; i++) {
					chunkIds.push(id+'-chunk'+i);
				}
				this._doStore(id+'-hasChunks', JSON.stringify(chunkIds)).then(function() {
					var chunkCount = 0;
					var currIndex = 0;
					for (var i = 0; i < numChunks; i++) {
						var chunkString = dataString.substr(currIndex, this.MAX_LENGTH);
						
						this._doStore(chunkIds[i], chunkString).then(function() {
							chunkCount++;
							if (chunkCount == numChunks) {
								resolve();
							}
						}, function() {
							reject();
						});
						
						currIndex += this.MAX_LENGTH;
					}
				}.bind(this), function() {
					reject();
				});
			}.bind(this));
			
			return promise;
		} else {
			return this._doStore(id, dataString);
		}
	}

	/**
	 * Get the URL for trombone
	 * @name Spyral.Util.Storage.getTromboneUrl
	 * @function
	 * @static
	 * @returns {String}
	 */
	static getTromboneUrl() {
		return Voyant.application.getTromboneUrl();
	}
	
	static _doStore(id, dataString) {
		return fetch(this.getTromboneUrl(), {
			method: 'GET',
			body: {
                tool: 'resource.StoredResource',
                resourceId: id,
                storeResource: dataString
            }
		});
	}
	
	/**
	 * Get a stored resource
	 * @name Spyral.Util.Storage.getStoredResource
	 * @function
	 * @static
	 * @param {String} id 
	 * @returns {Promise}
	 */
	static getStoredResource(id) {
		return fetch(this.getTromboneUrl(), {
			method: 'GET',
			body: {
                tool: 'resource.StoredResource',
                verifyResourceId: id+'-hasChunks'
            }
		}).then(function(response) {
			if (response.ok) {
				response.json().then(json => {
					if (json && json.storedResource && json.storedResource.id && json.storedResource.id !== '') {
						// chunks
						this._doGetStored(json.storedResource.id, false).then(function(chunkIds) {
							var fullData = '';
							var dataChunks = {};
							for (var i = 0; i < chunkIds.length; i++) {
								this._doGetStored(chunkIds[i], true).then(function(response) {
									var chunkId = response[0];
									var value = response[1];
									dataChunks[chunkId] = value;
									
									var done = true;
									for (var j = chunkIds.length-1; j >= 0; j--) {
										if (dataChunks[chunkIds[j]] === undefined) {
											done = false;
											break;
										}
									}
									
									if (done) {
										for (var j = 0; j < chunkIds.length; j++) {
											fullData += dataChunks[chunkIds[j]];
										}
										return fullData;
									}
								}, function(err) {
									throw Error('Storage: '+err)
								});
							}
						}, function(err) {
							throw Error('Storage: '+err)
						});
					} else {
						// no chunks
						return this._doGetStored(id, false).then(function(value) {
							return value
						}, function(err) {
							throw Error('Storage: '+err)
						});
					}
				});
			} else {

			}
		});
	}
	
	static _doGetStored(id, isChunk) {
		return fetch(this.getTromboneUrl(), {
			method: 'GET',
			body: {
                tool: 'resource.StoredResource',
                retrieveResourceId: id,
                failQuietly: true
            }
		}).then(function(response) {
			if (response.ok) {
				response.json().then(json => {
					var id = json.storedResource.id;
					var value = json.storedResource.resource;
					if (value.length == 0) {
						throw Error('Storage: stored file is empty')
					} else {
						if (isChunk !== true) {
							// value = JSON.parse(value);
							return value;
						} else {
							return [id, value];
						}
					}
				})
			}
		});
	}
}

export default Storage