_matrixs=[];

var matrixImages={
	'images': {},
	'errors': {}
}

class ImagesLoader {
	constructor(callback,count) {
		this.images={};
		this.count=count;
		this.callback=callback;
		this.loaded=0;
	}

	isLoaded(src) {
		return matrixImages.errors[src]===undefined;
	}

	imageLoaded(timeout) {
		this.loaded++;
		if (this.loaded==this.count) {
			this.callback();
		}
	}

	getImg(src) {
		return matrixImages.images[src];
	}

	addImage(src) {
		var _this=this;
		if (matrixImages.images[src]===undefined) {
			var img=new Image;
			img.src=src;
			img.onload=function() {
				matrixImages.images[src]=img;
				_this.imageLoaded();
			}
			img.onerror=function() {
				matrixImages.images[src]=img;
				matrixImages.errors[src]=true;
				_this.imageLoaded();
			}
		} else {
			setTimeout(function() {
				_this.imageLoaded(true);
			},10);
		}
	}
}

var winLineColors=['red','green','blue','white'];

function getCellImage(CDN,cell,attributes) {
	return `<img src=${CDN}${cell} ${attributes}>`;
}

function addCellValue(parent,elem,cell,matrix) {
	parent.append(elem);
	var attributes="";
	if (cell && cell.colspan) {
		elem.attr('colspan',cell.colspan);
	}
	if (cell && cell.type=='boolean' && cell.active) {
		elem.attr('active','');
	}
	if (matrix.img) {
		if (matrix.img.width) {
			attributes+=` width='${matrix.img.width}'`;
		}
		if (matrix.img.height) {
			attributes+=` width='${matrix.img.height}'`;
		}
	}
	if (cell instanceof Object) {
		if (cell.type=='multiple') {
			cell.values.forEach(function(c) {
				/*var div=$("<div></div>");
				cell.append(div);*/
				addCellValue(elem,$("<div></div>"),c,matrix);
			});
		} else if (cell.type=="cards") {
			var marginLeft=matrix.img.width-matrix.img.cardwidth;
			cell.values.forEach(function(c) {
				marginLeftStr=c?` style="margin-left: -${marginLeft}px"`:"";
				elem.append(getCellImage(matrix.imgUrl,c,`${attributes}${marginLeftStr}`));
			});
		} else if (cell.type=='boolean') {
			elem.html(cell.value);
		} else if (cell.type=='matrix') {
			matrixDraw(elem,cell.value);
		}
	} else if (cell) {
		elem.html(getCellImage(matrix.imgUrl,cell,attributes));
	}
}

function attributesToString(attributes) {
	str=[];
	for (key in attributes) {
		str.push(`${key}="${attributes[key]}"`);
	}
	return str.join(" ");
}

function transformMatrix(elem,matrix) {
	var table=$("<table></table>");
	elem.html(table);
	if (matrix.class) {
		table.addClass("matrix-"+matrix.class);
	}
	matrix.matrix.forEach(function(line) {
		var tr=$('<tr></tr>');
		line.forEach(function(cell) {
			addCellValue(tr,$('<td></td>'),cell,matrix);
		});
		table.append(tr);
	});
}

function getMatrixImage(matrix,x,y) {
	var cell=matrix.matrix[y][x];
	return matrix.imgUrl+(isObject(cell)?cell.image:cell)+'.png';
}

function drawWinLines(elem,canvas,ctx,matrixElem,index) {
	var matrix=matrixElem.matrix;
	if (matrix.winLines.length>1) {
		setTimeout(function() {
			drawWinLines(elem,canvas,ctx,matrixElem,(index+1)%matrix.winLines.length);
		},2000);
	}
	if (!matrixElem.isIntersecting) {
		return;
	}
	drawImages(canvas,ctx,matrix,function() {	
		ctx.beginPath();
		ctx.lineWidth = "3";
		ctx.strokeStyle = winLineColors[index%winLineColors.length];
		getLine(ctx, matrix.winLines[index].combination, matrix.imgSize, matrix.imgSize);
		ctx.stroke();
		elem.find(".matrix-winline-amount").html(matrix.winLines[index].win);
		elem.find(".matrix-winline-count").html(`${index+1}/${matrix.winLines.length}`);
		for (let j = 0; j < matrix.winLines[index].combination.length; j++) {
			if (matrix.winLines[index].combination[j][2]) {
				ctx.strokeRect(matrix.imgSize * matrix.winLines[index].combination[j][0], matrix.imgSize * matrix.winLines[index].combination[j][1],matrix.imgSize,matrix.imgSize);
			}
		}
		ctx.closePath();
	});
}

function isObject(value) {
	return typeof value==='object' && value!=null;
}

