import Drawer from './drawer.js';

class ROIDrawer extends Drawer {
    constructor(props) {
        super(props);
        this.currentState = 'end';
        this.points = [];
        this.polygons = [];
        this.MAX_POLYGON = 1;
        this.onDrawROIFinishedCallback = null;
    }

    _init() {
        this.context.lineWidth = 2;
        this.context.font = 'bold 20px Arial';

        this.canvas.addEventListener('click', this._onClick.bind(this));
        this.canvas.addEventListener('contextmenu', this._oncontextmenu.bind(this));
        this.canvas.addEventListener('mousemove', this._onmousemove.bind(this));
    }

    _onClick(e) {
        switch (this.currentState) {
            case 'begin':
                this.points.push(getMousePos(this.canvas, e));
                this.currentState = 'firstPoint';
                break;
            case 'firstPoint': // 防止初始点点两次
                break;
            case 'move':
                this.currentState = 'points';
                break;
            case 'points':
                let currentPoint = getMousePos(this.canvas, e);
                if ((currentPoint.x === this.points[this.points.length - 1].x) && (currentPoint.y === this.points[this.points.length - 1].y)) {
                    return;
                }
                this.points.push(currentPoint);
                if (checkPolygon(this.points)) {
                    this.points.pop();
                }
                //console.log(this.points);
                break;
            case 'end':
                //console.log(this.points)
                break;
            default:
                console.log('unknown state: ', this.currentState);
                break;
        }
        // this._drawPolygons(this.points, true);
    }

    _oncontextmenu(e) {
        e.preventDefault();
        if(this.currentState === 'end') { //防止点击右键启动绘制
            return ;
        }
        if (this.points.length <= 2) {
            this._resetPoints();
        } else {
            if ((this.points[0].x !== this.points[this.points.length - 1].x) || (this.points[0].y !== this.points[this.points.length - 1].y)) {
                this.points.push(this.points[0]);
            }
            if (checkPolygon(this.points)) {
                this.points.pop();
            } else {
                this.currentState = 'end';
                this.polygons.push([...this.points]);
                if(this.polygons.length < this.MAX_POLYGON) {
                    this._resetPoints();
                } else {
                    this.onDrawROIFinishedCallback && this.onDrawROIFinishedCallback();
                    this._drawPolygons([]);
                }
            }
        }
    }

    _onmousemove(e) {
        let pos = getMousePos(this.canvas, e);
        //console.log('mousemove');
        if (e.button === 0) {
            if (this.currentState === 'firstPoint') {
                this.currentState = 'move';
                this.points.push(pos);
            } else if (this.currentState === 'move') {
                this.points.pop();
                this.points.push(pos);
            }
            if (this.currentState !== 'end') {
                this.points.push(pos);
                this._drawPolygons(this.points);
                this.points.pop();
            } else {
                //this._drawPolygons(this.points);
            }
            if(this.currentState === 'begin') {
                this._drawText('区域' + (this.polygons.length + 1), pos.x, pos.y)
            }
        }
    }

    getROIData() {
        if(this.currentState !== 'end') { //非完成状态
            return null;
        }
        let polygons = [];
        this.polygons.map((points, k) =>{
            let data = points.slice(0, points.length - 1);
            data.map((point, k) => {
                data[k] = this._to8191Coordinate(point, this.canvas);
            });
            polygons.push([...data]);
        });

        return polygons;
    }

    setROI(polygons) {
        if(!polygons) {
            return;
        }
        let data = [];
        this.polygons = [];
        polygons.map((points, k) => {
            points.map((point, k) => {
                let result = this._toRealCoordinate(point.x, point.y);
                data[k] = {x: result[0], y: result[1]};
            });
            if(data.length) {
                data[data.length] = data[0];
            }
            this.polygons.push([...data]);
            data = [];
        });
        this.currentState = 'end';
        this.points = [];
        this._drawPolygons(this.points);
    }

    redrawROI() {
        this._drawPolygons(this.points);
    }

    reset() {
        this.currentState = 'begin';
        this.polygons = [];
        this.points.length = 0;
        this._drawPolygons(this.points);
    }

    setROIFinishedCallback(callback) {
        this.onDrawROIFinishedCallback = callback;
    }

