include(Resources.idRelative("mtr:lib/harrys_lib.js"));
include("display.js");

var rawModels = ModelManager.loadPartedRawModel(Resources.manager(), Resources.idRelative("mtr:t6b5/tatrat6b5.obj"), null);
var models = uploadPartedModels(rawModels, true, true);


var grafCount = 6;

var rawModelsNums = ModelManager.loadPartedRawModel(Resources.manager(), Resources.idRelative("mtr:number/nums.obj"), null);
var modelNumt6b5 = uploadNumModels(rawModelsNums);

var rawModelsG = ModelManager.loadPartedRawModel(Resources.manager(), Resources.idRelative("mtr:t6b5/ad.obj"), null);
var adModel = uploadGrafModel(rawModelsG);

const doorCoef = 1.2;

function uploadGrafModel(rawModels) {
	let grafCnt = grafCount; 
	print("starting registering grafs");
	result = {};
	for (it = rawModels.entrySet().iterator(); it.hasNext(); ) {

		entry = it.next();
		let jsStringKey = "" + entry.getKey(); // строка в жс строку
		entry.getValue().applyUVMirror(false, true);
		result[jsStringKey] = {}
		let og = ModelManager.uploadVertArrays(entry.getValue());
		for (let i = 0; i < grafCnt; i++) {
			let copy = og.copyForMaterialChanges();
			copy.replaceAllTexture(Resources.idRelative("mtr:t6b5/ads/"+i+".png"))
			result[jsStringKey]["" + i] = copy;

		}
		print(jsStringKey)
		
		
	}
	
	return result;
}

function create(ctx, state, train) {
	displCreate(ctx, state, train);
	initWipers(state);
	initRocking(train, state);
	initWheelAngle(state);

	state.postCreateFunctionCalled = false;


	state.hasGraf = false;

	state.grafTypes = [];
	state.grafShouldBeArray = [];

	let random = new java.util.Random(train.id());

	for (let i = 0; i < train.trainCars(); i++) {
		// graffity vars
		state.grafTypes[i] = modPositive(random.nextInt(), grafCount);
		state.grafShouldBeArray[i] = modPositive(random.nextInt(), 10) > 3;
	}

	if (train.trainCars() >= 2 && !state.grafShouldBeArray[0] && !state.grafShouldBeArray[1]) {
		state.grafShouldBeArray[0] = true;
		state.grafShouldBeArray[1] = true;
	}

	state.number = (1000 + Math.abs(train.id() % 1000))
	state.postCreateFunctionCalled = false;
}


function dispose(ctx, state, train) {
	displDispose(ctx, state, train);
}

function render(ctx, state, train) {
	setPostcreateInfo(ctx, state, train); // train.siding() при вызове в функции create возвращает null, поэтому нужна доп. проверка.
	updateLogic(state, train);
	renderLogic(ctx, state, train);
	displRender(ctx, state, train);
}



function setPostcreateInfo(ctx, state, train) {
	if (train.siding() == null || state.postCreateFunctionCalled) {
		return;
	}
	let num = (Math.abs(parseInt(train.siding().name)) % 10000);

	state.hasGraf = false;
	state.number = isNaN(num) ? state.number : num;
	state.postCreateFunctionCalled = true;

}

function updateLogic(state, train) {
	updateRocking(train, state, 50, 50, 70, 70);
	updateWipers(train, state);
	updateWheelAngle(train, state);

}



function renderLogic(ctx, state, train) {
	let matrices = new Matrices();
	renderHead(ctx, state, train, 0, matrices)
	for (var i = 1; i < train.trainCars(); i++) {
		renderCart(ctx, state, train, i, matrices);
	}
}

