/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const {IgniteClient, ObjectType, ComplexObjectType, BinaryObject, CacheEntry, ScanQuery, IgniteClientConfiguration} = require('apache-ignite-client');

const ENDPOINT = '127.0.0.1:10800';

const CACHE_NAME = 'CachePutGetExample_person';
const PERSON_TYPE_NAME = 'Person';

class Person {
    constructor(firstName = null, lastName = null, salary = null) {
        this.id = Person.generateId();
        this.firstName = firstName;
        this.lastName = lastName;
        this.salary = salary;
    }

    static generateId() {
        if (!Person.id) {
            Person.id = 0;
        }
        const id = Person.id;
        Person.id++;
        return id;
    }
}

// This example demonstrates basic Cache, Key-Value Queries and Scan Query operations:
// - connects to a node
// - creates a cache, if it doesn't exist
//   - specifies key type as Integer
// - executes different cache operations with Complex Objects and Binary Objects
//   - put several objects in parallel
//   - putAll
//   - get
//   - getAll
//   - ScanQuery
// - destroys the cache
class CachePutGetExample {

    constructor() {
        this._personCache = null;
        this._personObjectType = null;
        this._binaryObjectCache = null;
    }

    async start() {
        const igniteClient = new IgniteClient(this.onStateChanged.bind(this));
        try {
            await igniteClient.connect(new IgniteClientConfiguration(ENDPOINT));

            this._personObjectType = new ComplexObjectType(new Person(), PERSON_TYPE_NAME).
                setFieldType('id', ObjectType.PRIMITIVE_TYPE.INTEGER);

            this._personCache = (await igniteClient.getOrCreateCache(CACHE_NAME)).
                setKeyType(ObjectType.PRIMITIVE_TYPE.INTEGER).
                setValueType(this._personObjectType);

            this._binaryObjectCache = igniteClient.getCache(CACHE_NAME).
                setKeyType(ObjectType.PRIMITIVE_TYPE.INTEGER);

            await this.putComplexObjects();
            await this.putAllBinaryObjects();

            await this.getAllComplexObjects();
            await this.getBinaryObjects();

            await this.scanQuery();

            await igniteClient.destroyCache(CACHE_NAME);
        }
        catch (err) {
            console.log('ERROR: ' + err.message);
        }
        finally {
            igniteClient.disconnect();
        }
    }

    async putComplexObjects() {
        const person1 = new Person('John', 'Doe', 1000);
        const person2 = new Person('Jane', 'Roe', 2000);

        // put multiple values in parallel
        await Promise.all([
            await this._personCache.put(person1.id, person1),
            await this._personCache.put(person2.id, person2)
        ]);

        console.log('Complex Objects put successfully');
    }

    async putAllBinaryObjects() {
        // create binary object from scratch
        const personBinaryObject1 = new BinaryObject(PERSON_TYPE_NAME).
            setField('id', Person.generateId(), ObjectType.PRIMITIVE_TYPE.INTEGER).
            setField('firstName', 'Mary').
            setField('lastName', 'Major').
            setField('salary', 1500);

        // create binary object from complex object
        const personBinaryObject2 = await BinaryObject.fromObject(
            new Person('Richard', 'Miles', 800), this._personObjectType);

        await this._binaryObjectCache.putAll([
            new CacheEntry(await personBinaryObject1.getField('id'), personBinaryObject1),
            new CacheEntry(await personBinaryObject2.getField('id'), personBinaryObject2)
        ]);

        console.log('Binary Objects put successfully using putAll()');
    }

    async getAllComplexObjects() {
        const persons = await this._personCache.getAll([2, 3]);
        console.log('Complex Objects getAll:');
        for (let person of persons) {
            this.printPersonObject(person.getValue());
        }
    }

    async getBinaryObjects() {
        const personBinaryObject = await this._binaryObjectCache.get(3);
        console.log('Binary Object get:');
        console.log('  ' + personBinaryObject.getTypeName());
        let fieldValue;
        for (let fieldName of personBinaryObject.getFieldNames()) {
            fieldValue = await personBinaryObject.getField(fieldName);
            this.printPersonField(fieldName, fieldValue);
        }
    }

    async scanQuery() {
        const cursor = await this._personCache.query(new ScanQuery());
        console.log('Scan query results:');
        for (let cacheEntry of await cursor.getAll()) {
            this.printPersonObject(cacheEntry.getValue());
        }
    }

    onStateChanged(state, reason) {
        if (state === IgniteClient.STATE.CONNECTED) {
            console.log('Client is started');
        }
        else if (state === IgniteClient.STATE.DISCONNECTED) {
            console.log('Client is stopped');
            if (reason) {
                console.log(reason);
            }
        }
    }

    printPersonObject(person) {
        console.log('  ' + PERSON_TYPE_NAME);
        for (let key in person) {
            this.printPersonField(key, person[key]);
        }
    }

    printPersonField(fieldName, fieldValue) {
        console.log('    ' + fieldName + ' : ' + fieldValue);
    }
}

const cachePutGetExample = new CachePutGetExample();
cachePutGetExample.start();