    setPolygonNum(num) {
        this.MAX_POLYGON = num;
    }

    terminate() {
        this.clearCanvas();
        this.canvas.width = 0;
        this.canvas.height = 0;
        this.currentState = 'end';
        this.points.length = 0;
        this.canvas.removeEventListener('click', this._onClick);
        this.canvas.removeEventListener('contextmenu', this._oncontextmenu);
        this.canvas.removeEventListener('mousemove', this._onmousemove);
    }

    _drawPolygons(points) {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.polygons.map((points, k)=> {
            this._drawPolygon(points);
        });
        this._drawPolygon(points);
    }

    _drawPolygon(points) {
        if (!points.length) {
            return;
        }
        const end = this.currentState === 'end';
        //console.log(points)
        this.context.strokeStyle = end ? '#0000ff' : "#ffff00";

        this.context.beginPath();
        this.context.moveTo(points[0].x, points[0].y);
        for (let i = 1; i < points.length; i++) {
            this.context.lineTo(points[i].x, points[i].y);
        }
        if (end) {
            // draw is done, fill polygon with a color
            this.context.fillStyle = "rgba(255, 0, 0, 0.2)";
            this.context.fill();
        } else {
            this.context.stroke();
        }
        this.context.closePath();

        this.polygons.map((points, k)=> {
            this._drawText('区域' + (k + 1), points[0].x - 20, points[0].y - 10);
        });
    }

    _resetPoints() {
        this.currentState = 'begin';
        this.points.length = 0;
        this._drawPolygons(this.points);
    }

    _drawText(text, x, y) {
        this.context.beginPath();
        this.context.fillStyle = "rgba(255, 255, 0, 1)";
        this.context.fillText(text, x, y);
        this.context.closePath();
    }

}

class StandingDrawer extends Drawer {
    constructor(props) {
        super(props);
        this.currentState = 'end';
        this.points = [];
        this.onDrawROIFinishedCallback = null;
    }

    _init() {
        this.context.lineWidth = 2;
        this.context.font = 'bold 20px Arial';

        this.canvas.addEventListener('click', this._onClick.bind(this));
        this.canvas.addEventListener('contextmenu', this._oncontextmenu.bind(this));
        this.canvas.addEventListener('mousemove', this._onmousemove.bind(this));
    }

    _onClick(e) {
        let pos = getMousePos(this.canvas, e);
        switch (this.currentState) {
            case 'begin':
                this.points.push(pos);
                this.currentState = 'firstPoint';
                break;
            case 'firstPoint': // 防止初始点点两次
                break;
            case 'move':
                this.currentState = 'points';
                break;
            case 'points':
                if (((pos.x === this.points[this.points.length - 1].x) && (pos.y === this.points[this.points.length - 1].y))
                    || this.points.length > 6) {
                    return;
                }
                this.points.push(pos);
                let points = this.points.length > 4 ? this.points.slice(0, 4) : this.points;
                if(checkPolygon(points)) {
                    this.points.pop();
                }
                if(this.points.length === 6) {
                    this.currentState = 'end';
                    this.onDrawROIFinishedCallback && this.onDrawROIFinishedCallback();
                }
                this._drawArea(this.points);
                break;
            case 'end':
                break;
            default:
                console.log('unknown state: ', this.currentState);
                break;
        }
    }

    _oncontextmenu(e) {
        e.preventDefault();
    }

    _onmousemove(e) {
        let pos = getMousePos(this.canvas, e);
        if (e.button === 0) {
            if (this.currentState === 'firstPoint') {
                this.currentState = 'move';
                this.points.push(pos);
            } else if (this.currentState === 'move') {
                this.points.pop();
                this.points.push(pos);
            }
            if (this.currentState !== 'end') {
                this.points.push(pos);
                this._drawArea(this.points);
                this.points.pop();
            } else {
            }
            // if(this.currentState === 'begin') {
            //     this._drawText('区域' + (this.polygons.length + 1), pos.x, pos.y)
            // }
        }
    }

    _drawArea(points) {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
        let polygon = points.length > 4 ? points.slice(0, 4) : points;
        this._drawPolygon(polygon);
        let line = points.length > 4 ? points.slice(4) : [];
        this._drawLine(line);
    }

