/**
 * Created by rburson on 3/18/16.
 */

/**
 * Smoothing techniques.
 * http://perfectionkills.com/exploring-canvas-drawing-techniques/
 */
import * as React from 'react'
import {
    CvState,
    CvProps,
    CvValueAdapter,
    CvValueListener,
    ColorUtil,
    ImageUtil,
    CvImagePackageUrl
} from 'catreact'
import {
    Log, Color, SignatureCapture
} from 'catavolt-sdk'

interface SigBundle {
    listener:CvValueListener<Object>,
    colors:{background:Color, line:Color },
    size: {width:number, height:number},
    ratio:{width:number, height:number}
}

    /**
 * Value to be assigned when CvSignaturePopup is mounted.
 */
let openSignaturePopupListener:CvValueListener<SigBundle>;

export function openSignaturePopup(listener:CvValueListener<Object>, signature?:SignatureCapture, ratio?:{width:number, height:number}):void {
    if (openSignaturePopupListener != null) {  // This is the mechanism that gets us inside the component's instance
        if (signature) {
            let c = { background: signature.backgroundColor, line: signature.lineColor }
            let s = {width:signature.captureBounds.width.value, height:signature.captureBounds.height.value}
            openSignaturePopupListener({listener: listener, colors: c, size:s, ratio:ratio});
        } else {
            // Provide some defaults
            let c = { background: new Color(null, 255,255,255,1), line: new Color(null, 0,0,0,1) }
            let s = { width: 800, height: 600 }
            let r = { width: 400, height: 200 }
            openSignaturePopupListener({listener: listener, colors: c, size:s, ratio:r});
        }
    }
}

export interface CvSignaturePopupState extends CvState {
    resultListener:CvValueListener<Object>,
    canvas?:HTMLCanvasElement,
    lineColor?:Color,
    backgroundColor?:Color,
    width?:number,
    height?:number,
    drawingStatus:{isDrawing:boolean, someDrawn:boolean}
}

export interface CvSignaturePopupProps extends CvProps {
}

/**
 Component that overlays a signature popup.
 */