function drawImages(canvas,ctx,matrix,func) {
	var count=0;
	for (var i=0;i<matrix.matrix.length;i++) {
		count+=matrix.matrix[i].length;
	}
	var imagesLoader=new ImagesLoader(function() {
		ctx.clearRect(0, 0, canvas.width, canvas.height);
		for (var j = 0; j < matrix.matrix.length; j++) {
			for (var i = 0; i < matrix.matrix[j].length; i++) {
				var src=getMatrixImage(matrix,i,j);
				if (this.isLoaded(src)) {
					ctx.drawImage(this.getImg(src), i * matrix.imgSize, j*matrix.imgSize, matrix.imgSize, matrix.imgSize);
				} else {
					ctx.lineWidth = "1";
					ctx.strokeStyle="#000";
					ctx.strokeRect(i * matrix.imgSize, j*matrix.imgSize, matrix.imgSize, matrix.imgSize);
				}
				if (isObject(matrix.matrix[j][i])) {
					text=matrix.matrix[j][i].value;
					ctx.lineWidth = "2";
					ctx.strokeStyle="black";
					ctx.strokeText(text,(i+1/2) * matrix.imgSize,(j+1/2) * matrix.imgSize);
					ctx.fillText(text,(i+1/2) * matrix.imgSize,(j+1/2) * matrix.imgSize);
				}
			}
		}
		if (func) {
			func();
		}
	},count);
	for (var j = 0; j < matrix.matrix.length; j++) {
		for (var i = 0; i < matrix.matrix[j].length; i++) {
			imagesLoader.addImage(getMatrixImage(matrix,i,j));
		}
	}
}

function matrixDraw(elem,matrix) {
	if (typeof matrix==="string") {
		try {
			matrix=JSON.parse(matrix);
		} catch(e) {

		}
	}
	if (!matrix.matrix) {
		return;
	}
	elem.html('');
	_matrixs.push({elem: elem,matrix: matrix});
	matrixObserver.observe(elem[0]);
}

function matrixObserve(elem,isIntersecting) {
	var matrixElem=_matrixs.find(function(e) {
		return e.elem.is(elem);
	});
	matrixElem.isIntersecting=isIntersecting;
	if (!isIntersecting) {
		return;
	}
	var matrix=matrixElem.matrix;
	if (!matrixElem.loaded) {
		matrixElem.loaded=true;

		if (matrix.matrix[0]) {
			if (!matrix.class || matrix.class=="slot") {
				var canvas=document.createElement('canvas');
				elem.html(canvas);
				canvas.setAttribute('width', matrix.imgSize*matrix.matrix[0].length);
				canvas.setAttribute('height', matrix.matrix.length*matrix.imgSize);
				$(canvas).click(function(e) {
					var x=Math.floor(e.offsetX/matrix.imgSize);
					var y=Math.floor(e.offsetY/matrix.imgSize);
					console.log(x,y,getMatrixImage(matrix,x,y));
				});
				// -------------------------------------------------------------------------------
				// Отрисовка изображений ----------------------------------------------------------------------
				var ctx = canvas.getContext("2d");
				ctx.textAlign = "center";
				ctx.textBaseline = 'middle';
				ctx.fillStyle="white";
				ctx.font = "bold 14px serif";
				// --------------------------------------------------------------------------------------------
				// Линии выигрыша ------------------------------------------------------------------------------------
				if (matrix.winLines) {
					elem.prepend("<div class='matrix-winline'><span class='matrix-winline-amount'></span><span class='matrix-winline-count'></span></div>");
					drawWinLines(elem,canvas,ctx,matrixElem,0);
				} else {
					drawImages(canvas,ctx,matrix);
				}
			} else {
				transformMatrix(elem,matrix);
			}
		}
		if (matrix.string) {
			elem.append(matrix.string);
		}
	}
}

/**
 * Функция отрисовки выигрышной линии.
 *
 * @param ctx
 * @param win_lines
 * @param width_img
 * @param height_img
 */
function getLine(ctx, win_lines, width_img, height_img) {
	ctx.moveTo(width_img * (0.5 + win_lines[0][0]), height_img * (0.5 + win_lines[0][1]));
	for (let i = 1; i < win_lines.length; i++) {
		ctx.lineTo(width_img * (0.5 + win_lines[i][0]), height_img * (0.5 + win_lines[i][1]));
	}
	//ctx.globalCompositeOperation = 'destination-over';
}

/**
 * Функция добавления атрибутов к тэгу из объекта свойств.
 *
 * @param tagName
 * @param arrAttr
 */
function setAttributesTag(tagName, arrAttr) {
	for(key in arrAttr) {
		tagName.setAttribute(key, arrAttr[key]);
	}
}

var matrixObserver = new IntersectionObserver(function (entries, observer) {
    for (var i = 0; i < entries.length; i++) {
        matrixObserve($(entries[i].target),entries[i].isIntersecting);
    }
}, {
    rootMargin: '0px',
    threshold: 0.1
});