include("display.js");

var shouldRenderWindows = true;

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

function create(ctx, state, train) {

	state.wheelAngle = 0;
	state.steeringAngle = 0.0;
	state.oldFirstCarTurnForSteering = train.lastCarRotation[0].y();

	displCreate(ctx, state, train)
}

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

function render(ctx, state, train) {
	updateLogic(state, train);
	renderLogic(ctx, state, train);

	displRender(ctx, state, train)
}

function updateLogic(state, train) {
	updateWheelAngle(train, state);
	updateSteeringAngle(train, state, 3.473, 0);

}

function renderLogic(ctx, state, train) {
	renderHead(ctx, state, train) 
}

function renderHead(ctx, state, train) {
	let matrices = new Matrices();
	let carIndex = 0;

	let coef = train.lastCarRotation[0].y() % (3.1415/2)
	if (coef > 3.1415 / 4) coef = 3.1415/2 - coef;
	coef = coef / (3.1415/4);

	ctx.drawCarModel(models["SHELL"], carIndex, matrices);
	ctx.drawCarModel(models["SALON"], carIndex, matrices);
	ctx.drawCarModel(models["LIGHT"], carIndex, matrices);
	ctx.drawCarModel(models["SALON_LIGHT"], carIndex, matrices);

	ctx.drawCarModel(models["POLE_R"], carIndex, matrices);

	matrices.pushPose();
	matrices.translate(0.2661, 0.0, -0.1565);
	matrices.rotateY(coef * 0.0475);
	matrices.translate(-0.2661, 0.0, 0.1565);
	
	ctx.drawCarModel(models["POLE_L"], carIndex, matrices);

	matrices.popPose();

	if (shouldRenderWindows) ctx.drawCarModel(models["WINDOW"], carIndex, matrices);

	
	{
	// WHEELS
		// front right
		const radius = 1.8;
		let steeringAngle = state.steeringAngle;
		matrices.pushPose();
		matrices.translate(-0.8484, -0.4343, 3.488);
		matrices.rotateY(steeringAngle);
		matrices.rotateX(state.wheelAngle * radius);
		matrices.translate(0.8484, 0.4343, -3.488);
	
		ctx.drawCarModel(models["WHEEL_R"], carIndex, matrices);
	
		matrices.popPose();
	
		matrices.pushPose();
		matrices.translate(0.8484, -0.4343, 3.488);
		matrices.rotateY(steeringAngle);
		matrices.rotateX(state.wheelAngle * radius);
		matrices.translate(-0.8484, 0.4343, -3.488);
	
		ctx.drawCarModel(models["WHEEL_L"], carIndex, matrices);
	
		matrices.popPose();
	
		// BACK WHEELS
		matrices.pushPose();
		matrices.translate(-0.8484, -0.4343, -2.731);
		matrices.rotateX(state.wheelAngle * radius);
		matrices.translate(0.8484, 0.4343, 2.731);
	
		ctx.drawCarModel(models["WHEEL2"], carIndex, matrices);
		
		matrices.popPose();
	}
	

	{
	// DOORS	
		// front
				let doorVal = 0.0;
		if (train.doorRightOpen[0]) {
			if (train.isDoorOpening()) {
				doorVal = smoothCubic(clamp(train.doorValue() * 1.3, 0.0, 1.0));
			} else {
				doorVal = smoothCubic(clamp(train.doorValue() * 1.8 - 0.7, 0.0, 1.0));
			}
		}


		renderDoorWithChild(matrices, ctx, null, models["FRE"], 
			null, models["FREI"], null, models["FRW"], 
			doorVal * -70, doorVal * 155, -1.166, 5.069, -1.166, 5.069 - 0.3, carIndex)
	
		// middle
		renderDoorWithChild(matrices, ctx, null, models["MRE"], 
			null, models["MREI"], null, models["MRW"], 
			doorVal * -75, doorVal * 155, -1.166, 1.106, -1.166, 1.106 - 0.3, carIndex)

		renderDoorWithChild(matrices, ctx, null, models["MLE"], 
			null, models["MLEI"], null, models["MLW"], 
			doorVal * 75, doorVal * -155, -1.166, -0.2613, -1.166, -0.2613 + 0.3, carIndex)

		// back
		renderDoorWithChild(matrices, ctx, null, models["BRE"], 
			null, models["BREI"], null, models["BRW"], 
			doorVal * -75, doorVal * 155, -1.166, -3.928, -1.166, -3.928 - 0.3, carIndex)

		renderDoorWithChild(matrices, ctx, null, models["BLE"], 
			null, models["BLEI"], null, models["BLW"], 
			doorVal * 75, doorVal * -155, -1.166, -5.308, -1.166, -5.308 + 0.3, carIndex)
	}
}




