/*
 * psserverchar.h
 *
 * Copyright (C) 2002 Atomic Blue (info@planeshift.it, http://www.atomicblue.org)
 *
 *
 * 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 (version 2 of the License)
 * 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 PS_SERVER_CHAR_MANAGER_H
#define PS_SERVER_CHAR_MANAGER_H

#include "msgmanager.h"
#include "bulkobjects/pscharacter.h"
#include "bulkobjects/psitem.h"
#include "iutil/vfs.h"
#include <csutil/ref.h>
#include <csutil/xmltiny.h>

class MsgEntry;
class ClientConnectionSet;
class psServer;
class Client;
struct psItemCategory;
class psMerchantInfo;
class psItem;
class psActionLocation;

enum ReservedNames{NAME_RESERVED_FOR_YOU, NAME_RESERVED, NAME_AVAILABLE};



/** Handles Drag and Drop Messages from the client.
  * This basically figures out what item is being dragged and places it in a 
  * holding slot.  It then looks for the destination slot and sees if it can be placed
  * there.  If not it will Replace the holding item back to where it came from.
  */
class SlotManager : public MessageManager
{
public:
    SlotManager();
    virtual ~SlotManager();

    bool Initialize();
    
    virtual void HandleMessage( MsgEntry *me, Client *client );            
    
    psItem* FindItem( Client* client, int containerID, int slotID, int parentID = 0 );
        
private:
    /** Used in the slot management.  This is called when a player tries to place an 
      * item into an equipment slot.  If it was successful then holdingItem should be 
      * set to NULL.  Otherwise the holdingItem will automatically be replaced in it's
      * orginal slot.
      *
      * @param mesg The incoming message from the client for the movement.    
      */
    void PlaceItemInEquipment( psSlotMovementMsg& mesg );

    /// Place the dragged item back to where it came from.
    void ReplaceHolding();   

    /** Find a container based on id.
      * This uses the gem idea of the gemItem object to find the psItem.
      */
    psItem* FindContainer( Client* client, int containerID, int parentContainerID );    
    
    /** This creates a money item.
      *
      * @param slot One of the four money slots.
      * @param stackCount The amount to put in the item.
      * @return A new psItem object.
      */
    psItem* MakeMoneyItem( int slot, int stackCount );
    
    /** Finds the particular item the client dragged/dropped.
      * @param fromClient The client the message came from.
      * @param mesg The slot movement message that has the drag/drop details.
      *
      * @return A psItem object that the player is manipulating.
      */
    psItem* FindHoldingItem( Client* fromClient, psSlotMovementMsg& mesg );
    
    /** Places the item that is being dragged into it's destination slot.
     *
     *  @param mesg The slot movement message that has the drag/drop details.
     */
    void PlaceHoldingItem( psSlotMovementMsg& mesg);

    void PlaceItemInExchange( psSlotMovementMsg & mesg);

    void UnequipHolding( psSlotMovementMsg & mesg);
    
    /** Consume an item.  This will consume the item and fire off any events 
      * that this item has.
      */
    bool Consume( psItem* item );

    /** Sends an error message to the client based on the return code.  
      * This will send a popup floating text error message.
      * @param result One of the enums from psitem.h 
      * @param fromClient The client the error message should be sent to.
      */
    void SendContainerError( int result, Client* fromClient );
        
    // Holding details. 
    psItem* holdingItem;
    psItem* holdingContainer;
    int holdingSlotID;
    int holdingContainerID;
    int holdingParentContainerID;
    
    int clientNum;
    Client* fromClient;
    psCharacter* charData;
};


/// Manages character details over the net.
/**
 * This is used instead of cel persistance because the persistance
 * is an all or nothing sort of thing. By using this we can make
 * more efficient use of the net traffic
 */
class psServerCharManager : public MessageManager
{
public:

    psServerCharManager();
    virtual ~psServerCharManager();

    bool Initialize( ClientConnectionSet* ccs);

    virtual void HandleMessage( MsgEntry *me, Client *client );

    // Handles any incomming messages about the character gui.
    virtual bool HandleInventoryMessage( MsgEntry* me );

    
    /// Sends the client an inventory
    virtual bool SendInventory( int clientNum );

    /// Update all views with items
    virtual bool UpdateItemViews( int clientNum );