    _drawPolygon(points) {
        if(!points.length) {
            return;
        }
        this.context.strokeStyle = '#00ff00';
        this.context.beginPath();
        this.context.moveTo(points[0].x, points[0].y);
        for (let i = 1; i < points.length; i++) {
            this.context.lineTo(points[i].x, points[i].y);
        }
        this.points.length >= 4 && this.context.lineTo(points[0].x, points[0].y);
        this.context.stroke();
        this.context.closePath();
    }

    _drawLine(points) {
        if(points.length !== 2) {
            return;
        }
        this.context.strokeStyle = '#0000ff';
        this.context.beginPath();
        this.context.moveTo(points[0].x, points[0].y);
        this.context.lineTo(points[1].x, points[1].y);
        this.context.stroke();
        this.context.closePath();
    }

    getROIData() {
        if(this.currentState !== 'end') { //非完成状态
            return null;
        }
        let points = [];
        this.points.map((point, k) => {
            points.push(this._to8191Coordinate(point, this.canvas));
        });
        return points;
    }

    setROI(points) {
        if(!points) {
            return;
        }
        let data = [];
        points.map((point, k) => {
            let result = this._toRealCoordinate(point.x, point.y);
            data[k] = {x: result[0], y: result[1]};
        });
        this.points = [...data];
        this._drawArea(data);
        this.currentState = 'end';
    }

    redrawROI() {
        this._drawArea(this.points);
    }

    reset() {
        this.currentState = 'begin';
        this.points.length = 0;
        this._drawArea(this.points);
    }

    setROIFinishedCallback(callback) {
        this.onDrawROIFinishedCallback = callback;
    }

    terminate() {
        this.clearCanvas();
        this.canvas.width = 0;
        this.canvas.height = 0;
        this.currentState = 'end';
        this.points.length = 0;
        this.canvas.removeEventListener('click', this._onClick);
        this.canvas.removeEventListener('contextmenu', this._oncontextmenu);
        this.canvas.removeEventListener('mousemove', this._onmousemove);
    }

}

class SpeedLine extends Drawer {
    constructor(canvas) {
        super(canvas);
        this.currentState = 'end';
        this.MAXLINE = 2;
        this.points = [];
        this.onDrawROIFinishedCallback = null;
    }

    _init() {
        this.canvas.addEventListener('click', this._onClick.bind(this));
        this.canvas.addEventListener('contextmenu', this._oncontextmenu.bind(this));
        this.canvas.addEventListener('mousemove', this._onmousemove.bind(this));
    }

    _onClick(e) {
        if(this.points.length === this.MAXLINE * 2) {
            return;
        }
        switch (this.currentState) {
            case 'begin':
                this.points.push(getMousePos(this.canvas, e));
                this.currentState = 'firstPoint';
                break;
            case 'firstPoint': // 防止初始点点两次
                break;
            case 'move':
                this.currentState = 'points';
                break;
            case 'points':
                let currentPoint = getMousePos(this.canvas, e);
                if ((currentPoint.x === this.points[this.points.length - 1].x) && (currentPoint.y === this.points[this.points.length - 1].y)) {
                    return;
                }
                this.points.push(currentPoint);
                if(this.points.length === this.MAXLINE * 2) {
                    if (this._checkLine(this.points)) {
                        this.points.pop();
                    } else {
                        this.currentState = 'end';
                        this._drawLines(this.points);
                        this.onDrawROIFinishedCallback && this.onDrawROIFinishedCallback();
                    }
                }
                break;
            case 'end':
                break;
            default:
                console.log('unknown state: ', this.currentState);
                break;
        }
    }

    _onmousemove(e) {
        let pos = getMousePos(this.canvas, e);
        console.log(e);
        if (e.button === 0) {
            if (this.currentState === 'firstPoint') {
                this.currentState = 'move';
                this.points.push(pos);
            } else if (this.currentState === 'move') {
                this.points.pop();
                this.points.push(pos);
            }
            if (this.currentState !== 'end' && this.currentState !== 'begin') {
                this.points.push(pos);
                this._drawLines(this.points);
                this.points.pop();
            }
        }
    }

