include("display.js");

var shouldRenderWindows = true;

var rawModels = ModelManager.loadPartedRawModel(Resources.manager(), Resources.idRelative("mtr:682v/682v.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();

	state.brakeRateLimit = new RateLimit(0.25);
	state.brakeOldSpeed = train.speed();
	state.shouldRenderStopLights = false;

	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);
	updateStopSignals(train, state);
}

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["EXT"], carIndex, matrices);
	ctx.drawCarModel(models["SALON"], carIndex, matrices);
	ctx.drawCarModel(models["SALON_DETAIL"], carIndex, matrices);
	ctx.drawCarModel(models["GABARIT"], 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["WIN"], carIndex, matrices);

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

	{
		// FARY
		let shouldRenderLights = (MinecraftClient.worldDayTime() % 24000) > 12000;

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

		if (state.shouldRenderStopLights) {
			ctx.drawCarModel(models["STOP"], carIndex, matrices);
		}
	}
	

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

		}

		renderDoorWithChild(matrices, ctx, models["D1_R2_EXT"], models["D1_R1_EXT"], 
			models["D1_R2_INT"], models["D1_R1_INT"], models["D1_R2_WIN"], models["D1_R1_WIN"], 
			doorVal * -86, doorVal * 172, -1.207, 5.151, -1.226, 4.767, carIndex)


		renderDoorWithChild(matrices, ctx, models["D2_R2_EXT"], models["D2_R1_EXT"], 
			models["D2_R2_INT"], models["D2_R1_INT"], models["D2_R2_WIN"], models["D2_R1_WIN"], 
			doorVal * -86, doorVal * 172, -1.207, 1.312, -1.226, 0.9786, carIndex)
		renderDoorWithChild(matrices, ctx, models["D2_L2_EXT"], models["D2_L1_EXT"], 
			models["D2_L2_INT"], models["D2_L1_INT"], models["D2_L2_WIN"], models["D2_L1_WIN"], 
			doorVal * 86, doorVal * -172, -1.207, -0.07319, -1.226, 0.2599, carIndex)

		renderDoorWithChild(matrices, ctx, models["D3_R2_EXT"], models["D3_R1_EXT"], 
			models["D3_R2_INT"], models["D3_R1_INT"], models["D3_R2_WIN"], models["D3_R1_WIN"], 
			doorVal * -86, doorVal * 172, -1.207, -3.576, -1.226, -3.909, carIndex)
		renderDoorWithChild(matrices, ctx, models["D3_L2_EXT"], models["D3_L1_EXT"], 
			models["D3_L2_INT"], models["D3_L1_INT"], models["D3_L2_WIN"], models["D3_L1_WIN"], 
			doorVal * 86, doorVal * -172, -1.207, -4.962, -1.226, -4.629, 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 updateStopSignals(train, state) {
	if (state.brakeRateLimit.shouldUpdate()) {
		let oldSpeed = state.brakeOldSpeed;
		let speed	= train.speed();

		state.shouldRenderStopLights = speed < oldSpeed;

		state.brakeOldSpeed	= speed;
	}
}

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);
}

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;
	}
}
