import 'babel-polyfill';
import VConsole from 'vconsole';
import Graph from '../src/executor/loader';
import IO from '../src/feed/imageFeed';
import Logger from '../tools/logger';
window.log = new Logger();
// var vConsole = new VConsole();
// 统计参数
window.badCases = [];
// import Utils from '../src/utils/utils';
// 获取map表
// import Map from '../test/data/map';

// import demoPic from './bbt1.jpg';
// import demoPic2 from './bbt2.jpg';
// import demoPic3 from './bbt3.jpg';
// import demoPic4 from './bbt4.jpg';
// import demoPic5 from './bbt5.jpg';
// import testOutput from './data.json';

// 后处理测试用例
// let tempPic = [demoPic, demoPic2, demoPic3, demoPic4, demoPic5];
/**
 * @file model demo 入口文件
 * @author wangqun@baidu.com
 *
 */
// 'http://mms-xr.cdn.bcebos.com/paddle/mnist/model.json'
// 模型输出shape
const outputShapes = {
    '608': {
        from: [19, 19, 25, 1],
        to: [19, 19, 5, 5]
    },
    '320': {
        from: [10, 10, 25, 1],
        to: [10, 10, 5, 5]
    },
    '320fused': {
        from: [10, 10, 25, 1],
        to: [10, 10, 5, 5]
    },
    'separate': {
        from: [10, 10, 25, 1],
        to: [10, 10, 5, 5]
    }
};
// 模型feed数据
const feedShape = {
    '608': {
        fw: 608,
        fh: 608
    },
    '320': {
        fw: 320,
        fh: 320
    },
    '320fused': {
        fw: 320,
        fh: 320
    },
    'separate': {
        fw: 320,
        fh: 320
    }
};
// 模型路径
const modelPath = {
    '608': 'faceModel',
    '320': 'facemodel320',
    '320fused': 'facemodelfused',
    'separate': 'separablemodel'
};
const modelType = 'separate';
const path = modelPath[modelType];
// 统计参数
let loaded = false;
let model = {};
window.statistic = [];
const {fw, fh} = feedShape[modelType];
// 第一遍执行比较慢 所以预热一下
async function preheat() {
    const io = new IO();
    let feed = io.process({
        input: video,
        params: {
            gapFillWith: '#000', // 缩放后用什么填充不足方形部分
            targetSize: {
                height: fw,
                width: fh
            },
            targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名
            // shape: [3, 608, 608], // 预设tensor形状
            mean: [117.001, 114.697, 97.404], // 预设期望
            // std: [0.229, 0.224, 0.225]  // 预设方差
        }
    });
    const MODEL_URL = `/${path}/model.json`;
    const MODEL_CONFIG = {
        dir: `/${path}/`, // 存放模型的文件夹
        main: 'model.json', // 主文件
    };
    loaded = true;
    const graphModel = new Graph();
    log.start('加载模型');
    model = await graphModel.loadGraphModel(MODEL_CONFIG, {
        multipart: true,
        dataType: 'binary',
        binaryOption: {
            fileCount: 1, // 切成了多少文件
            getFileName(i) { // 获取第i个文件的名称
                return 'chunk_0.dat';
            }
        },
        feed
    });
    log.end('加载模型');
    let inst = model.execute({
        input: feed
    });
}
async function run(input) {
    // const input = document.getElementById('mobilenet');
    log.start('总耗时');
    const io = new IO();
    log.start('预处理');
    let feed = io.process({
        input: input,
        params: {
            gapFillWith: '#000', // 缩放后用什么填充不足方形部分
            targetSize: {
                height: fw,
                width: fh
            },
            targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名
            // shape: [3, 608, 608], // 预设tensor形状
            mean: [117.001, 114.697, 97.404], // 预设期望
            // std: [0.229, 0.224, 0.225]  // 预设方差
        }
    });
    log.end('预处理');
    if (!loaded) {
        const MODEL_URL = `/${path}/model.json`;
        const MODEL_CONFIG = {
            dir: `/${path}/`, // 存放模型的文件夹
            main: 'model.json', // 主文件
        };
        loaded = true;
        const graphModel = new Graph();
        log.start('加载模型');
        model = await graphModel.loadGraphModel(MODEL_CONFIG, {
            multipart: true,
            dataType: 'binary',
            binaryOption: {
                fileCount: 1, // 切成了多少文件
                getFileName(i) { // 获取第i个文件的名称
                    return 'chunk_0.dat';
                }
            },
            feed
        });
        log.end('加载模型');
    }

    log.start('运行耗时');
    let inst = model.execute({
        input: feed
    });

    // 其实这里应该有个fetch的执行调用或者fetch的输出
    let result = await inst.read();
    log.end('后处理-读取数据');
    // console.dir(['result', result]);
    log.start('后处理-形状调整');
    const newData = [];
    let newIndex = -1;
    const [w, h, c, b] = outputShapes[modelType].from;
    // c channel
    for (let i = 0; i < c; i++) {
        // height channel
        for (let j = 0; j < h; j++) {
            // width channel
            for (let k = 0; k < w; k++) {
                // position: (0, 0, 0, 0)
                const index = j * (c * h) + k * c + i;
                // const index = j * (i * k) + k * i + i;
                newData[++newIndex] = result[index];
            }
        }
    }
    log.end('后处理-形状调整');
    log.start('后处理-画框');
    testRun(newData, input);
    log.end('后处理-画框');
    log.end('后处理');
    log.end('总耗时');
}
var image = '';

