/*
    This file is part of the TDE games library
    Copyright (C) 2001-2004 Nicolas Hadacek (hadacek@kde.org)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#ifndef KEXTHIGHSCORE_INTERNAL_H
#define KEXTHIGHSCORE_INTERNAL_H

#include <tdeapplication.h>
#include <tdeconfig.h>
#include <tdelocale.h>
#include <kurl.h>

#include "khighscore.h"
#include "kexthighscore.h"

class TQTextStream;
class TQTabWidget;
class TQDomNamedNodeMap;


namespace KExtHighscore
{

class PlayerInfos;
class Score;
class Manager;


//-----------------------------------------------------------------------------
class RankItem : public Item
{
 public:
    RankItem()
        : Item((uint)0, i18n("Rank"), TQt::AlignRight) {}

    TQVariant read(uint rank, const TQVariant &) const  { return rank; }
    TQString pretty(uint rank, const TQVariant &) const
        { return TQString::number(rank+1); }
};

class NameItem : public Item
{
 public:
    NameItem()
        : Item(TQString(), i18n("Name"), TQt::AlignLeft) {
            setPrettySpecial(Anonymous);
    }
};

class DateItem : public Item
{
 public:
    DateItem()
        : Item(TQDateTime(), i18n("Date"), TQt::AlignRight) {
            setPrettyFormat(DateTime);
    }
};

class SuccessPercentageItem : public Item
{
 public:
    SuccessPercentageItem()
        : Item((double)-1, i18n("Success"), TQt::AlignRight) {
            setPrettyFormat(Percentage);
            setPrettySpecial(NegativeNotDefined);
    }
};

//-----------------------------------------------------------------------------
class ItemContainer
{
 public:
    ItemContainer();
    ~ItemContainer();

    void setItem(Item *item);
    const Item *item() const { return _item; }
    Item *item() { return _item; }

    void setName(const TQString &name) { _name = name; }
    TQString name() const { return _name; }

    void setGroup(const TQString &group) { _group = group; }
    bool isStored() const { return !_group.isNull(); }

    void setSubGroup(const TQString &subGroup) { _subGroup = subGroup; }
    bool canHaveSubGroup() const { return !_subGroup.isNull(); }

    static const char ANONYMOUS[]; // name assigned to anonymous players
    static const char ANONYMOUS_LABEL[];

    TQVariant read(uint i) const;
    TQString pretty(uint i) const;
    void write(uint i, const TQVariant &value) const;
    // for UInt TQVariant (return new value)
    uint increment(uint i) const;

 private:
    Item    *_item;
    TQString  _name, _group, _subGroup;

    TQString entryName() const;

    ItemContainer(const ItemContainer &);
    ItemContainer &operator =(const ItemContainer &);
};

//-----------------------------------------------------------------------------
/**
 * Manage a bunch of @ref Item which are saved under the same group
 * in KHighscores config file.
 */
class ItemArray : public TQMemArray<ItemContainer *>
{
 public:
    ItemArray();
    virtual ~ItemArray();

    virtual uint nbEntries() const = 0;

    const ItemContainer *item(const TQString &name) const;
    ItemContainer *item(const TQString &name);

    void addItem(const TQString &name, Item *, bool stored = true,
                 bool canHaveSubGroup = false);
    void setItem(const TQString &name, Item *);
    int findIndex(const TQString &name) const;

    void setGroup(const TQString &group);
    void setSubGroup(const TQString &subGroup);

    void read(uint k, Score &data) const;
    void write(uint k, const Score &data, uint maxNbLines) const;

    void exportToText(TQTextStream &) const;

 private:
    TQString _group, _subGroup;

    void _setItem(uint i, const TQString &name, Item *, bool stored,
                  bool canHaveSubGroup);

    ItemArray(const ItemArray &);
    ItemArray &operator =(const ItemArray &);
};

