///
import utils = require('./Utils');
import context = require('./Context');
import request = require('./http/Request');
import response = require('./http/Response');
export class Helper {
protected defaultProperty:string = 'id';
protected context:context.Context;
protected utils:utils.Utils;
constructor(context:context.Context) {
this.context = context;
this.utils = utils.$get(context);
}
getContext() {
return this.context;
}
createUrl(options?:any, id?:string) {
return '';
}
getId(object:IHelperObject) {
return object && object[this.defaultProperty];
}
isNew(object:IHelperObject) {
return !this.getId(object) || !this.getUri(object);
}
resetAsNew(object:IHelperObject) {
if (object) {
delete object.id;
delete object.uri;
}
return object;
}
getUri(object:IHelperObject) {
return object && object.uri;
}
parseMultipartResponse(ajax:response.Response) {
if (ajax.isMultipart()) {
// ajax.data has full array, leave only successful
return ajax.data.filter((result) => {
return (!result.error);
}).map((result:response.Response) => {
return result.data;
});
} else { // Single ID
return [ajax.data];
}
}
/**
* Options have higher priority, if object.url and options.url were provided, options.url will be returned
* If no URL was provided, default will be returned
*/
loadRequest(object?, options?:request.IAjaxOptions):request.IAjaxOptions {
return this.utils.extend(options || {}, {
url: (options && options.url) || (object && this.getUri(object)) || this.createUrl(),
method: (options && options.method) || 'GET'
});
}
/**
* Options have higher priority, if object.url and options.url were provided, options.url will be returned
* If no URL was provided, default will be returned
*/
saveRequest(object?, options?:request.IAjaxOptions):request.IAjaxOptions {
if (!object && !(options && (options.post || options.body))) throw new Error('No Object');
return this.utils.extend(options || {}, {
method: (options && options.method) || (this.isNew(object) ? 'POST' : 'PUT'),
url: (options && options.url) || this.getUri(object) || this.createUrl(),
body: (options && (options.body || options.post)) || object
});
}
/**
* Options have higher priority, if object.url and options.url were provided, options.url will be returned
* If no URL was provided exception will be thrown
*/
deleteRequest(object?, options?:request.IAjaxOptions):request.IAjaxOptions {
options = options || {};
if (!this.getUri(object) && !(options && options.url)) throw new Error('Object has to be not new or URL must be provided');
return this.utils.extend(options || {}, {
method: (options && options.method) || 'DELETE',
url: (options && options.url) || this.getUri(object)
});
}
/**
* If no url was provided, default SYNC url will be returned
*/
syncRequest(options?:request.IAjaxOptions):request.IAjaxOptions {
options = options || {};
options.url = options.url || this.createUrl({sync: true});
options.query = options.query || options.get || {};
if (!!options.query.syncToken) {
options.query = {
syncType: 'ISync',
syncToken: options.get.syncToken
};
} else {
options.query.syncType = 'FSync';
}
return options;
}
nextPageExists(data):boolean {
return (data && data.navigation && ('nextPage' in data.navigation));
}
/**
* array - an array to be indexed
* getIdFn - must return an ID for each array item
* gather - if true, then each index will have an array of items, that has same ID, otherwise the first indexed
* item wins
*/
index(array:IHelperObject[], getIdFn?:(obj:IHelperObject)=>string, gather?:boolean):any {
getIdFn = getIdFn || this.getId.bind(this);
array = array || [];
return array.reduce((index, item) => {
var id = getIdFn(item);
if (!id || (index[id] && !gather)) return index;
if (gather) {
if (!index[id]) index[id] = [];
index[id].push(item);
} else {
index[id] = item;
}
return index;
}, {});
}
/**
* Returns a shallow copy of merged _target_ array plus _supplement_ array
* mergeItems
* - if true, properties of _supplement_ item will be applied to _target_ item,
* - otherwise _target_ item will be replaced
*/
merge(target:IHelperObject[],
supplement:IHelperObject[],
getIdFn?:(obj:IHelperObject)=>string, mergeItems?:boolean):any {
getIdFn = getIdFn || this.getId.bind(this);
target = target || [];
supplement = supplement || [];
var supplementIndex = this.index(supplement, getIdFn),
updatedIDs = [],
result = target.map((item) => {
var id = getIdFn(item),
newItem = supplementIndex[id];
if (newItem) updatedIDs.push(id);
return newItem ? (mergeItems ? this.utils.extend(item, newItem) : newItem) : item;
});
supplement.forEach((item) => {
if (updatedIDs.indexOf(getIdFn(item)) == -1) result.push(item);
});
return result;
}
}
export function $get(context:context.Context):Helper {
return new Helper(context);
}
export interface IHelperObject {
id?:string;
uri?:string;
}