function renderHead(ctx, state, train, i, matrices){
	// WHEELS
	let radius = 2.5;

	ctx.drawCarModel(models["bogies"], i, matrices);

	matrices.pushPose();
	matrices.translate(0, -0.4054, 4.820);
	matrices.rotateX(state.wheelAngle * radius);
	matrices.translate(0, 0.4054, -4.820);
	ctx.drawCarModel(models["wheel1"], i, matrices);
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(0, -0.4054, 2.816);
	matrices.rotateX(state.wheelAngle * radius);
	matrices.translate(0, 0.4054, -2.816);
	ctx.drawCarModel(models["wheel2"], i, matrices);
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(0, -0.4054, -2.747);
	matrices.rotateX(state.wheelAngle * radius);
	matrices.translate(0, 0.4054, 2.747);
	ctx.drawCarModel(models["wheel3"], i, matrices);
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(0, -0.4054, -4.747);
	matrices.rotateX(state.wheelAngle * radius);
	matrices.translate(0, 0.4054, 4.747);
	ctx.drawCarModel(models["wheel4"], i, matrices);
	matrices.popPose();

	// roll
	matrices.pushPose();

	let rollCoef = pseudoSin((state.rockingZCoef + i * 0.2) % 1.0);
	let speedCoef = clamp(train.speed() * 2 + 0.2, 0, 1);
	let totalCoef = rollCoef * speedCoef * 0.01 * (1 + state.curvyRailCoef * 1);
	matrices.rotateZ(totalCoef);
	// DISPLAY

	ctx.drawCarModel(state.dh.model, i, matrices);
	ctx.drawCarModel(state.dh2.model, i, matrices);

	// AD

	if (state.grafShouldBeArray[i]) {
		ctx.drawCarModel(adModel["ad"][state.grafTypes["" + i]], i, matrices);
	}

	// NUMBER
	matrices.pushPose();
	matrices.translate(0, 0.49, 7.59);
	matrices.rotateX(0.21);
	numRender(ctx, train, state, matrices, 0.15, i)
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(0, 0.49, -7.59);
	matrices.rotateX(-0.21);
	matrices.rotateY(3.141592);
	numRender(ctx, train, state, matrices, 0.15, i)
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(1.275, 0.49, 0.7);	
	matrices.rotateY(3.141592/2);
	numRender(ctx, train, state, matrices, 0.15, i)
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(-1.23, 0.49, 0.7);	
	matrices.rotateY(-3.141592/2);
	numRender(ctx, train, state, matrices, 0.15, i)
	matrices.popPose();
	// PANTO
	let pantoPolozOffset = -0.14;
	let pantoAngle1 = -0.08;
	let pantoAngle2 = 0.15;
	matrices.pushPose();
	matrices.translate(0,pantoPolozOffset,0);
	ctx.drawCarModel(models["pantpoloz"], i, matrices);
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(0, 2.458, 3.939);
	matrices.rotateX(-pantoAngle1);
	matrices.translate(0, -2.458, -3.939);
	ctx.drawCarModel(models["pantfd"], i, matrices);
	{
		matrices.pushPose();
		matrices.translate(0, 3.630, 4.696);
		matrices.rotateX(-pantoAngle2);
		matrices.translate(0, -3.630, -4.696);
		ctx.drawCarModel(models["pantfu"], i, matrices);
		matrices.popPose();
	}
	matrices.popPose();
	
	
	matrices.pushPose();
	matrices.translate(0, 2.458, 3.200);
	matrices.rotateX(pantoAngle1);
	matrices.translate(0, -2.458, -3.200);
	ctx.drawCarModel(models["pantbd"], i, matrices);
	{
		matrices.pushPose();
		matrices.translate(0, 3.630, 2.440);
		matrices.rotateX(pantoAngle2);
		matrices.translate(0, -3.630, -2.440);
		ctx.drawCarModel(models["pantbu"], i, matrices);
		matrices.popPose();
	}
	matrices.popPose();

	// KUZOV

	ctx.drawCarModel(models["ext"], i, matrices);
	ctx.drawCarModel(models["int"], i, matrices);
	ctx.drawCarModel(models["lamp"], i, matrices);

	// LIGHTS

	let shouldRenderLights = MinecraftClient.worldDayTime() % 24000 >= 13000;

	if (shouldRenderLights) {
		ctx.drawCarModel(models["fary"], i, matrices);
		ctx.drawCarModel(models["gabarity"], i, matrices);
	}
	// WIPERS

	let wcoef = state.wipeCoef;

	matrices.pushPose();
	matrices.translate(-0.3532, 0.8979, 7.582);
	matrices.rotate(0,0.155,0.988, -1.5*wipFunc(wcoef));
	matrices.translate(0.3532, -0.8979, -7.582);
	ctx.drawCarModel(models["dvor1"], i, matrices);
	{
		matrices.pushPose();
		matrices.translate(-0.7627, 1.305, 7.518);
		matrices.rotate(0,0.155,0.988, 1.5*wipFunc(wcoef));
		matrices.translate(0.7627, -1.305, -7.518);
		ctx.drawCarModel(models["dvor11"], i, matrices);
		matrices.popPose();
	}
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(0.4115, 0.8979, 7.582);
	matrices.rotate(0,0.155,0.988, -1.5*wipFunc(wcoef));
	matrices.translate(-0.4115, -0.8979, -7.582);
	ctx.drawCarModel(models["dvor2"], i, matrices);
	{
		matrices.pushPose();
		matrices.translate(0, 1.305, 7.517);
		matrices.rotate(0,0.155,0.988, 1.5*wipFunc(wcoef));
		matrices.translate(0, -1.305, -7.517);
		ctx.drawCarModel(models["dvor21"], i, matrices);
		matrices.popPose();
	}
	matrices.popPose();

	// DOORS
	let valClamped = clamp(train.doorValue() * doorCoef, 0, 1)
	let doorVal = 0.0; 
	if (train.doorRightOpen[i]) {
		doorVal = clamp(valClamped * 1.0, 0.0, 1.0);
		if (train.isDoorOpening()){
			doorVal = shirmaCoolAnimationOpen(doorVal);
		} else {
			doorVal = clamp(valClamped * 1.5 - 0.35, 0.0, 1.0);
			doorVal = smoothCubic(doorVal) * 0.9;
		}
	}

	renderDoorWithChild(matrices, ctx, models["doorrl1"], models["doorrr1"], models["doorrl1i"], models["doorrr1i"], 
		null, null, -85*doorVal, 170*doorVal, -1.155, 6.731, -1.191, 6.368, i)
	renderDoorWithChild(matrices, ctx, models["doorll1"], models["doorlr1"], models["doorll1i"], models["doorlr1i"], 
		null, null, 85*doorVal, -170*doorVal, -1.191, 5.290, -1.206, 5.656, i)

	renderDoorWithChild(matrices, ctx, models["doorrl2"], models["doorrr2"], models["doorrl2i"], models["doorrr2i"], 
		null, null, -85*doorVal, 170*doorVal, -1.195, -0.1511, -1.221, -0.5131, i)
	renderDoorWithChild(matrices, ctx, models["doorll2"], models["doorlr2"], models["doorll2i"], models["doorlr2i"], 
		null, null, 85*doorVal, -170*doorVal, -1.221, -1.577, -1.195, -1.220, i)

	renderDoorWithChild(matrices, ctx, models["doorll3"], models["doorlr3"], models["doorll3i"], models["doorlr3i"], 
		null, null, -85*doorVal, 170*doorVal, -1.186, -5.330, -1.205, -5.696, i)
	renderDoorWithChild(matrices, ctx, models["doorrl3"], models["doorrr3"], models["doorrl3i"], models["doorrr3i"], 
		null, null, 85*doorVal, -170*doorVal, -1.156, -6.771, -1.190, -6.404, i)

	matrices.popPose();
}