//-----------------------------------------------------------------------------
class ScoreInfos : public ItemArray
{
 public:
    ScoreInfos(uint maxNbEntries, const PlayerInfos &infos);

    uint nbEntries() const;
    uint maxNbEntries() const { return _maxNbEntries; }

 private:
    uint _maxNbEntries;
};

//-----------------------------------------------------------------------------
class ConfigGroup : public TDEConfigGroupSaver
{
 public:
    ConfigGroup(const TQString &group = TQString())
        : TDEConfigGroupSaver(kapp->config(), group) {}
};

//-----------------------------------------------------------------------------
class PlayerInfos : public ItemArray
{
 public:
    PlayerInfos();

    bool isNewPlayer() const { return _newPlayer; }
    bool isOldLocalPlayer() const { return _oldLocalPlayer; }
    uint nbEntries() const;
    TQString name() const { return item("name")->read(_id).toString(); }
    bool isAnonymous() const;
    TQString prettyName() const { return prettyName(_id); }
    TQString prettyName(uint id) const { return item("name")->pretty(id); }
    TQString registeredName() const;
    TQString comment() const { return item("comment")->pretty(_id); }
    bool isWWEnabled() const;
    TQString key() const;
    uint id() const { return _id; }
    uint oldLocalId() const { return _oldLocalId; }

    void createHistoItems(const TQMemArray<uint> &scores, bool bound);
    TQString histoName(uint i) const;
    uint histoSize() const;
    const TQMemArray<uint> &histogram() const { return _histogram; }

    void submitScore(const Score &) const;
    // return true if the nickname is already used locally
    bool isNameUsed(const TQString &name) const;
    void modifyName(const TQString &newName) const;
    void modifySettings(const TQString &newName, const TQString &comment,
                        bool WWEnabled, const TQString &newKey) const;
    void removeKey();

 private:
    bool _newPlayer, _bound, _oldLocalPlayer;
    uint _id, _oldLocalId;
    TQMemArray<uint> _histogram;
};

//-----------------------------------------------------------------------------
class ManagerPrivate
{
 public:
    ManagerPrivate(uint nbGameTypes, Manager &manager);
    void init(uint maxNbentries);
    ~ManagerPrivate();

    bool modifySettings(const TQString &newName, const TQString &comment,
                        bool WWEnabled, TQWidget *widget);

    void setGameType(uint type);
    void checkFirst();
    int submitLocal(const Score &score);
    int submitScore(const Score &score, TQWidget *widget, bool askIfAnonymous);
    Score readScore(uint i) const;

    uint gameType() const        { return _gameType; }
    uint nbGameTypes() const     { return _nbGameTypes; }
    bool isWWHSAvailable() const { return !serverURL.isEmpty(); }
    ScoreInfos &scoreInfos()     { return *_scoreInfos; }
    PlayerInfos &playerInfos()   { return *_playerInfos; }
    KHighscore &hsConfig()       { return *_hsConfig; }
    enum QueryType { Submit, Register, Change, Players, Scores };
    KURL queryURL(QueryType type, const TQString &newName=TQString()) const;

    void exportHighscores(TQTextStream &);

    Manager &manager;
    KURL     serverURL;
    TQString  version;
    bool     showStatistics, showDrawGames, trackLostGames, trackDrawGames;
    Manager::ShowMode showMode;

 private:
    KHighscore   *_hsConfig;
    PlayerInfos  *_playerInfos;
    ScoreInfos   *_scoreInfos;
    bool          _first;
    const uint    _nbGameTypes;
    uint          _gameType;

    // return -1 if not a local best score
    int rank(const Score &score) const;

    bool submitWorldWide(const Score &score, TQWidget *parent) const;
    static bool doQuery(const KURL &url, TQWidget *parent,
                        TQDomNamedNodeMap *map = 0);
    static bool getFromQuery(const TQDomNamedNodeMap &map, const TQString &name,
                             TQString &value, TQWidget *parent);
    void convertToGlobal();
};

} // namespace

#endif
