/**
 * Copyright (c) 2020-2025, JGraph Holdings Ltd
 * Copyright (c) 2020-2025, draw.io AG
 */
/**
 * mxAsyncCanvas
 */

/**
 * Extends mxAbstractCanvas2D
 */
function mxAsyncCanvas(htmlCanvas)
{
	mxAbstractCanvas2D.call(this);
	this.htmlCanvas = htmlCanvas;
	htmlCanvas.images = htmlCanvas.images || [];
	htmlCanvas.subCanvas = htmlCanvas.subCanvas || [];
};

/**
 * Extends mxAbstractCanvas2D
 */
mxUtils.extend(mxAsyncCanvas, mxAbstractCanvas2D);

/**
 * Variable: htmlCanvas
 * 
 * The canvas instance this object is obtaining async resources for
 */
mxAsyncCanvas.prototype.htmlCanvas = null;

/**
 * Variable: canvasIndex
 * 
 * The current index into the canvas sub-canvas array being processed
 */
mxAsyncCanvas.prototype.canvasIndex = 0;

/**
 * Variable: ctx
 * 
 * Holds the current canvas context
 */
mxAsyncCanvas.prototype.waitCounter = 0;

/**
 * Variable: ctx
 * 
 * Holds the current canvas context
 */
mxAsyncCanvas.prototype.onComplete = null;

mxAsyncCanvas.prototype.incWaitCounter = function()
{
	this.waitCounter++;
};
	
mxAsyncCanvas.prototype.decWaitCounter = function()
{
	this.waitCounter--;
	
	if (this.waitCounter == 0 && this.onComplete != null)
	{
		this.onComplete();
		this.onComplete = null;
	}
};

mxAsyncCanvas.prototype.updateFont = function()
{
	var style = '';
	
	if ((this.state.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
	{
		style += 'bold ';
	}
	
	if ((this.state.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
	{
		style += 'italic ';
	}
	
	this.ctx.font = style + this.state.fontSize + 'px ' + this.state.fontFamily;
};

mxAsyncCanvas.prototype.rotate = function(theta, flipH, flipV, cx, cy)
{
};

mxAsyncCanvas.prototype.setAlpha = function(alpha)
{
	this.state.alpha = alpha;
};

mxAsyncCanvas.prototype.setFontColor = function(value)
{
	this.state.fontColor = value;
};

mxAsyncCanvas.prototype.setFontBackgroundColor = function(value)
{
	if (value == mxConstants.NONE)
	{
		value = null;
	}
	
	this.state.fontBackgroundColor = value;
};

mxAsyncCanvas.prototype.setFontBorderColor = function(value)
{
	if (value == mxConstants.NONE)
	{
		value = null;
	}
	
	this.state.fontBorderColor = value;
};

mxAsyncCanvas.prototype.setFontSize = function(value)
{
	this.state.fontSize = value;
};

mxAsyncCanvas.prototype.setFontFamily = function(value)
{
	this.state.fontFamily = value;
};

mxAsyncCanvas.prototype.setFontStyle = function(value)
{
	this.state.fontStyle = value;
};

mxAsyncCanvas.prototype.rect = function(x, y, w, h) {};

mxAsyncCanvas.prototype.roundrect = function(x, y, w, h, dx, dy) {};

mxAsyncCanvas.prototype.ellipse = function(x, y, w, h) {};

//Redirect can be implemented via a hook
mxAsyncCanvas.prototype.rewriteImageSource = function(src)
{
	if (src.substring(0, 7) == 'http://' || src.substring(0, 8) == 'https://')
	{
		src = '/proxy?url=' + encodeURIComponent(src);
	}
	
	return src;
};

mxAsyncCanvas.prototype.image = function(x, y, w, h, src, aspect, flipH, flipV)
{
	src = this.rewriteImageSource(src);
	var image = this.htmlCanvas.images[src];
	
	if (image == null)
	{
		var image = new Image();
		
		image.onload = mxUtils.bind(this, function()
		{
			this.decWaitCounter();
		});
		
		image.onerror = mxUtils.bind(this, function()
		{
			this.decWaitCounter();
			// TODO null the image out? this.htmlCanvas.images[src] = null;
		});

		this.incWaitCounter();
		this.htmlCanvas.images[src] = image;
		image.src = src;
	}
};

mxAsyncCanvas.prototype.fill = function() {};

mxAsyncCanvas.prototype.stroke = function() {};

mxAsyncCanvas.prototype.fillAndStroke = function() {};
	
mxAsyncCanvas.prototype.text = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation)
{
	if (str == null || str.length == 0)
	{
		return;
	}

	var sc = this.state.scale;

	if (format == 'html' && typeof html2canvas === 'function')
	{
		this.incWaitCounter();
		var canvasIndex = this.canvasIndex++;
		
	    html2canvas(str,
	    {
	        onrendered: mxUtils.bind(this, function(canvas)
	        {
	        	this.htmlCanvas.subCanvas[canvasIndex] = canvas;
	        	this.decWaitCounter();
	        }),
	        scale: sc,
	        logging: true
	    });
	}
};

mxAsyncCanvas.prototype.finish = function(handler)
{
	// TODO: Check if waitCounter updates need a monitor. Question is
	// if image load-handler can be executed in parallel leading to
	// race conditions when updating the "shared" waitCounter.
	if (this.waitCounter == 0)
	{
		handler();
	}
	else
	{
		this.onComplete = handler;
	}
};
