var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promise, generator) {
    return new Promise(function (resolve, reject) {
        generator = generator.call(thisArg, _arguments);
        function cast(value) { return value instanceof Promise && value.constructor === Promise ? value : new Promise(function (resolve) { resolve(value); }); }
        function onfulfill(value) { try { step("next", value); } catch (e) { reject(e); } }
        function onreject(value) { try { step("throw", value); } catch (e) { reject(e); } }
        function step(verb, value) {
            var result = generator[verb](value);
            result.done ? resolve(result.value) : cast(result.value).then(onfulfill, onreject);
        }
        step("next", void 0);
    });
};
import { Api } from '../../api';
import { Util } from '../../util/util';
export class JsonApi extends Api {
    constructor() {
        super();
        this.entities = {};
        this.collections = {};
        this.nodes = {};
        this.resources = {};
        this.views = {};
        this.cache = false;
        this.headers = {
            'Accept': 'application/vnd.api+json',
            'Content-Type': 'application/vnd.api+json'
        };
    }
    post(path, object) {
        return __awaiter(this, void 0, Promise, function* () {
            this.headers['Authorization'] = 'Basic ' + jDrupal.settings.auth_hash;
            this.headers['X-CSRF-Token'] = jDrupal.settings.user_csrf_token;
            this.headers['Content-Type'] = 'application/vnd.api+json';
            yield fetch(`${this.baseUrl}${path}`, {
                headers: this.headers,
                method: 'POST',
                body: JSON.stringify(object)
            });
        });
    }
    patch(path, id, object) {
        return __awaiter(this, void 0, Promise, function* () {
            this.headers['Authorization'] = 'Basic ' + jDrupal.settings.auth_hash;
            this.headers['X-CSRF-Token'] = jDrupal.settings.user_csrf_token;
            this.headers['Content-Type'] = 'application/vnd.api+json';
            if (object.data.attributes.changed) {
                object.data.attributes.changed = undefined;
            }
            yield fetch(`${this.baseUrl}${path}/` + id, {
                headers: this.headers,
                method: 'PATCH',
                body: JSON.stringify(object)
            });
        });
    }
    // FIXME: causes php server error on drupal content admin page
    delete(path, id) {
        return __awaiter(this, void 0, Promise, function* () {
            this.headers['Authorization'] = 'Basic ' + jDrupal.settings.auth_hash;
            this.headers['X-CSRF-Token'] = jDrupal.settings.user_csrf_token;
            this.headers['Content-Type'] = 'application/vnd.api+json';
            // await fetch(`${this.baseUrl}${path}/` + id, {
            //     headers: this.headers,
            //     method: 'DELETE'
            // });
        });
    }
    getResourcesIndex(jsonapi_endpoint = 'jsonapi', language = undefined) {
        return __awaiter(this, void 0, Promise, function* () {
            const self = this;
            yield new Promise((resolve, reject) => {
                let url = self.baseUrl + 'index.php/';
                if (language) {
                    url += language + '/';
                }
                url += jsonapi_endpoint;
                fetch(url)
                    .then((response) => {
                    if (response.status >= 400) {
                        throw new Error('JsonApi: Bad resources response from server');
                    }
                    return response.json();
                })
                    .then((result) => {
                    self.resources = result;
                    self.baseUrl = result.links.self + '/';
                    Object.keys(result.links).forEach((k, i) => {
                        if (k.match('node--')
                            || k.match('menu--')
                            || k.match('comment--')
                            || k.match('file--')
                            || k.match('taxonomy_term--')
                            || k.match('node_type--')) {
                            self.collections[k] = {};
                        }
                    });
                    resolve(result);
                });
            });
        });
    }
    ;
    getCollection(collectionId, params = undefined, getRelationships = false) {
        return __awaiter(this, void 0, Promise, function* () {
            let path = collectionId.split('--')[0] + '/' + collectionId.split('--')[1];
            let collection = this.collections[collectionId] = yield this.get(path, {});
            if (getRelationships) {
                let relatedPromises = [];
                Object.keys(collection.data).forEach((k) => {
                    relatedPromises.push(this.getEntityRelationships({ data: collection.data[k] }));
                });
                for (const k in relatedPromises) {
                    yield relatedPromises[k];
                }
            }
            Object.keys(collection.data).forEach((k, i) => {
                this.entities[collection.data[k].attributes.uuid] = collection.data[k];
            });
            return collection;
        });
    }
    getCollections(collectionIds, params = undefined, getRelationships = false) {
        return __awaiter(this, void 0, Promise, function* () {
            let promises = [];
            collectionIds.forEach((id) => {
                promises.push(this.getCollection(id, params, getRelationships));
            });
            for (let k in promises) {
                yield promises[k];
            }
        });
    }
    getAllCollections(getRelationships = false, exclude = []) {
        return __awaiter(this, void 0, Promise, function* () {
            let promises = [];
            Object.keys(this.collections).forEach((k, i) => {
                let excluded = false;
                exclude.forEach((id) => {
                    if (id === k) {
                        excluded = true;
                    }
                });
                if (!excluded) {
                    promises.push(this.getCollection(k, {}, getRelationships));
                }
            });
            for (const k in promises) {
                yield promises[k];
            }
        });
    }
    getResource(url, params = undefined) {
        return __awaiter(this, void 0, Promise, function* () {
            if (params) {
                url += '?';
                Object.keys(params).forEach(key => url += key + '=' + params[key] + '&');
            }
            let resource = yield fetch(url, { headers: this.headers })
                .then((response) => {
                if (response.status >= 400) {
                    throw new Error('Bad response from server');
                }
                return response.json();
            })
                .then((data) => {
                // set entity + get relationships
                if (data.data && data.data.id) {
                    this.entities[data.data.id] = data;
                }
                // set entities array + get relationships
                if (data.data && Array.isArray(data.data)) {
                    data.data.forEach((item) => {
                        if (item.id) {
                            this.entities[item.id] = item;
                        }
                    });
                }
                return data;
            });
            return resource;
        });
    }
    getResources(urls) {
        return __awaiter(this, void 0, Promise, function* () {
            let promises = [];
            urls.forEach((url) => {
                promises.push(this.getResource(url));
            });
            for (let k in promises) {
                yield promises[k];
            }
        });
    }
    // todo:
    getEntityRelationships(entity) {
        return __awaiter(this, void 0, Promise, function* () {
            // console.log(entity);
            return yield new Promise(resolve => {
                let relationships = [];
                if (entity.data && entity.data.relationships) {
                    Object.keys(entity.data.relationships).forEach((k, i) => {
                        // todo: nodes only: check other entity relation types
                        if (k.match('field_')) {
                            relationships.push(entity.data.relationships[k]);
                        }
                    });
                }
                if (relationships.length) {
                    let urls = [];
                    relationships.forEach((relationship) => {
                        if (relationship.links && relationship.links.self) {
                            urls.push(relationship.links.related);
                        }
                    });
                    if (urls.length) {
                        this.getResources(urls).then(() => {
                            // console.log(urls);
                            resolve();
                        });
                    }
                    else {
                        resolve();
                    }
                }
                else {
                    resolve();
                }
            });
        });
    }
    getNode(id, type = undefined) {
        return __awaiter(this, void 0, Promise, function* () {
            const self = this;
            id = Util.castToType(id);
            let idField = 'uuid';
            if (typeof id === 'number') {
                idField = 'nid';
            }
            return yield new Promise(resolve => {
                let path;
                // cached node
                if (this.cache) {
                    let cachedNode;
                    Object.keys(this.entities).forEach((k) => {
                        if (this.entities[k].data && this.entities[k].data.attributes[idField] == id) {
                            cachedNode = this.entities[k];
                        }
                    });
                    if (cachedNode) {
                        resolve(cachedNode);
                        return;
                    }
                }
                // define type from node_index view
                if (this.views['node_index']) {
                    this.views['node_index'].forEach((item) => {
                        if (item[idField] == id) {
                            type = item.type;
                        }
                    });
                }
                if (type) {
                    path = 'node/' + type;
                    this.get(path + '?filter[' + idField + '][value]=' + id).then((res) => {
                        parseNodeResult(res);
                    });
                }
                else {
                    // search through all node collections
                    let nodeTypes = [];
                    Object.keys(this.collections).forEach((k) => {
                        if (k.match('node--')) {
                            nodeTypes.push(k);
                        }
                    });
                    nodeTypes.forEach((type) => {
                        let path = type.split('--')[0] + '/' + type.split('--')[1];
                        // fixme: stop further http requests after node match response
                        this.get(path + '?filter[' + idField + '][value]=' + id).then((res) => {
                            parseNodeResult(res);
                        });
                    });
                }
                function parseNodeResult(res) {
                    if (res.data.length) {
                        let node = { data: res.data[0] };
                        self.entities[res.data[0].id] = node;
                        if (!self.collections[res.data[0].type].data) {
                            self.collections[res.data[0].type].data = [];
                        }
                        // fixme: todo: check for doubles before push
                        self.collections[res.data[0].type].data.push(node);
                        // todo: deprecate, use collections + entities only
                        self.nodes[res.data[0].attributes.nid] = node;
                        // get relationships
                        if (node.data.relationships) {
                            self.getEntityRelationships(node).then(() => {
                                resolve(node);
                            });
                        }
                    }
                }
            });
        });
    }
    getNodes(ids) {
        return __awaiter(this, void 0, Promise, function* () {
            let promises = [];
            ids.forEach((id) => {
                promises.push(this.getNode(id));
            });
            for (let k in promises) {
                yield promises[k];
            }
        });
    }
    saveNode(node) {
        return __awaiter(this, void 0, Promise, function* () {
            let path = node.data.type.split('--')[0] + '/' + node.data.type.split('--')[1];
            if (!node.data.id) {
                yield this.post(path, node);
            }
            else {
                yield this.patch(path, node.data.id, node);
            }
        });
    }
    deleteNode(node) {
        return __awaiter(this, void 0, Promise, function* () {
            let path = node.data.type.split('--')[0] + '/' + node.data.type.split('--')[1];
            yield this.delete(path, node.data.id).then((arg) => {
                // fixme: todo: delete from collections + entities
                // if (this.entities[node.data.id]){
                //     this.entities[node.data.id] = undefined;
                // }
                // let collection = this.collections[node.data.type];
                // if(collection.data && collection.data.length) {
                //     collection.data.forEach((collectionNode,i) => {
                //         if(node.data.id === collectionNode.data.id){
                //             // collection.data.slice(i)
                //         }
                //     });
                // }
            });
        });
    }
    // todo: check
    getById(entity_id) {
        let entity;
        Object.keys(this.collections).forEach((k, i) => {
            if (this.collections[k]['data'] && this.collections[k]['data'].length) {
                this.collections[k]['data'].forEach((entityObject) => {
                    if (entityObject.id === entity_id) {
                        entity = entityObject;
                    }
                });
            }
        });
        if (entity) {
            return { data: entity };
        }
        // return entity;
    }
    getByNodeId(nid) {
        return __awaiter(this, void 0, Promise, function* () {
            let entity;
            Object.keys(this.collections).forEach((k, i) => {
                if (k.match('node--') && this.collections[k]['data'] && this.collections[k]['data'].length) {
                    this.collections[k]['data'].forEach((entityObject) => {
                        if (entityObject.attributes.nid == nid) {
                            entity = entityObject;
                        }
                    });
                }
            });
            if (entity) {
                return { data: entity };
            }
            else {
            }
        });
    }
    // public async entityLoad(entity_type_id: string, bundle_id: string, entity_id: any) {
    //     if(entity_type_id === 'node'){
    //         // if( typeof entity_id === 'number'){  }
    //     }
    //     // return await this.get(entity_type_id+'/'+bundle_id+'/'+entity_id);
    //     console.log(entity_type_id+'/'+bundle_id+'/'+entity_id);
    // }
    getByNid(nid, type = undefined) {
    }
}
//# sourceMappingURL=json-api.js.map