function renderCart(ctx, state, train, i, matrices){
	// WHEELS
	let radius = 2.5;

	ctx.drawCarModel(models["bogies"], i, matrices);

	matrices.pushPose();
	matrices.translate(0, -0.4054, 4.820);
	matrices.rotateX(state.wheelAngle * radius);
	matrices.translate(0, 0.4054, -4.820);
	ctx.drawCarModel(models["wheel1"], i, matrices);
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(0, -0.4054, 2.816);
	matrices.rotateX(state.wheelAngle * radius);
	matrices.translate(0, 0.4054, -2.816);
	ctx.drawCarModel(models["wheel2"], i, matrices);
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(0, -0.4054, -2.747);
	matrices.rotateX(state.wheelAngle * radius);
	matrices.translate(0, 0.4054, 2.747);
	ctx.drawCarModel(models["wheel3"], i, matrices);
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(0, -0.4054, -4.747);
	matrices.rotateX(state.wheelAngle * radius);
	matrices.translate(0, 0.4054, 4.747);
	ctx.drawCarModel(models["wheel4"], i, matrices);
	matrices.popPose();

	// roll
	matrices.pushPose();

	let rollCoef = pseudoSin((state.rockingZCoef + i * 0.2) % 1.0);
	let speedCoef = clamp(train.speed() * 2 + 0.2, 0, 1);
	let totalCoef = rollCoef * speedCoef * 0.01 * (1 + state.curvyRailCoef * 1);
	matrices.rotateZ(totalCoef);
	// DISPLAY

	ctx.drawCarModel(state.dh2.model, i, matrices);

	// AD

	if (state.grafShouldBeArray[i]) {
		ctx.drawCarModel(adModel["ad"][state.grafTypes["" + i]], i, matrices);
	}

	// PANTO
	let pantoPolozOffset = -2.1;
	let pantoAngle1 = -0.85;
	let pantoAngle2 = 1.6;
	matrices.pushPose();
	matrices.translate(0,pantoPolozOffset,0);
	ctx.drawCarModel(models["pantpoloz"], i, matrices);
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(0, 2.458, 3.939);
	matrices.rotateX(-pantoAngle1);
	matrices.translate(0, -2.458, -3.939);
	ctx.drawCarModel(models["pantfd"], i, matrices);
	{
		matrices.pushPose();
		matrices.translate(0, 3.630, 4.696);
		matrices.rotateX(-pantoAngle2);
		matrices.translate(0, -3.630, -4.696);
		ctx.drawCarModel(models["pantfu"], i, matrices);
		matrices.popPose();
	}
	matrices.popPose();
	
	
	matrices.pushPose();
	matrices.translate(0, 2.458, 3.200);
	matrices.rotateX(pantoAngle1);
	matrices.translate(0, -2.458, -3.200);
	ctx.drawCarModel(models["pantbd"], i, matrices);
	{
		matrices.pushPose();
		matrices.translate(0, 3.630, 2.440);
		matrices.rotateX(pantoAngle2);
		matrices.translate(0, -3.630, -2.440);
		ctx.drawCarModel(models["pantbu"], i, matrices);
		matrices.popPose();
	}
	matrices.popPose();

	// KUZOV

	ctx.drawCarModel(models["ext"], i, matrices);
	ctx.drawCarModel(models["int"], i, matrices);
	ctx.drawCarModel(models["lamp"], i, matrices);

	// NUMBER
	matrices.pushPose();
	matrices.translate(0, 0.49, 7.59);
	matrices.rotateX(0.21);
	numRender(ctx, train, state, matrices, 0.15, i)
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(0, 0.49, -7.59);
	matrices.rotateX(-0.21);
	matrices.rotateY(3.141592);
	numRender(ctx, train, state, matrices, 0.15, i)
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(1.275, 0.49, 0.7);	
	matrices.rotateY(3.141592/2);
	numRender(ctx, train, state, matrices, 0.15, i)
	matrices.popPose();

	matrices.pushPose();
	matrices.translate(-1.23, 0.49, 0.7);	
	matrices.rotateY(-3.141592/2);
	numRender(ctx, train, state, matrices, 0.15, i)
	matrices.popPose();
	// LIGHTS

	let shouldRenderLights = MinecraftClient.worldDayTime() % 24000 >= 13000;

	if (shouldRenderLights) {
		ctx.drawCarModel(models["gabarity"], i, matrices);
	}

	// DOORS
	let valClamped = clamp(train.doorValue() * doorCoef, 0, 1)
	let doorVal = 0.0; 
	if (train.doorRightOpen[i]) {
		doorVal = clamp(valClamped * 1.0, 0.0, 1.0);
		if (train.isDoorOpening()){
			doorVal = shirmaCoolAnimationOpen(doorVal);
		} else {
			doorVal = clamp(valClamped * 1.5 - 0.35, 0.0, 1.0);
			doorVal = smoothCubic(doorVal) * 0.9;
		}
	}

	renderDoorWithChild(matrices, ctx, models["doorrl1"], models["doorrr1"], models["doorrl1i"], models["doorrr1i"], 
		null, null, -85*doorVal, 170*doorVal, -1.155, 6.731, -1.191, 6.368, i)
	renderDoorWithChild(matrices, ctx, models["doorll1"], models["doorlr1"], models["doorll1i"], models["doorlr1i"], 
		null, null, 85*doorVal, -170*doorVal, -1.191, 5.290, -1.206, 5.656, i)

	renderDoorWithChild(matrices, ctx, models["doorrl2"], models["doorrr2"], models["doorrl2i"], models["doorrr2i"], 
		null, null, -85*doorVal, 170*doorVal, -1.195, -0.1511, -1.221, -0.5131, i)
	renderDoorWithChild(matrices, ctx, models["doorll2"], models["doorlr2"], models["doorll2i"], models["doorlr2i"], 
		null, null, 85*doorVal, -170*doorVal, -1.221, -1.577, -1.195, -1.220, i)

	renderDoorWithChild(matrices, ctx, models["doorll3"], models["doorlr3"], models["doorll3i"], models["doorlr3i"], 
		null, null, -85*doorVal, 170*doorVal, -1.186, -5.330, -1.205, -5.696, i)
	renderDoorWithChild(matrices, ctx, models["doorrl3"], models["doorrr3"], models["doorrl3i"], models["doorrr3i"], 
		null, null, 85*doorVal, -170*doorVal, -1.156, -6.771, -1.190, -6.404, i)




	/// WIPERS

	ctx.drawCarModel(models["dvor21"], i, matrices);
	ctx.drawCarModel(models["dvor11"], i, matrices);
	ctx.drawCarModel(models["dvor1"], i, matrices);
	ctx.drawCarModel(models["dvor2"], i, matrices);

	matrices.popPose();
}