function selectImage(file) {
    if (!file.files || !file.files[0]) {
        return;
    }
    let reader = new FileReader();
    reader.onload = function (evt) {
        let img = document.getElementById('image');
        img.src = evt.target.result;
        img.onload = function() {
            log.during('每次执行的时间间隔');
            run(img);
        };
        image = evt.target.result;
    }
    reader.readAsDataURL(file.files[0]);
}
// selectImage
document.getElementById("uploadImg").onchange = function () {
    selectImage(this);
};

/* 后处理图片 by zhangmiao06 */
let preTestRun = (index) => {
    let img = document.getElementById('image');
    img.src = tempPic[index];
    img.onload = function() {
        testRun(testOutput.data[index], img);
    };
};
let testRun = (data, img) => {
    // console.log('ori', data);
    const {from, to} = outputShapes[modelType];
    // let shape = [1, 25, 19, 19];
    let shape = [].concat(from).reverse();
    // 1.从一维数组到1*25*19*19
    let formatData = reshapeMany({
        data: data,
        reshapeShape: shape
    });
    // console.log('一维到多维', formatData);
    // 2.从1*25*19*19 到 19*19*25*1
    let formatData2 = transpose({
        data: formatData,
        shape: shape,
        transposeShape: [2, 3, 1, 0]
    });
    // console.log('transpose', formatData2);
    // 3.从19*19*25*1到19*19*5*5
    let formatData3 = reshape({
        data: formatData2,
        shape: from,
        reshapeShape: to
    });
    // console.log('reshape', formatData3);
    // 4.运算
    let finalData = handleFinal(formatData3, shape, img);
    // console.log('final', finalData);
    // 5.处理画布
    // handleCanvas(finalData, img);
    handleDiv(finalData, img);
};

// sigmoid
let sigmoid = (x) => {
    if (x < -100) {
        return 0.0;
    }
    return 1 / (1 + Math.exp(-x));
}

// transpose
let transpose = (data) => {
    let shape = data.shape;
    let transposeShape = data.transposeShape;
    let formatData = data.data;
    let formatData2 = [];
    for(let n = 0; n < shape[transposeShape[0]]; n++) {
        let nData = [];
        for(let c = 0; c < shape[transposeShape[1]]; c++) {
            let cData = [];
            for(let row = 0; row < shape[transposeShape[2]]; row++) {
                let rowData = [];
                for(let col = 0; col < shape[transposeShape[3]]; col++) {
                    let tempArr = [n, c, row, col];
                    let newN = n;
                    let newC = c;
                    let newW = row;
                    let newH = col;
                    transposeShape.forEach((item, index)=> {
                        switch(item) {
                            case 0:
                                newN = tempArr[index];
                                break;
                            case 1:
                                newC = tempArr[index];
                                break;
                            case 2:
                                newW = tempArr[index];
                                break;
                            case 3:
                                newH = tempArr[index];
                        }
                    });
                    rowData.push(formatData[newN][newC][newW][newH]);
                }
                cData.push(rowData);
            }
            nData.push(cData);
        }
        formatData2.push(nData);
    }
    return formatData2;
};

// reshape
let reshape = (data) =>{
    let formatData2 = data.data;
    let shape = data.shape;
    let reshapeShape = data.reshapeShape;
    // 1.变成一维
    let tempData = reshapeOne({
        data: formatData2,
        shape: shape
    });
    // 2.变成多维
    let formatData3 = reshapeMany({
        data: tempData,
        reshapeShape: reshapeShape
    });
    return formatData3;
};