    bool SendItemContents( Client *client, psItem *item,
                           int parentContainer = 0, int containerID = CONTAINER_INVENTORY_BULK);
    bool SendActionContents( Client *client, psActionLocation *action, csRef<iDocumentNode> topNode, psItem *item,
                             int parentContainer = 0, int containerID = CONTAINER_INVENTORY_BULK);

    void SendOutPlaySoundMessage( int clientnum, const char* itemsound, const char* action );

    /** Sends out equipment messages to all the people around client.
     *
     * This is used when a player changes their visible equipment and needs
     * to be reflected on other nearby clients. Visible changes can be either 
     * new weapons/shields ( new mesh ) or texture changes for clothes ( new material ).
     *
     * @param fromClient The client that has changed equipment.
     * @param slotName To what slot has changed.
     * @param item The item that is the piece of visible equipment.
     * @param type  The equiping type. One of:                  
     *                psEquipmentMessage::DEEQUIP
     *                psEquipmentMessage::EQUIP
     *              
     */
    void SendOutEquipmentMessages( Client* fromClient, 
                                   int slotID,
                                   psItem* item, 
                                   int equiped );  
                                   
    void SendOutEquipmentMessages( unsigned int fromClient, 
                                   int slotID,
                                   psItem* item, 
                                   int equiped );
    
    void SendOutEquipmentMessages( gemActor* actor, 
                                   int slotID,
                                   psItem* item, 
                                   int equiped );  
   
    /** Check to see if a name is on the reserve list for database migration.
        @param playerName The name to check to see if is on a the reserve list.
        @param acctID The acct that is trying to create this character. 
        
        @return <UL>
                <LI>NAME_RESERVED_FOR_YOU - if you can take this name.
                <LI>NAME_RESERVED - you are not allowed this name.
                <LI>NAME_AVAILABLE - name is free for use.
                </UL>
    */                
    int  IsReserved( const char* playerName, int acctID );

    /** Check to see a name is unique in the characters table.
        @param playerName The name to check to see if it is unique.
        @return true if the name is unique.
    */
    bool IsUnique( const char* playerName );

    /** Check to see a lastname is unique in the characters table.
        @param lastname The lastname to check to see if it is unique.
        @return true if the name is unique.
    */
    bool IsLastNameUnique( const char* lastname );
    
    void ViewItem(Client* client, int containerID, int slotID, int parentContainerID);

    void BeginTrading(Client * client, gemObject * target, const csString & type);

    /// Returns true if the name is ok
    static bool FilterName( const char* name );

    bool IsBanned(const char* name);
    
    ///Checked if the character exists still or if it hasn't connected in two months.
    int HasConnected( csString name );

protected:    
                                   
    void SendPlayerMoney( Client *client);
    bool SendItemDescription( Client *client, psItem *item);
    bool SendBookText( Client *client, psItem *item);
    bool SendMerchantItems( Client *client, psCharacter * merchant, psItemCategory * category);
    bool SendPlayerItems( Client *client, psItemCategory * category);

    void HandleUploadMessage( MsgEntry * me, Client *client );
    void HandleCharInfo( MsgEntry* me, Client *client );
    void HandleMerchantMessage( MsgEntry* me, Client *client );
    void HandleCraftInfo( MsgEntry * me, Client *client );

    /** Fills up the message with the details about the items in the container.
      * @param item The item that is the container
      * @param client The client the message is for. Used to figure out ownership flags.
      * @param outgoing The message that needs to be populated.
      */    
    void FillContainerMsg( psItem* item, Client* client, psViewItemDescription& outgoing );
        
    /// Return true if all trade params are ok
    bool VerifyTrade( Client * client, psCharacter * character, psCharacter ** merchant, psMerchantInfo ** info,
                      const char * trade,const char * itemName, unsigned int merchantID);
  
    // verifies that item dropped in mind slot is a valid goal
    bool VerifyGoal(Client* client, psCharacter* character, psItem* goal);

    ClientConnectionSet*    clients;   
       
    
    /** Assign a script to a character.
        Takes whatever script is stored in the migration table and adds it to the 
        character to be run on character login.
        @param chardata The character data class to append the script to.
    */
    void AssignScript( psCharacter* chardata );
        
    SlotManager *slotManager;
    
    void ViewItem( MsgEntry* me );
};

#endif


