/*
 * This file is part of OpenTTD.
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
 */

/** @file tunnelbridge_map.h Functions that have tunnels and bridges in common. */

#ifndef TUNNELBRIDGE_MAP_H
#define TUNNELBRIDGE_MAP_H

#include "bridge_map.h"
#include "tunnel_map.h"


/**
 * Get the direction pointing to the other end.
 *
 * Tunnel: Get the direction facing into the tunnel
 * Bridge: Get the direction pointing onto the bridge
 * @param t The tile to analyze
 * @pre IsTileType(t, TileType::TunnelBridge)
 * @return the above mentioned direction
 */
inline DiagDirection GetTunnelBridgeDirection(Tile t)
{
	assert(IsTileType(t, TileType::TunnelBridge));
	return (DiagDirection)GB(t.m5(), 0, 2);
}

/**
 * Tunnel: Get the transport type of the tunnel (road or rail)
 * Bridge: Get the transport type of the bridge's ramp
 * @param t The tile to analyze
 * @pre IsTileType(t, TileType::TunnelBridge)
 * @return the transport type in the tunnel/bridge
 */
inline TransportType GetTunnelBridgeTransportType(Tile t)
{
	assert(IsTileType(t, TileType::TunnelBridge));
	return (TransportType)GB(t.m5(), 2, 2);
}

/**
 * Tunnel: Is this tunnel entrance in a snowy or desert area?
 * Bridge: Does the bridge ramp lie in a snow or desert area?
 * @param t The tile to analyze
 * @pre IsTileType(t, TileType::TunnelBridge)
 * @return true if and only if the tile is in a snowy/desert area
 */
inline bool HasTunnelBridgeSnowOrDesert(Tile t)
{
	assert(IsTileType(t, TileType::TunnelBridge));
	return HasBit(t.m7(), 5);
}

/**
 * Tunnel: Places this tunnel entrance in a snowy or desert area, or takes it out of there.
 * Bridge: Sets whether the bridge ramp lies in a snow or desert area.
 * @param t the tunnel entrance / bridge ramp tile
 * @param snow_or_desert is the entrance/ramp in snow or desert (true), when
 *                       not in snow and not in desert false
 * @pre IsTileType(t, TileType::TunnelBridge)
 */
inline void SetTunnelBridgeSnowOrDesert(Tile t, bool snow_or_desert)
{
	assert(IsTileType(t, TileType::TunnelBridge));
	SB(t.m7(), 5, 1, snow_or_desert);
}

/**
 * Determines type of the wormhole and returns its other end
 * @param t one end
 * @pre IsTileType(t, TileType::TunnelBridge)
 * @return other end
 */
inline TileIndex GetOtherTunnelBridgeEnd(Tile t)
{
	assert(IsTileType(t, TileType::TunnelBridge));
	return IsTunnel(t) ? GetOtherTunnelEnd(t) : GetOtherBridgeEnd(t);
}


/**
 * Get the reservation state of the rail tunnel/bridge
 * @pre IsTileType(t, TileType::TunnelBridge) && GetTunnelBridgeTransportType(t) == TransportType::Rail
 * @param t the tile
 * @return reservation state
 */
inline bool HasTunnelBridgeReservation(Tile t)
{
	assert(IsTileType(t, TileType::TunnelBridge));
	assert(GetTunnelBridgeTransportType(t) == TransportType::Rail);
	return HasBit(t.m5(), 4);
}

/**
 * Set the reservation state of the rail tunnel/bridge
 * @pre IsTileType(t, TileType::TunnelBridge) && GetTunnelBridgeTransportType(t) == TransportType::Rail
 * @param t the tile
 * @param b the reservation state
 */
inline void SetTunnelBridgeReservation(Tile t, bool b)
{
	assert(IsTileType(t, TileType::TunnelBridge));
	assert(GetTunnelBridgeTransportType(t) == TransportType::Rail);
	AssignBit(t.m5(), 4, b);
}

/**
 * Get the reserved track bits for a rail tunnel/bridge
 * @pre IsTileType(t, TileType::TunnelBridge) && GetTunnelBridgeTransportType(t) == TransportType::Rail
 * @param t the tile
 * @return reserved track bits
 */
inline TrackBits GetTunnelBridgeReservationTrackBits(Tile t)
{
	return HasTunnelBridgeReservation(t) ? DiagDirToDiagTrack(GetTunnelBridgeDirection(t)) : TrackBits{};
}

#endif /* TUNNELBRIDGE_MAP_H */