function renderDoorWithChild(matrices, ctx, parentDoor, childDoor, parentInt, childInt, parentWindow, childIWindow, firstAngle, secondAngle, x1, z1, x2, z2, i) {
	firstAngle = firstAngle / 180.0 * 3.1415;
	secondAngle = secondAngle / 180.0 * 3.1415;

	matrices.pushPose(); // пушим родительскую матрицу в стек
	matrices.translate(x1, 0.0, z1);
	matrices.rotate(0.0, 1.0, 0.0, firstAngle); // поворот двери. Смотри самый нижний комментарий для пояснения 
	matrices.translate(-x1, 0.0, -z1);	
	{
		matrices.pushPose();	// пуш матрицы дочерней
		matrices.translate(x2, 0.0, z2);
		matrices.rotate(0.0, 1.0, 0.0, secondAngle); // поворот
		matrices.translate(-x2, 0.0, -z2);		
		if (childDoor != null) ctx.drawCarModel(childDoor, i, matrices); // рендер внутренней ширмы либо двери
		if (childInt != null) ctx.drawCarModel(childInt, i, matrices);
		if (childIWindow != null) ctx.drawCarModel(childIWindow, i, matrices);
		matrices.popPose(); // дочерняя матрица лопается
	}
	if (parentDoor != null) ctx.drawCarModel(parentDoor, i, matrices); // рендер крайней ширмы либо механизма двери
	if (parentInt != null) ctx.drawCarModel(parentInt, i, matrices);
	if (parentWindow != null) ctx.drawCarModel(parentWindow, i, matrices);
	matrices.popPose(); // родительская матрица лопается

}



