/*
* 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") {
            const internal = false;
            let {className, isObjectSubcategory} = this._data;
            let fragment = document.createDocumentFragment();
            let iconElement = fragment.appendChild(document.createElement("img"));
            iconElement.classList.add("icon", WI.HeapSnapshotClusterContentView.iconStyleClassNameForClassName(className, internal, isObjectSubcategory));
            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;
