export default class AGrid extends window.AObject {
    constructor(options) {
        super();
        const defaultO = { "element": ".AGrid", "gridType": "row", "hasRatio": false, "desiredHeight": "200", "gutter": "10" };
        this.ele = document.querySelector(options.element);
        this._o = { ...defaultO, ...options };
        this.gridWidth = this.ele.clientWidth;
        this.keyI = 1;
        this.isRender = false;
        this.listGrid = new Map();
        this.loaded = false;
        this.ticking = false;
        this.timeout = false
        this.cancelFunc = null;
        this.ele.querySelectorAll(".grid-item").forEach(el => {
            var img = el.querySelector("img.mImg");
            this.listGrid.set(this.keyI, { "gridEl": el, "imgEl": img, "aRatio": el.hasAttribute("aRatio") ? el.getAttribute("aRatio") : 0, "status": 0, "bounding": null });
            var kt = this.keyI;
            let f = (function (e) {
                let k = kt;
                this.listGrid.get(kt).status = 1;
                this.listGrid.get(kt).aRatio = e.currentTarget.clientWidth / e.currentTarget.clientHeight;
                this.listGrid.get(kt).gridEl.setAttribute("aRatio", this.listGrid.get(k).aRatio);
                this.listGrid.get(kt).bounding = e.currentTarget.getBoundingClientRect();
                this.loadImage();
                this.removeSystemEvent(e.currentTarget);
            }).bind(this);
            this.addSystemEvent("load", img, f);
            if (img.complete) {
                f({ "currentTarget": img });
                this.removeSystemEvent(img);
            }
            this.keyI++;
        });
        this.initRows();
        this.wWidth = window.innerWidth || document.body.clientWidth;
        this.options = options;
        this.addSystemEvent("resize", window, this.reLayout.bind(this));
        window.app.on("App_Scrolling", ((y) => {
            if (window.app.checkVisible(this.ele) && !this.isRender) {
                this.renderAnimation();
            }
        }).bind(this));
    }
    
