/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

WI.HeapSnapshotClassDataGridNode = class HeapSnapshotClassDataGridNode extends WI.DataGridNode
{
    constructor(data, tree)
    {
        super(data, true);

        this._data = data;
        this._tree = tree;

        this._batched = false;
        this._instances = null;

        this.addEventListener("populate", this._populate, this);
    }

    // Protected

    get data() { return this._data; }

    createCellContent(columnIdentifier)
    {
        if (columnIdentifier === "retainedSize") {
            let size = this._data.retainedSize;
            let fragment = document.createDocumentFragment();
            let sizeElement = fragment.appendChild(document.createElement("span"));
            sizeElement.classList.add("size");
            sizeElement.textContent = Number.bytesToString(size);
            let percentElement = fragment.appendChild(document.createElement("span"));
            percentElement.classList.add("percentage");
            percentElement.textContent = emDash;
            return fragment;
        }

        if (columnIdentifier === "size")
            return Number.bytesToString(this._data.size);

        if (columnIdentifier === "className") {
            let {className} = this._data;
            let fragment = document.createDocumentFragment();
            let iconElement = fragment.appendChild(document.createElement("img"));
            iconElement.classList.add("icon", WI.HeapSnapshotClusterContentView.iconStyleClassNameForClassName(className));
            let nameElement = fragment.appendChild(document.createElement("span"));
            nameElement.classList.add("class-name");
            nameElement.textContent = className;
            return fragment;
        }

        return super.createCellContent(columnIdentifier);
    }

    sort()
    {
        if (this._batched) {
            this._removeFetchMoreDataGridNode();
            this._sortInstances();
            this._updateBatchedChildren();
            this._appendFetchMoreDataGridNode();
            return;
        }

        let children = this.children;
        children.sort(this._tree._sortComparator);

        for (let i = 0; i < children.length; ++i) {
            children[i]._recalculateSiblings(i);
            children[i].sort();
        }
    }

    removeCollectedNodes(collectedNodes)
    {
        let nodesToRemove = [];

        this.forEachImmediateChild((dataGridNode) => {
            if (dataGridNode instanceof WI.HeapSnapshotInstanceDataGridNode) {
                let heapSnapshotNode = dataGridNode.node;
                if (heapSnapshotNode.id in collectedNodes)
                    nodesToRemove.push(dataGridNode);
            }
        });

        if (nodesToRemove.length) {
            for (let dataGridNode of nodesToRemove)
                this.removeChild(dataGridNode);
        }

        if (this._instances) {
            this._instances = this._instances.filter((instance) => !(instance.id in collectedNodes));
            this._fetchBatch(nodesToRemove.length);
        }
    }

    updateCount(count)
    {
        if (count === this._data.count)
            return;

        if (!count) {
            this._tree.removeChild(this);
            return;
        }

        this._data.count = count;
        this.needsRefresh();
    }

    // Private

    _populate()
    {
        this.removeEventListener("populate", this._populate, this);

        this._tree.heapSnapshot.instancesWithClassName(this._data.className, (instances) => {
            // FIXME: <https://webkit.org/b/157905> Web Inspector: Provide a way to toggle between showing only live objects and live+dead objects
            this._instances = instances.filter((instance) => !instance.dead);
            this._sortInstances();

            // Batch.
            if (instances.length > WI.HeapSnapshotClassDataGridNode.ChildrenBatchLimit) {
                this._batched = true;
                this._fetchBatch(WI.HeapSnapshotClassDataGridNode.ChildrenBatchLimit);
                return;
            }

            for (let instance of this._instances)
                this.appendChild(new WI.HeapSnapshotInstanceDataGridNode(instance, this._tree));
        });
    }

    _fetchBatch(batchSize)
    {
        if (this._batched && this.children.length)
            this._removeFetchMoreDataGridNode();

        let oldCount = this.children.length;
        let newCount = oldCount + batchSize;

        if (newCount >= this._instances.length) {
            newCount = this._instances.length - 1;
            this._batched = false;
        }

        let count = newCount - oldCount;
        if (count) {
            for (let i = 0; i <= count; ++i) {
                let instance = this._instances[oldCount + i];
                this.appendChild(new WI.HeapSnapshotInstanceDataGridNode(instance, this._tree));
            }
        }

        if (this._batched)
            this._appendFetchMoreDataGridNode();
    }

    _sortInstances()
    {
        this._instances.sort((a, b) => {
            let fakeDataGridNodeA = {data: a};
            let fakeDataGridNodeB = {data: b};
            return this._tree._sortComparator(fakeDataGridNodeA, fakeDataGridNodeB);
        });
    }

    _updateBatchedChildren()
    {
        let count = this.children.length;

        this.removeChildren();

        for (let i = 0; i < count; ++i)
            this.appendChild(new WI.HeapSnapshotInstanceDataGridNode(this._instances[i], this._tree));
    }

    _removeFetchMoreDataGridNode()
    {
        console.assert(this.children[this.children.length - 1] instanceof WI.HeapSnapshotInstanceFetchMoreDataGridNode);

        this.removeChild(this.children[this.children.length - 1]);
    }

    _appendFetchMoreDataGridNode()
    {
        console.assert(!(this.children[this.children.length - 1] instanceof WI.HeapSnapshotInstanceFetchMoreDataGridNode));

        let count = this.children.length;
        let totalCount = this._instances.length;
        let remainingCount = totalCount - count;
        let batchSize = remainingCount >= WI.HeapSnapshotClassDataGridNode.ChildrenBatchLimit ? WI.HeapSnapshotClassDataGridNode.ChildrenBatchLimit : 0;

        this.appendChild(new WI.HeapSnapshotInstanceFetchMoreDataGridNode(this._tree, batchSize, remainingCount, this._fetchBatch.bind(this)));
    }
};

WI.HeapSnapshotClassDataGridNode.ChildrenBatchLimit = 100;