// 变成一维
let reshapeOne = (data) => {
    let formatData2 = data.data;
    let shape = data.shape;
    let tempData = [];
    for(let n = 0; n < shape[0]; n++) {
        for(let c = 0; c < shape[1]; c++) {
            for(let row = 0; row < shape[2]; row++) {
                for(let col = 0; col < shape[3]; col++) {
                    tempData.push(formatData2[n][c][row][col]);
                }
            }
        }
    }
    return tempData;
};

// 变成多维
let reshapeMany = (data) => {
    let tempData = data.data;
    let reshapeShape = data.reshapeShape;
    let formatData3 = [];
    for(let n = 0; n < reshapeShape[0]; n++) {
        let nData = [];
        for(let c = 0; c < reshapeShape[1]; c++) {
            let cData = [];
            for(let row = 0; row < reshapeShape[2]; row++) {
                let rowData = [];
                for(let col = 0; col < reshapeShape[3]; col++) {
                    let tempN = n * reshapeShape[1] * reshapeShape[2] * reshapeShape[3];
                    let tempC = c * reshapeShape[2] * reshapeShape[3];
                    let tempRow = row * reshapeShape[3];
                    rowData.push(tempData[tempN + tempC + tempRow + col]);
                }
                cData.push(rowData);
            }
            nData.push(cData);
        }
        formatData3.push(nData);
    }
    return formatData3;
};
let calSize = (img) => {
    let w1 = img.width;
    let h1 = img.height;
    let wh1 = Math.max(w1, h1);
    // let factor = 608.0 / wh1;
    let factor = fw / wh1;
    let width = Math.round(w1 * factor);
    let height = Math.round(h1 * factor);
    return [w1, h1, width, height];
};
// 处理运算
let handleFinal = (formatData3, shape, img) => {
    let finalData = [];
    let c = shape[2];
    let [w1, h1, width, height] = calSize(img);
    let factorX = Math.max(width, height) / width;
    let factorY = Math.max(width, height) / height;

    let maxProb = 0.0;
    let anchors = [[1.603231, 2.094468], [6.041143, 7.080126], [2.882459, 3.518061], [4.266906, 5.178857], [9.041765, 10.66308]];

    for(let i = 0; i < shape[2]; i++) {
        for(let j = 0; j < shape[3]; j++) {
            for(let k = 0; k < anchors.length; k++) {
                let [a1, a2, a3, a4, prob] = formatData3[i][j][k];
                prob = sigmoid(prob);
                if (prob > maxProb && prob >= 0.5) {
                    let ctx = (j + sigmoid(a1)) / c * factorX;
                    let cty = (i + sigmoid(a2)) / c * factorY;
                    let col = Math.exp(a3) * anchors[k][0] / c * factorX;
                    let row = Math.exp(a4) * anchors[k][1] / c * factorY;
                    let x = (ctx - (col / 2));
                    let y = (cty - (row / 2));
                    finalData.push([x * w1, y * h1, col * w1, row * h1, prob]);
                }
            }
        }
    }
    return finalData;
};

// 处理画布
let handleCanvas = (finalData, img) => {
    let myCanvas = document.getElementById('myCanvas');
    let [w1, h1, width, height] = calSize(img);
    myCanvas.width = w1;
    myCanvas.height = h1;
    let ctx = myCanvas.getContext("2d");
    ctx.drawImage(img, 0, 0, w1, h1);

    finalData.forEach((demoArr,index) => {
        let [demoLeft, demoTop, demoWidth, demoHeight, prob] = demoArr;
        ctx.beginPath();
        ctx.strokeStyle="red";
        ctx.moveTo(demoLeft, demoTop);
        ctx.lineTo(demoLeft + demoWidth, demoTop);
        ctx.lineTo(demoLeft + demoWidth, demoTop + demoHeight);
        ctx.lineTo(demoLeft, demoTop + demoHeight);
        ctx.closePath();
        ctx.stroke();
    });
};
let handleDiv = (finalData, img) => {
    if (finalData.length < 1) {
        return false;
    }
    let myCanvas = document.getElementById('myDiv');
    let maxIndex = 0;
    if (finalData.length > 1) {
        for(let i = 1; i < finalData.length; i++) {
            if (finalData[i].prob > finalData[maxIndex].prob) {
                maxIndex = i;
            }
        }
    }
    let [demoLeft, demoTop, demoWidth, demoHeight, prob] = finalData[maxIndex];
    myCanvas.style.width = demoWidth;
    myCanvas.style.height = demoHeight;
    myCanvas.style.left = demoLeft;
    myCanvas.style.top = demoTop;
};
// preTestRun(0);

// run(document.getElementById('pic'));