    initGrid() {
        this.ele.style.height = this.ele.clientHeight + "px";
        const firstEntry = this.listGrid.entries().next().value;
        let refY = firstEntry[1].bounding.top;
        let refX = firstEntry[1].bounding.left;
        for (const [key, value] of this.listGrid) {
            let rect = value.bounding;
            let t = rect.top - refY;
            let l = rect.left - refX;
            value.gridEl.setAttribute("style", `position: absolute;top:${t}px;left:${l}; width:${rect.width};height:${rect.height}`);
        }
      
    }
    reLayout(e) {
        if (this.gridWidth == this.ele.clientWidth) {
            return;
        }
        if (!this.ticking) {
            if (this.cancelFunc != null) this.cancelFunc();
            window.requestAnimationFrame(() => {
                this.isRender = false;
                this.sTime = new Date();
                this.timeout = false;
                this.ticking = true;
                this.layoutInit();
                if (this.timeout == false) {
                    this.timeout = true;
                    this.resizeEnd();
                }
                this.ticking = false;
            });
        }
    }
    layoutInit() {
        this.gridWidth = this.ele.clientWidth;
        switch (this._o.gridType) {
            case "row":
                this.initRows();
                this.layoutRows();
                break;
            case "waterfall":
                this.restuctCol();
                this.initCols();
                this.layoutCols();
                break;
        }
    }
    resizeEnd() {
        var t = new Date() - this.sTime;
        if (t < 200) {
            window.requestTimeout(this.resizeEnd.bind(this), 100, (t) => { this.cancelFunc = t });
        } else {
            this.layoutInit();
            this.timeout = false;
        }      
    }
    initRows() {
        this.listRows = [];
        this.listRows.push(this.structureRow(this._o.desiredHeight));
    }
    initCols() {
        this.listCols = [];
        const firstEntry =this.listGrid.entries().next().value;
        this.colNum = Math.round(this.gridWidth / firstEntry[1].bounding.width);
        let colW = (this.gridWidth - (this.colNum - 1) * this._o.gutter) / this.colNum;
        for (let i = 0; i < this.colNum; i++) {
            const tm = this.structureCol(i + 1);
            tm.colW = colW;
            this.listCols.push(tm);
        }
    }
    restuctCol() {
        this.ele.style.height = '';

        this.listGrid.forEach((v, k) => {
            v.gridEl.style.top = '';
            v.gridEl.style.left = '';
            v.gridEl.style.width = '';
            v.gridEl.style.height = '';
            v.gridEl.style.position = "relative";
            v.bounding = v.gridEl.getBoundingClientRect();
        });
        this.initGrid();
    }
    loadImage() {
        if (this._o.hasRatio) {

        } else {
            window.requestTimeout((() => {
                if (this.loaded) return;
                for (const [key, value] of this.listGrid) {
                    if (value.status == 0) {
                        return;
                    }
                } 
                this.loaded = true;
                //if (this._o.gridType == "waterfall") console.log("waterfall " + this.loaded);
                //else console.log("Rows: " + this.loaded);
                this.initGrid();
                switch (this._o.gridType) {
                    case "row":
                        this.layoutRows();
                        break;
                    case "waterfall":
                        this.initCols();
                        this.layoutCols();
                        break;
                }
            }).bind(this), 100);
        }
    }
    layoutRows() {
        var nRow = 0;
        this.listGrid.forEach((v, k) => {
            nRow = this.pushEleToRow(nRow, k);
        });
        this.ele.style.height = this.calcPosTop(0, this.listRows.length) + "px";
        if (window.app.checkVisible(this.ele)) {
            this.renderAnimation();
        }
    }
    layoutCols() {
        let i = 0;
        let col = 0;
        let l = 0;
        //console.log(this.listgrid);
        //console.log(this.listcols);
        this.listGrid.forEach((v, k) => {
            let t = 0;
            let cVal;
            if (i % this.colNum == 0) {
                col = 0;
                cVal = this.listCols[col];
                l = 0;
            } else {
                col++;
                cVal = this.listCols[col];
                l += this.listCols[col].colW + 1*this._o.gutter;
            }
            t = cVal.colH;
            if (i > this.colNum - 1) {
                t += 1*this._o.gutter;
            }
            cVal.listElement.push({ "key": k, "top": t, "left": l, "render": false });
            cVal.colH = t + cVal.colW / v.aRatio;
            i++;
        });
       
        this.ele.style.height = this.getColMaxHeight() + "px";
        if (window.app.checkVisible(this.ele)) {
            this.renderAnimation();
        }
    }
    getColMaxHeight() {
        let m = 0;
        for (let i = 0; i < this.listCols.length; i++) {
            if (m <= this.listCols[i].colH) {
                m = this.listCols[i].colH;
            }
        }
        return m;
    }
    popEle(nRow, pos, k) {
        var cRow = this.listRows[nRow];
        var listPop = [];
        let posEle = 0;
        for (let i = 0; i < cRow.listElement.length; i++) {
            if (cRow.listElement[i].key > k) {
                posEle = i;
                break;
            }
        }
        cRow.listElement.slice(posEle, this.listElement.length - posEle);
        this.listRows.slice(nRow + 1, this.listRows.length - nRow);
        
    }
    renderAnimation() {
        this.isRender = true;
        switch (this._o.gridType) {
            case "row":
                this.listRows.forEach((el) => {
                    for (let i = 0; i < el.listElement.length; i++) {
                        let grid = this.listGrid.get(el.listElement[i].key);
                        var w = parseFloat(el.rowH * grid.aRatio).toFixed(2);
                        grid.gridEl.setAttribute("style", `position: absolute; top: ${parseFloat(el.listElement[i].top).toFixed(2)}px; left: ${parseFloat(el.listElement[i].left).toFixed(2)}px; width:${w}px; height:${parseFloat(el.rowH).toFixed(2)}px`);
                        grid.imgEl.setAttribute("style", `width:${w}px; height:${parseFloat(el.rowH).toFixed(2)}px`);
                    }
                });
                break;
            case "waterfall":
                this.listCols.forEach((el) => {
                    for (let i = 0; i < el.listElement.length; i++) {
                        let grid = this.listGrid.get(el.listElement[i].key);
                        grid.gridEl.setAttribute("style", `position: absolute; top: ${parseFloat(el.listElement[i].top).toFixed(2)}px; left: ${parseFloat(el.listElement[i].left).toFixed(2)}px; width:${el.colW}px; height:${parseFloat(el.colW / grid.aRatio).toFixed(2)}px`);
                    }
                });
                break;
        }
    }
    pushEleToRow(nRow, k) {
        let grid = this.listGrid.get(k);
        var cRow = this.listRows[nRow];
        let t1 = this._o.desiredHeight * grid.aRatio;
        let rowH = cRow.rowH;
        var errorH = (cRow.rowW + t1) / (this.gridWidth - (cRow.listElement.length - 1) * (this._o.gutter));
        
        if (errorH > 1.2) {
            if (cRow.listElement.length != 0) {
                cRow.rowH = this.reCalcWidth(cRow);
                this.listRows.push(this.structureRow(this._o.desiredHeight));
                return this.pushEleToRow(nRow + 1, k);
            }
        }
        var g = 0;
        if (cRow.listElement.length > 0) {
            g = this._o.gutter;
        }
        cRow.listElement.push({ "key": k, "top": this.calcPosTop(0, nRow), "left": (cRow.rowW + g), "render": false });
        cRow.rowW += t1;
        cRow.numM = k;
        if (errorH <= 1.2 && errorH >= 0.8) {
            cRow.rowH = this.reCalcWidth(cRow);
        }
        return nRow;
    }
    calcPosTop(begin, end) {
        if (begin == 0 && end == 0) {
            return 0;
        }
        let rowH = 0;
        for (let i = begin; i <= end - 1; i++) {
            rowH += 1*this.listRows[i].rowH + parseFloat(this._o.gutter);
        }
        return rowH;

    }
    reCalcWidth(cRow) {
        let rowW = this.gridWidth - (cRow.listElement.length - 1) * (this._o.gutter);
        let tRate = 0;
        for (var i = 0; i < cRow.listElement.length; i++) {
            tRate += this.listGrid.get(cRow.listElement[i].key).aRatio;
        }
        var rrowH = rowW / ((tRate == 0) ? 1 : tRate);
        for (var i = 0; i < cRow.listElement.length; i++) {
            if (i == 0) {
                cRow.listElement[i].left = 0;
                continue;
            }
            var t1 = cRow.listElement[i - 1];
            let w1 = this.listGrid.get(t1.key).aRatio * rrowH;
            cRow.rowW += w1;
            cRow.listElement[i].left = 1*t1.left + w1 + 1*this._o.gutter;
        }
        return rrowH;
    }
    structureCol(colN) {
        return { "listElement": [], "colNum": colN, "colH": 0, "colW":0 };
    }
    structureRow(rowH = 0) {
        return { "listElement": [], "rowH": rowH, "status": 0, "numM": 0, "rowW": 0 };
    }
}