/*****************************************************************************
 * Copyright (c) 2014-2026 OpenRCT2 developers
 *
 * For a complete list of all authors, please refer to contributors.md
 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
 *
 * OpenRCT2 is licensed under the GNU General Public License version 3.
 *****************************************************************************/

#include "WallObject.h"

#include "../core/Guard.hpp"
#include "../core/IStream.hpp"
#include "../core/Json.hpp"
#include "../core/String.hpp"
#include "../drawing/Drawing.h"
#include "../drawing/ScrollingText.h"
#include "../interface/Cursors.h"
#include "../localisation/Language.h"

namespace OpenRCT2
{
    void WallObject::ReadLegacy(IReadObjectContext* context, IStream* stream)
    {
        stream->Seek(6, STREAM_SEEK_CURRENT);
        _legacyType.tool_id = static_cast<CursorID>(stream->ReadValue<uint8_t>());
        _legacyType.flags = stream->ReadValue<uint8_t>();
        _legacyType.height = stream->ReadValue<uint8_t>();
        _legacyType.flags2 = stream->ReadValue<uint8_t>();
        _legacyType.price = stream->ReadValue<money16>();
        _legacyType.scenery_tab_id = kObjectEntryIndexNull;
        stream->Seek(1, STREAM_SEEK_CURRENT);
        _legacyType.scrolling_mode = stream->ReadValue<uint8_t>();

        GetStringTable().Read(context, stream, ObjectStringID::name);

        RCTObjectEntry sgEntry = stream->ReadValue<RCTObjectEntry>();
        SetPrimarySceneryGroup(ObjectEntryDescriptor(sgEntry));

        GetImageTable().Read(context, stream);

        // Validate properties
        if (_legacyType.price <= 0.00_GBP)
        {
            context->LogError(ObjectError::invalidProperty, "Price can not be free or negative.");
        }

        // Autofix this object (will be turned into an official object later).
        auto identifier = GetLegacyIdentifier();
        if (identifier == "XXWLBR03")
        {
            _legacyType.flags2 &= ~WALL_SCENERY_2_DOOR_SOUND_MASK;
            _legacyType.flags2 |= (1u << WALL_SCENERY_2_DOOR_SOUND_SHIFT) & WALL_SCENERY_2_DOOR_SOUND_MASK;
        }
    }

    void WallObject::Load()
    {
        GetStringTable().Sort();
        _legacyType.name = LanguageAllocateObjectString(GetName());
        _legacyType.image = LoadImages();
    }

    void WallObject::Unload()
    {
        LanguageFreeObjectString(_legacyType.name);
        UnloadImages();

        _legacyType.name = 0;
        _legacyType.image = 0;
    }

    void WallObject::DrawPreview(Drawing::RenderTarget& rt, int32_t width, int32_t height) const
    {
        auto screenCoords = ScreenCoordsXY{ width / 2, height / 2 };

        screenCoords.x += 14;
        screenCoords.y += (_legacyType.height * 2) + 16;

        auto imageId = ImageId(_legacyType.image, Drawing::Colour::bordeauxRed);
        if (_legacyType.flags & WALL_SCENERY_HAS_SECONDARY_COLOUR)
        {
            imageId = imageId.WithSecondary(Drawing::Colour::yellow);
        }

        GfxDrawSprite(rt, imageId, screenCoords);

        if (_legacyType.flags & WALL_SCENERY_HAS_GLASS)
        {
            auto glassImageId = imageId.WithTransparency(Drawing::Colour::bordeauxRed).WithIndexOffset(6);
            GfxDrawSprite(rt, glassImageId, screenCoords);
        }
        else if (_legacyType.flags & WALL_SCENERY_IS_DOOR)
        {
            GfxDrawSprite(rt, imageId.WithIndexOffset(1), screenCoords);
        }
    }

    void WallObject::ReadJson(IReadObjectContext* context, json_t& root)
    {
        Guard::Assert(root.is_object(), "WallObject::ReadJson expects parameter root to be object");

        auto properties = root["properties"];

        if (properties.is_object())
        {
            _legacyType.tool_id = Cursor::FromString(Json::GetString(properties["cursor"]), CursorID::FenceDown);
            _legacyType.height = Json::GetNumber<uint8_t>(properties["height"]);
            _legacyType.price = Json::GetNumber<money64>(properties["price"]);

            _legacyType.scrolling_mode = Json::GetNumber<uint8_t>(properties["scrollingMode"], kScrollingModeNone);

            SetPrimarySceneryGroup(ObjectEntryDescriptor(Json::GetString(properties["sceneryGroup"])));

            // clang-format off
        _legacyType.flags = Json::GetFlags<uint8_t>(
            properties,
            {
                { "hasPrimaryColour",       WALL_SCENERY_HAS_PRIMARY_COLOUR,    Json::FlagType::Normal },
                { "isAllowedOnSlope",       WALL_SCENERY_CANT_BUILD_ON_SLOPE,   Json::FlagType::Inverted },
                { "hasSecondaryColour",     WALL_SCENERY_HAS_SECONDARY_COLOUR,  Json::FlagType::Normal },
                { "hasTertiaryColour",      WALL_SCENERY_HAS_TERTIARY_COLOUR,   Json::FlagType::Normal },
                { "hasTernaryColour",       WALL_SCENERY_HAS_TERTIARY_COLOUR,   Json::FlagType::Normal },
                { "hasGlass",               WALL_SCENERY_HAS_GLASS,             Json::FlagType::Normal },
                { "isBanner",               WALL_SCENERY_IS_DOUBLE_SIDED,       Json::FlagType::Normal },
                { "isDoubleSided",          WALL_SCENERY_IS_DOUBLE_SIDED,       Json::FlagType::Normal },
                { "isDoor",                 WALL_SCENERY_IS_DOOR,               Json::FlagType::Normal },
                { "isLongDoorAnimation",    WALL_SCENERY_LONG_DOOR_ANIMATION,   Json::FlagType::Normal },
            });
            // clang-format on

            _legacyType.flags2 = Json::GetFlags<uint8_t>(
                properties,
                {
                    { "isOpaque", WALL_SCENERY_2_IS_OPAQUE },
                    { "isAnimated", WALL_SCENERY_2_ANIMATED },
                });

            // HACK WALL_SCENERY_HAS_PRIMARY_COLOUR actually means, has any colour but we simplify the
            //      JSON and handle this on load. We should change code base in future to reflect the JSON.
            if (!(_legacyType.flags & WALL_SCENERY_HAS_PRIMARY_COLOUR))
            {
                if (_legacyType.flags & (WALL_SCENERY_HAS_SECONDARY_COLOUR | WALL_SCENERY_HAS_TERTIARY_COLOUR))
                {
                    _legacyType.flags |= WALL_SCENERY_HAS_PRIMARY_COLOUR;
                    _legacyType.flags2 |= WALL_SCENERY_2_NO_SELECT_PRIMARY_COLOUR;
                }
            }

            // Door sound
            auto jDoorSound = properties["doorSound"];
            if (jDoorSound.is_number())
            {
                auto doorSound = Json::GetNumber<uint8_t>(jDoorSound);
                _legacyType.flags2 |= (doorSound << WALL_SCENERY_2_DOOR_SOUND_SHIFT) & WALL_SCENERY_2_DOOR_SOUND_MASK;
            }
        }

        PopulateTablesFromJson(context, root);
    }
} // namespace OpenRCT2
