"use strict";
// The MIT License (MIT)
//
// Copyright (c) 2017 Firebase
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
Object.defineProperty(exports, "__esModule", { value: true });
var _ = require("lodash");
var cloud_functions_1 = require("../cloud-functions");
/** @internal */
exports.provider = (new Buffer('Y2xvdWQuZmlyZXN0b3Jl', 'base64')).toString();
/** @internal */
exports.defaultDatabase = '(default)';
function database(database) {
    if (database === void 0) { database = exports.defaultDatabase; }
    return new DatabaseBuilder("projects/" + process.env.GCLOUD_PROJECT + "/databases/" + database);
}
exports.database = database;
function namespace(namespace) {
    return database().namespace(namespace);
}
exports.namespace = namespace;
function document(path) {
    return database().document(path);
}
exports.document = document;
var DatabaseBuilder = (function () {
    /** @internal */
    function DatabaseBuilder(resource) {
        this.resource = resource;
    }
    DatabaseBuilder.prototype.namespace = function (namespace) {
        return new NamespaceBuilder(this.resource + "/documents@" + namespace);
    };
    DatabaseBuilder.prototype.document = function (path) {
        return (new NamespaceBuilder(this.resource + "/documents")).document(path);
    };
    return DatabaseBuilder;
}());
exports.DatabaseBuilder = DatabaseBuilder;
var NamespaceBuilder = (function () {
    /** @internal */
    function NamespaceBuilder(resource) {
        this.resource = resource;
    }
    NamespaceBuilder.prototype.document = function (path) {
        return new DocumentBuilder(this.resource + "/" + path);
    };
    return NamespaceBuilder;
}());
exports.NamespaceBuilder = NamespaceBuilder;
var DocumentBuilder = (function () {
    /** @internal */
    function DocumentBuilder(resource) {
        this.resource = resource;
        // TODO what validation do we want to do here?
    }
    /** Respond to all document writes (creates, updates, or deletes). */
    DocumentBuilder.prototype.onWrite = function (handler) {
        return this.onOperation(handler, 'document.write');
    };
    /** Respond only to document creations. */
    DocumentBuilder.prototype.onCreate = function (handler) {
        return this.onOperation(handler, 'document.create');
    };
    /** Respond only to document updates. */
    DocumentBuilder.prototype.onUpdate = function (handler) {
        return this.onOperation(handler, 'document.update');
    };
    /** Respond only to document deletions. */
    DocumentBuilder.prototype.onDelete = function (handler) {
        return this.onOperation(handler, 'document.delete');
    };
    DocumentBuilder.prototype.onOperation = function (handler, eventType) {
        var dataConstructor = function (raw) {
            if (raw.data instanceof DeltaDocumentSnapshot) {
                return raw.data;
            }
            return new DeltaDocumentSnapshot(_.get(raw.data, 'value.fields', {}), _.get(raw.data, 'oldValue.fields', {}));
        };
        return cloud_functions_1.makeCloudFunction({
            provider: exports.provider, handler: handler,
            resource: this.resource,
            eventType: eventType,
            dataConstructor: dataConstructor,
        });
    };
    return DocumentBuilder;
}());
exports.DocumentBuilder = DocumentBuilder;
var DeltaDocumentSnapshot = (function () {
    function DeltaDocumentSnapshot(_raw, _old) {
        this._raw = _raw;
        this._old = _old;
    }
    DeltaDocumentSnapshot.prototype.data = function () {
        var _this = this;
        if (!this._data) {
            this._data = _.mapValues(this._raw, function (field) {
                return _this._transformField(field);
            });
        }
        return this._data;
    };
    DeltaDocumentSnapshot.prototype.get = function (key) {
        return _.get(this.data(), key, null);
    };
    Object.defineProperty(DeltaDocumentSnapshot.prototype, "previous", {
        // Note: this is an expected assymetry between event.data and
        // event.data.previous until we move the latter to event.previous
        get: function () {
            if (_.isEmpty(this._old)) {
                return null;
            }
            this._previous = new DeltaDocumentSnapshot(this._old, null);
            return this._previous;
        },
        enumerable: true,
        configurable: true
    });
    DeltaDocumentSnapshot.prototype._transformField = function (field) {
        var _this = this;
        // field is an object with only 1 key-value pair, so this will only loop once
        var result;
        _.forEach(field, function (fieldValue, fieldType) {
            if (fieldType === 'arrayValue') {
                result = _.map(_.get(fieldValue, 'values', []), function (elem) {
                    return _this._transformField(elem);
                });
            }
            else if (fieldType === 'mapValue') {
                result = _.mapValues(_.get(fieldValue, 'fields', {}), function (val) {
                    return _this._transformField(val);
                });
            }
            else if (fieldType === 'integerValue'
                || fieldType === 'doubleValue'
                || fieldType === 'longValue') {
                result = Number(fieldValue);
            }
            else if (fieldType === 'timestampValue') {
                result = new Date(fieldValue);
            }
            else if (fieldType === 'bytesValue') {
                try {
                    result = Buffer.from(fieldValue, 'base64');
                }
                catch (e) {
                    result = new Buffer(fieldValue, 'base64');
                }
            }
            else if (fieldType === 'referenceValue') {
                console.warn('WARNING: you have a data field which is a datastore reference. ' +
                    'There will be a breaking change later which will change it from a string to a reference object.');
                result = fieldValue;
            }
            else {
                result = fieldValue;
            }
        });
        return result;
    };
    return DeltaDocumentSnapshot;
}());
exports.DeltaDocumentSnapshot = DeltaDocumentSnapshot;
