/***************************************************************************
 *   Copyright (C) 2008 by Max-Wilhelm Bruker   *
 *   brukie@laptop   *
 *                                                                         *
 *   This program 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; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef SERVER_CARDZONE_H
#define SERVER_CARDZONE_H

#include <QMap>
#include <QSet>
#include <QString>
#include <libcockatrice/protocol/pb/serverinfo_zone.pb.h>

class Server_Card;
class Server_AbstractPlayer;
class Server_AbstractParticipant;
class Server_Game;
class GameEventStorage;

class Server_CardZone
{
private:
    Server_AbstractPlayer *player;
    QString name;
    bool has_coords; // having coords means this zone has x and y coordinates
    ServerInfo_Zone::ZoneType type;
    int cardsBeingLookedAt;
    QSet<int> playersWithWritePermission;
    bool alwaysRevealTopCard;
    bool alwaysLookAtTopCard;
    QList<Server_Card *> cards;
    QMap<int, QMap<int, Server_Card *>> coordinateMap; // y -> (x -> card)
    QMap<int, QMultiMap<QString, int>> freePilesMap;   // y -> (cardName -> x)
    QMap<int, int> freeSpaceMap;                       // y -> x
    void removeCardFromCoordMap(Server_Card *card, int oldX, int oldY);
    void insertCardIntoCoordMap(Server_Card *card, int x, int y);

public:
    Server_CardZone(Server_AbstractPlayer *_player,
                    const QString &_name,
                    bool _has_coords,
                    ServerInfo_Zone::ZoneType _type);
    ~Server_CardZone();

    [[nodiscard]] const QList<Server_Card *> &getCards() const
    {
        return cards;
    }
    int removeCard(Server_Card *card);
    int removeCard(Server_Card *card, bool &wasLookedAt);
    Server_Card *getCard(int id, int *position = nullptr, bool remove = false);

    [[nodiscard]] int getCardsBeingLookedAt() const
    {
        return cardsBeingLookedAt;
    }
    void setCardsBeingLookedAt(int _cardsBeingLookedAt)
    {
        cardsBeingLookedAt = qMax(0, _cardsBeingLookedAt);
    }
    [[nodiscard]] bool isCardAtPosLookedAt(int pos) const;
    [[nodiscard]] bool hasCoords() const
    {
        return has_coords;
    }
    [[nodiscard]] ServerInfo_Zone::ZoneType getType() const
    {
        return type;
    }
    [[nodiscard]] QString getName() const
    {
        return name;
    }
    [[nodiscard]] Server_AbstractPlayer *getPlayer() const
    {
        return player;
    }
    void getInfo(ServerInfo_Zone *info, Server_AbstractParticipant *recipient, bool omniscient);

    [[nodiscard]] int getFreeGridColumn(int x, int y, const QString &cardName, bool dontStackSameName) const;
    [[nodiscard]] bool isColumnEmpty(int x, int y) const;
    [[nodiscard]] bool isColumnStacked(int x, int y) const;
    void fixFreeSpaces(GameEventStorage &ges);
    void moveCardInRow(GameEventStorage &ges, Server_Card *card, int x, int y);
    void insertCard(Server_Card *card, int x, int y);
    void updateCardCoordinates(Server_Card *card, int oldX, int oldY);
    void shuffle(int start = 0, int end = -1);
    void clear();
    void addWritePermission(int playerId);
    [[nodiscard]] const QSet<int> &getPlayersWithWritePermission() const
    {
        return playersWithWritePermission;
    }
    [[nodiscard]] bool getAlwaysRevealTopCard() const
    {
        return alwaysRevealTopCard;
    }
    void setAlwaysRevealTopCard(bool _alwaysRevealTopCard)
    {
        alwaysRevealTopCard = _alwaysRevealTopCard;
    }
    [[nodiscard]] bool getAlwaysLookAtTopCard() const
    {
        return alwaysLookAtTopCard;
    }
    void setAlwaysLookAtTopCard(bool _alwaysLookAtTopCard)
    {
        alwaysLookAtTopCard = _alwaysLookAtTopCard;
    }
};

#endif