export const CvSignaturePopup = React.createClass<CvSignaturePopupProps, CvSignaturePopupState>({

    componentWillMount: function() {
        let signatureProvider = new CvValueAdapter<SigBundle>();
        signatureProvider.subscribe(this._handleParamChange);
        openSignaturePopupListener = signatureProvider.createValueListener();
        window.addEventListener("mouseup", this._onMouseUp);
    },

    componentWillUnmount() {
        window.removeEventListener("mouseup", this._onMouseUp);
        this.state.canvas = null;
    },

    getDefaultProps: function () {
        return {paramProvider:null}
    },

    getInitialState: function() {
        return {
            resultListener: null,
            forceRedraw: 1,
            drawingStatus: {isDrawing: false, someDrawn: false }
        };
    },

    render: function () {
        return (
            <div className="modal fade" role="dialog" key="CvSignaturePopup"
                 ref={(d:HTMLDivElement)=>{
                let visible:boolean = (this.state != null) && (this.state.resultListener != null);
                if(visible) {
                    let m:any = $(d);
                    if(m && m.modal){ m.modal({show:true, keyboard: false, backdrop: 'static'} ) }
                    let ctx:CanvasRenderingContext2D = this._get2dContext();
                    ctx.strokeStyle = ColorUtil.toColor(this.state.lineColor);
                    ctx.lineWidth = 7;
                    ctx.lineCap = "round";
                    ctx.lineJoin = "round";
                    this._resetDrawing();
                } else {
                    let m:any = $(d);
                    if(m && m.modal){ m.modal('hide') }
                }
                }}>
                <div className="modal-dialog cv-signature" >
                    <div className="modal-content ">
                        <div className="modal-header cv-signature-header">
                            <p>Signature Capture</p>
                        </div>
                        <div className="modal-body" >
                            <canvas ref={(c:HTMLCanvasElement)=>{ this.state.canvas = c }}
                                    className="cv-signature-canvas"
                                    height={this.state.height} width={this.state.width} onMouseDown={this._onMouseDown} onMouseMove={this._onMouseMove}/>
                        </div>
                        <div className="modal-footer cv-signature-footer">
                            <button type="button" className="btn btn-default" onClick={()=>{
                                this.state.resultListener(new CvImagePackageUrl(this.state.canvas.toDataURL()));
                                this.setState({resultListener: null });  // Clearing the listener closes the popup
                            }}>Save</button>
                            <button type="button" className="btn btn-default" onClick={()=>{
                                this._resetDrawing();
                            }}>Redo</button>
                            <button type="button" className="btn btn-default" onClick={()=>{
                                this.setState({resultListener: null })
                            }}>Cancel</button>
                        </div>
                    </div>
                </div>
            </div>
        );
    },

    _get2dContext: function() {
        // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
        return this.state.canvas.getContext("2d");
    },
    _getMousePos: function(event) {
        let rect = this.state.canvas.getBoundingClientRect();
        return {
            x: event.clientX - rect.left,
            y: event.clientY - rect.top
        }
    },
    _handleParamChange: function(sigBundle:SigBundle) { // resultListener:CvValueListener<Object>) {
        if (sigBundle.listener) {
            let maxW:number = Math.min(sigBundle.size.width, $(window).innerWidth() - 50);
            let maxH:number = Math.min(sigBundle.size.height, $(window).innerHeight() - 200);
            let size:any =  ImageUtil.calculateAspectRatioFit(sigBundle.ratio.width, sigBundle.ratio.height, maxW, maxH);
            this.setState({backgroundColor: sigBundle.colors.background, lineColor: sigBundle.colors.line,
                width: size.width, height: size.height});
        }
        this.setState({resultListener: sigBundle.listener});
    },

    _onMouseDown: function(event:MouseEvent) {
        if (this.state.canvas) {
            Log.debug("CvSignaturePopup:MouseDown");
            let ctx: CanvasRenderingContext2D = this._get2dContext();
            ctx.beginPath();
            this.state.drawingStatus.isDrawing = true;
            this.state.drawingStatus.someDrawn = false;
            let pos = this._getMousePos(event);
            ctx.moveTo(pos.x, pos.y);
        }
    },

    _onMouseUp: function(event:MouseEvent) {
        if (this.state.drawingStatus.isDrawing) {
            Log.debug("CvSignaturePopup:MouseUp");
            let ctx:CanvasRenderingContext2D = this._get2dContext();
            let pos = this._getMousePos(event);
            if (!this.state.drawingStatus.someDrawn) {
                // If just a mouse click, draw a dot.
                ctx.strokeStyle = ColorUtil.toColor(this.state.lineColor);
                ctx.lineTo(pos.x +1, pos.y +1);
                ctx.stroke();
            }
            ctx.closePath();
            this.state.drawingStatus.isDrawing = false;
            this.state.drawingStatus.someDrawn = false;
        }
    },

    _onMouseMove: function(event) {
        if (this.state.drawingStatus.isDrawing) {
            let pos = this._getMousePos(event);

            let ctx:CanvasRenderingContext2D = this._get2dContext();
            ctx.strokeStyle = ColorUtil.toColor(this.state.lineColor);
            ctx.lineTo(pos.x, pos.y);
            ctx.stroke();
            ctx.moveTo(pos.x, pos.y);
            this.state.drawingStatus.someDrawn = true;
            Log.debug("CvSignaturePopup:MouseMove  x: " + pos.x + "  y: " + pos.y);
        }
    },
    _resetDrawing:function() {
        let ctx:CanvasRenderingContext2D = this._get2dContext();
        ctx.fillStyle = ColorUtil.toColor(this.state.backgroundColor);
        ctx.fillRect(0,0,this.state.width, this.state.height);
    }
});