/////////////////////////////////////

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 && shouldRenderWindows) 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 && shouldRenderWindows) ctx.drawCarModel(parentWindow, i, matrices);
	matrices.popPose(); // родительская матрица лопается
}

//////////////////////////////

// ПОВОРОТ ВЕДУЩИХ КОЛЕС
function updateSteeringAngle(train, state, l, i) {
	if (Timing.delta() == 0.0) return;

	let delta = getCorrectDelta(train.lastCarRotation[i].y(), state.oldFirstCarTurnForSteering)
	if (delta == 0.0) {
		state.steeringAngle = 0.0;
		state.oldFirstCarTurnForSteering = train.lastCarRotation[i].y();
		return;
	}
	const coef = 0.0625;

	let radius = train.speed() * Timing.delta() / delta;
	let sin = clamp(coef * l / radius, -1.0, 1.0);

	if (train.isReversed()) sin *= -1;

	state.steeringAngle = Math.asin(sin);
	state.oldFirstCarTurnForSteering = train.lastCarRotation[i].y();
}




// ВРАЩЕНИE КОЛЕС
function updateWheelAngle(train, state) { 
	const angleLoop = 10000;

	// if (!train.shouldRenderDetail()) return 0;
	let speedMps = 20 * train.speed();
	let delta = Timing.delta();
	if (train.isReversed()) {
		state.wheelAngle -= speedMps * delta; 
	} else {
		state.wheelAngle += speedMps * delta; 
	}
	
	if (state.wheelAngle > angleLoop) state["wheelAngle"] = 0;
	if (state.wheelAngle < 0) state["wheelAngle"] = angleLoop;
}

function uploadPartedModels(rawModels, removeRenderType, invertUV) { 
  result = {};
  for (it = rawModels.entrySet().iterator(); it.hasNext(); ) {
    entry = it.next();

    let jsStringKey = "" + entry.getKey(); 
    if (jsStringKey.includes("__int__")) {
    	entry.getValue().setAllRenderType("interior"); //включение интерьера
    	if (removeRenderType) jsStringKey = jsStringKey.replace("__int__", '');

    } else if (jsStringKey.includes("__light__")) {
    	entry.getValue().setAllRenderType("light"); //включение света
    	if (removeRenderType) jsStringKey = jsStringKey.replace("__light__", '');

    } else if (jsStringKey.includes("__window__")) {
    	entry.getValue().setAllRenderType("exteriortranslucent"); //
    	if (removeRenderType) jsStringKey = jsStringKey.replace("__window__", '');

    } else if (jsStringKey.includes("__windowint__")) {
    	entry.getValue().setAllRenderType("interiortranslucent"); //
    	if (removeRenderType) jsStringKey = jsStringKey.replace("__windowint__", '');

    } 

    print("registering " + jsStringKey + "...");

    entry.getValue().applyUVMirror(false, invertUV);
    result[jsStringKey] = ModelManager.uploadVertArrays(entry.getValue());
  }
  return result;
}

function getCorrectDelta(angle1, angle2) {
  let delta = angle1 - angle2;
  if (Math.abs(delta) > Math.PI) {
    if(delta < 0) {
    	return Math.PI * 2 + delta
    } else {
    	return -Math.PI * 2 + delta
    }
  }
  return delta;
}

function clamp(num, min, max) {
	if (num > max) return max;
	if (num < min) return min;
	return num;
}

function smoothCubic(x) { //кубическая функция - в отрезке 0-1 возвращает сглаженную функцию 0-1
	return x*x*(-2*x + 3);
}
