var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { DatabaseDirectService } from './direct';
import { DatabaseServerService } from './server';
import { buildQuery, buildAdvancedFilter } from './filter';
export class DatabaseService {
    constructor(app) {
        this.app = app;
        this.DatabaseDirect = new DatabaseDirectService(this.app);
        this.DatabaseServer = new DatabaseServerService(this.app);
    }
    direct() {
        return this.DatabaseDirect;
    }
    server() {
        return this.DatabaseServer;
    }
    all(sheet, cacheTime = 0) {
        return __awaiter(this, void 0, void 0, function* () {
            let items = [];
            // first load from direct
            if (this.isDirect(sheet)) {
                try {
                    items = yield this.direct().all(sheet, cacheTime);
                }
                catch (error) {
                    // not published
                }
            }
            // load from server
            if (!items) {
                items = yield this.server().all(sheet, cacheTime);
            }
            return items;
        });
    }
    query(sheet, filter, local = true, cacheTime = 0) {
        return __awaiter(this, void 0, void 0, function* () {
            // prepare query
            let query;
            // advanced filter
            let advancedFilter;
            if (filter instanceof Function) {
                advancedFilter = filter;
            }
            else {
                query = buildQuery(filter);
            }
            // query items
            if (local) {
                // turn simple query into advanced query
                if (!advancedFilter) {
                    advancedFilter = buildAdvancedFilter(query);
                }
                // load local items
                const localItems = yield this.all(sheet, cacheTime);
                // query local items
                const items = [];
                for (let i = 0, length = localItems.length; i < length; i++) {
                    const item = localItems[i];
                    if (!!advancedFilter(item)) {
                        items.push(item);
                    }
                }
                return items;
            }
            else {
                if (!advancedFilter) {
                    return yield this.server().query(sheet, query, cacheTime);
                }
                else {
                    throw new Error('Can only apply advanced query with local data.');
                }
            }
        });
    }
    items(sheet, filter, local = true, cacheTime = 0) {
        return __awaiter(this, void 0, void 0, function* () {
            return !!filter ? this.query(sheet, filter, local, cacheTime) : this.all(sheet, cacheTime);
        });
    }
    item(sheet, finder, local = true, cacheTime = 0) {
        return __awaiter(this, void 0, void 0, function* () {
            let item = null;
            if (typeof finder === 'string' && !local) {
                item = yield this.server().item(sheet, finder, cacheTime);
            }
            else {
                // turn string into finder
                if (typeof finder === 'string') {
                    finder = { $key: finder };
                }
                // query items
                const items = yield this.query(sheet, finder, local, cacheTime);
                // extract item
                if ((items || []).length === 1) {
                    item = items[0];
                }
            }
            return item;
        });
    }
    content(contentSource, // doc url | published url
    styles = 'clean', cacheTime = 0) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.isDocsContentSourceNotDirectly(contentSource)) { // server
                return yield this.server().content(contentSource, styles, cacheTime);
            }
            else { // direct
                return yield this.direct().content(contentSource, styles, cacheTime);
            }
        });
    }
    itemAndContent(sheet, finder, item, // loaded item where not sure there is content or not
    styles = 'clean', local = true, cacheTime = 0) {
        return __awaiter(this, void 0, void 0, function* () {
            // load item
            if (!item) {
                item = yield this.item(sheet, finder, local, cacheTime);
            }
            // load content
            if (!!item &&
                !item['content'] &&
                !!item['contentSource'] &&
                this.isContentSourceFromDocs(item['contentSource'])) {
                // get content data
                const contentData = yield this.content(item['contentSource'], styles, cacheTime);
                // merge content to item
                item = Object.assign({}, item, contentData);
            }
            // return final item
            return item;
        });
    }
    set(sheet, key, data) {
        return __awaiter(this, void 0, void 0, function* () {
            return yield this.server().set(sheet, key, data);
        });
    }
    update(sheet, key, data) {
        return __awaiter(this, void 0, void 0, function* () {
            return yield this.server().update(sheet, key, data);
        });
    }
    add(sheet, key, data) {
        return __awaiter(this, void 0, void 0, function* () {
            return yield this.update(sheet, key, data);
        });
    }
    remove(sheet, key) {
        return __awaiter(this, void 0, void 0, function* () {
            return yield this.update(sheet, key, null);
        });
    }
    increase(sheet, key, increasing) {
        return __awaiter(this, void 0, void 0, function* () {
            return yield this.server().increase(sheet, key, increasing);
        });
    }
    clearCacheAll(input) {
        return __awaiter(this, void 0, void 0, function* () {
            // turn string to string[]
            if (typeof input === 'string') {
                input = [input];
            }
            // clear data
            for (let i = 0; i < input.length; i++) {
                yield this.app.Cache.removeByPrefix('database_' + input[i]);
            }
        });
    }
    clearCacheItem(sheet, item) {
        return __awaiter(this, void 0, void 0, function* () {
            // clear all associated data
            yield this.clearCacheAll(sheet);
            // clear content
            const input = item['contentSource'];
            if (this.isContentSourceFromDocs(input)) {
                let id = '';
                if (this.isDocsContentSourceNotDirectly(input)) {
                    id = input.replace('https://docs.google.com/document/d/', '').split('/').shift();
                }
                else {
                    id = input.replace('/pub', '').split('/').pop();
                }
                yield this.app.Cache.removeByPrefix('content_' + id + '_clean');
                yield this.app.Cache.removeByPrefix('content_' + id + '_full');
                yield this.app.Cache.removeByPrefix('content_' + id + '_original');
            }
        });
    }
    isDirect(sheet) {
        const { databaseId, databaseGids } = this.app.options;
        return !!databaseId && !!databaseGids && !!databaseGids[sheet];
    }
    isContentSourceFromDocs(input) {
        // must be: not custom | doc url | published url
        return (
        // not intended custom source
        input.indexOf('from:') < 0 &&
            // doc url | published url
            input.indexOf('https://docs.google.com/document/d/') > -1);
    }
    isDocsContentSourceNotDirectly(input) {
        return (input.indexOf('https://docs.google.com/document/d/e/') < 0 &&
            input.indexOf('/pub') < 0);
    }
}