function shirmaCoolAnimationOpen(x) {
	if (x < 0.66) {
		return 1.561 * x * x + 0.485 * x;
	} else {
		return 0.939 * x * x - 1.8538 * x + 1.8142;
	}
}

function numRender(ctx, train, state, matrices, offset, carInd) {
	let id = state.number === undefined ? 0 : state.number;

	id = (state.number + carInd) % 10000;

	const numOfDigits = 4;
	
	let idStr = id.toString().padStart(numOfDigits, '0');

	let firstOffset = offset * 0.5 * (- numOfDigits + 1);

	// matrices.pushPose();
	for (var i = 0; i < numOfDigits; i++) {
		matrices.translate(firstOffset + i * offset, 0, 0);
		ctx.drawCarModel(modelNumt6b5["" + idStr[i]], carInd, matrices);
		matrices.translate(-(firstOffset + i * offset), 0, 0);
	}
	// matrices.popPose();
}

function uploadNumModels(rawModels) { 
	result = {};
	for (it = rawModels.entrySet().iterator(); it.hasNext(); ) {
		entry = it.next();

		let jsStringKey = "" + entry.getKey(); 
		entry.getValue().applyUVMirror(false, true);
		result[jsStringKey] = ModelManager.uploadVertArrays(entry.getValue());
		result[jsStringKey] = result[jsStringKey].copyForMaterialChanges();
		result[jsStringKey].replaceAllTexture(Resources.idRelative("mtr:t6b5/bortnums.png"))
	}
	return result;
}