    _oncontextmenu(e) {
        e.preventDefault();
    }
    /**
     *
     * @param points [] x1,y1,x2,y2...
     * @private
     */
    _checkLine(points) {
        for (let i = 0; i < points.length - 3; i = i + 2) {
            for (let j = i + 2; j < points.length - 1; j = j + 2) {
                let result = segmentsIntr(points[i], points[i + 1], points[j], points[j + 1]);
                if (result) {
                    console.log('intersect:');
                    console.log(result)
                    return result;
                }
            }
        }
        return false;
    }

    _drawLines(points) {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
        if (!points.length) {
            return;
        }
        const end = this.currentState === 'end';
        this.context.strokeStyle = end ? '#00ff00' : "#ffff00";
        this.context.beginPath();
        for (let i = 0; i < points.length - 1; i = i + 2) {
            this.context.moveTo(points[i].x, points[i].y);
            this.context.lineTo(points[i + 1].x, points[i + 1].y);
        }
        this.context.stroke();
        this.context.closePath();
    }

    getROIData() {
        if(this.currentState !== 'end') { //非完成状态
            return null;
        }
        let data = this.points;
        data.map((point, k) => {
            data[k] = this._to8191Coordinate(point, this.canvas);
        });
        return data;
    }

    setROI(data) {
        data.map((point, k) => {
            let result = this._toRealCoordinate(point.x, point.y);
            data[k] = {x: result[0], y: result[1]};
        });

        this.currentState = 'end';
        this.points = data;
        this._drawLines(this.points);
    }

    redrawROI() {
        this._drawLines(this.points);
    }

    reset() {
        this.currentState = 'begin';
        this.points.length = 0;
        console.log(this.points)
        this._drawLines(this.points);
    }

    setROIFinishedCallback(callback) {
        this.onDrawROIFinishedCallback = callback;
    }

    setLineNum(num) {
        this.MAXLINE = num;
    }

    terminate() {
        this.clearCanvas();
        this.canvas.width = 0;
        this.canvas.height = 0;
        this.currentState = 'end';
        this.points.length = 0;
        this.canvas.removeEventListener('click', this._onClick);
        this.canvas.removeEventListener('contextmenu', this._oncontextmenu);
        this.canvas.removeEventListener('mousemove', this._onmousemove);
    }
}

class BlankROIDrawer extends Drawer {
    constructor(canvas) {
        super(canvas);
    }
    getROIData() {

    }

    setROI() {

    }

    redrawROI() {

    }

    reset() {

    }

    terminate() {

    }
}

function getMousePos(canvas, event) {
    var rect = canvas.getBoundingClientRect();
    var x = event.clientX - rect.left * (canvas.width / rect.width);
    var y = event.clientY - rect.top * (canvas.height / rect.height);
    //console.log("x:"+x+",y:"+y);
    return {x: x, y: y};
}

function checkPolygon(points) {
    for (let i = 0, length = points.length - 1; i < length; i++) {
        for (let j = i + 1, len = points.length - 1; j < len; j++) {
            let result = segmentsIntr(points[i], points[i + 1], points[j], points[j + 1]);
            if (result) {
                console.log('intersect:');
                console.log(result)
                return result;
            }
        }
    }
    return false;
}


function segmentsIntr(a, b, c, d) {

    // 三角形abc 面积的2倍
    var area_abc = (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x);

    // 三角形abd 面积的2倍
    var area_abd = (a.x - d.x) * (b.y - d.y) - (a.y - d.y) * (b.x - d.x);

    // 面积符号相同则两点在线段同侧,不相交 (对点在线段上的情况,本例当作不相交处理);
    if (area_abc * area_abd >= 0) {
        return false;
    }

    // 三角形cda 面积的2倍
    var area_cda = (c.x - a.x) * (d.y - a.y) - (c.y - a.y) * (d.x - a.x);
    // 三角形cdb 面积的2倍
    // 注意: 这里有一个小优化.不需要再用公式计算面积,而是通过已知的三个面积加减得出.
    var area_cdb = area_cda + area_abc - area_abd;
    if (area_cda * area_cdb >= 0) {
        return false;
    }

    //计算交点坐标
    var t = area_cda / (area_abd - area_abc);
    var dx = t * (b.x - a.x),
        dy = t * (b.y - a.y);
    return {x: a.x + dx, y: a.y + dy};

}


export  {ROIDrawer, StandingDrawer, SpeedLine, BlankROIDrawer};
