/**
* @file llpanelprofile.h
* @brief Profile panel
*
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2022, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
* $/LicenseInfo$
*/

#ifndef LL_LLPANELPROFILE_H
#define LL_LLPANELPROFILE_H

#include "llavatarpropertiesprocessor.h"
#include "llcallingcard.h"
#include "llfloater.h"
#include "llpanel.h"
#include "llpanelavatar.h"
#include "llmediactrl.h"
#include "llvoiceclient.h"
#include "rlvhandler.h"

// class LLPanelProfileClassifieds;
// class LLTabContainer;

// class LLPanelProfileSecondLife;
// class LLPanelProfileWeb;
// class LLPanelProfilePicks;
// class LLPanelProfileFirstLife;
// class LLPanelProfileNotes;

class LLAvatarName;
class LLButton;
class LLCheckBoxCtrl;
class LLComboBox;
class LLIconCtrl;
class LLTabContainer;
class LLTextBox;
class LLTextureCtrl;
class LLMediaCtrl;
class LLGroupList;
class LLTextBase;
class LLMenuButton;
class LLLineEditor;
class LLTextEditor;
class LLPanelProfileClassifieds;
class LLPanelProfilePicks;
class LLViewerFetchedTexture;

// <FS:Zi> FIRE-32184: Online/Offline status not working for non-friends
class LLPanelProfileSecondLife;

class FSPanelPropertiesObserver : public LLAvatarPropertiesObserver
{
public:
    FSPanelPropertiesObserver();

	virtual void processProperties(void* data, EAvatarProcessorType type);

    LLUUID mRequester;
    LLPanelProfileSecondLife* mPanelProfile;
};
// </FS:Zi>

/**
* Panel for displaying Avatar's second life related info.
*/
class LLPanelProfileSecondLife
	: public LLPanelProfilePropertiesProcessorTab
	, public LLFriendObserver
	, public LLVoiceClientStatusObserver
{
public:
	LLPanelProfileSecondLife();
	/*virtual*/ ~LLPanelProfileSecondLife();

	void onOpen(const LLSD& key) override;

	/**
	 * LLFriendObserver trigger
	 */
	void changed(U32 mask) override;

	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
	// button when voice is available
	void onChange(EStatusType status, const std::string &channelURI, bool proximal) override;

	void setAvatarId(const LLUUID& avatar_id) override;

	BOOL postBuild() override;

	void resetData() override;

	/**
	 * Sends update data request to server.
	 */
    void apply(LLAvatarData* data);
    void processProperties(void* data, EAvatarProcessorType type) override;
	void updateData() override;
    void refreshName();

	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);

    void setProfileImageUploading(bool loading);
    void setProfileImageUploaded(const LLUUID &image_asset_id);

    bool hasUnsavedChanges() override;
    void commitUnsavedChanges() override;

    friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);

    // <FS:Zi> FIRE-32184: Online/Offline status not working for non-friends
    void onAvatarProperties(const LLAvatarData* d);

protected:
	/**
	 * Process profile related data received from server.
	 */
	void processProfileProperties(const LLAvatarData* avatar_data);

	/**
	 * Processes group related data received from server.
	 */
	void processGroupProperties(const LLAvatarGroups* avatar_groups);

	/**
	 * Fills common for Avatar profile and My Profile fields.
	 */
	void fillCommonData(const LLAvatarData* avatar_data);

	/**
	 * Fills partner data.
	 */
	void fillPartnerData(const LLAvatarData* avatar_data);

	/**
	 * Fills account status.
	 */
	void fillAccountStatus(const LLAvatarData* avatar_data);

    /**
     * Sets permissions specific icon
     */
    void fillRightsData();

    /**
     * Fills user name, display name, age.
     */
    void fillAgeData(const LLDate &born_on);

    void onImageLoaded(BOOL success, LLViewerFetchedTexture *imagep);
    static void onImageLoaded(BOOL success,
                              LLViewerFetchedTexture *src_vi,
                              LLImageRaw* src,
                              LLImageRaw* aux_src,
                              S32 discard_level,
                              BOOL final,
                              void* userdata);

	/**
	 * Displays avatar's online status if possible.
	 *
	 * Requirements from EXT-3880:
	 * For friends:
	 * - Online when online and privacy settings allow to show
	 * - Offline when offline and privacy settings allow to show
	 * - Else: nothing
	 * For other avatars:
	 *	- Online when online and was not set in Preferences/"Only Friends & Groups can see when I am online"
	 *	- Else: Offline
	 */
	void updateOnlineStatus();
	void processOnlineStatus(bool is_friend, bool show_online, bool online);

private:
    void setLoaded() override;
    void onCommitMenu(const LLSD& userdata);
    bool onEnableMenu(const LLSD& userdata);
    bool onCheckMenu(const LLSD& userdata);
	void onAvatarNameCacheSetName(const LLUUID& id, const LLAvatarName& av_name);

    void setDescriptionText(const std::string &text);
    void onSetDescriptionDirty();
    void onShowInSearchCallback();
    void onSaveDescriptionChanges();
    void onDiscardDescriptionChanges();
    void onShowAgentPermissionsDialog();
    void onShowAgentProfileTexture();
    void onShowTexturePicker();
    void onSecondLifePicChanged();  // <FS:Zi> Allow proper texture swatch handling
    void onCommitProfileImage(const LLUUID& id);

    // <FS:Ansariel> Fix LL UI/UX design accident
    void updateButtons();

private:
	typedef std::map<std::string, LLUUID> group_map_t;
	group_map_t				mGroups;
	void					openGroupProfile();

	LLTextBox*			mStatusText; // <FS:Ansariel> Fix LL UI/UX design accident
	LLGroupList*		mGroupList;
	// <FS:Ansariel> Fix LL UI/UX design accident
    //LLComboBox*			mShowInSearchCombo;
	LLCheckBoxCtrl*		mShowInSearchCheckbox;
	// </FS:Ansariel>
    // <FS:Zi> Allow proper texture swatch handling
	// LLIconCtrl*			mSecondLifePic;
	LLTextureCtrl*		mSecondLifePic;
    // </FS:Zi>
	LLPanel*			mSecondLifePicLayout;
    LLTextEditor*		mDescriptionEdit;
    //LLMenuButton*		mAgentActionMenuButton; // <FS:Ansariel> Fix LL UI/UX design accident
    LLButton*			mSaveDescriptionChanges;
    LLButton*			mDiscardDescriptionChanges;
    LLIconCtrl*			mCanSeeOnlineIcon;
    LLIconCtrl*			mCantSeeOnlineIcon;
    LLIconCtrl*			mCanSeeOnMapIcon;
    LLIconCtrl*			mCantSeeOnMapIcon;
    LLIconCtrl*			mCanEditObjectsIcon;
    LLIconCtrl*			mCantEditObjectsIcon;
    // <FS:Ansariel> Fix LL UI/UX design accident
    LLMenuButton*		mCopyMenuButton;
    LLButton*			mGroupInviteButton;
    LLButton*			mDisplayNameButton;
    LLMenuButton*		mImageActionMenuButton;
    LLButton*			mTeleportButton;
    LLButton*			mShowOnMapButton;
    LLButton*			mBlockButton;
    LLButton*			mUnblockButton;
    LLButton*			mAddFriendButton;
    LLButton*			mRemoveFriendButton;    // <FS:Zi> Add "Remove Friend" button to profile
    LLButton*			mPayButton;
    LLButton*			mIMButton;
    LLMenuButton*		mOverflowButton;
    // </FS:Ansariel>

    LLHandle<LLFloater>	mFloaterPermissionsHandle;
    LLHandle<LLFloater>	mFloaterProfileTextureHandle;
    LLHandle<LLFloater>	mFloaterTexturePickerHandle;

    bool				mHasUnsavedDescriptionChanges;
	bool				mVoiceStatus;
    bool				mWaitingForImageUpload;
    bool				mAllowPublish;
    std::string			mDescriptionText;
    LLUUID				mImageId;

	boost::signals2::connection	mAvatarNameCacheConnection;

    // <FS:Ansariel> RLVa support
    boost::signals2::connection mRlvBehaviorCallbackConnection;
    void updateRlvRestrictions(ERlvBehaviour behavior);
    // </FS:Ansariel>

    // <FS:Zi> FIRE-32184: Online/Offline status not working for non-friends
    FSPanelPropertiesObserver mPropertiesObserver;
};


/**
* Panel for displaying Avatar's web profile and home page.
*/
class LLPanelProfileWeb
	: public LLPanelProfileTab
	, public LLViewerMediaObserver
{
public:
	LLPanelProfileWeb();
	/*virtual*/ ~LLPanelProfileWeb();

	void onOpen(const LLSD& key) override;

	BOOL postBuild() override;

	void resetData() override;

	/**
	 * Loads web profile.
	 */
	void updateData() override;
    void apply(LLAvatarData* data);

	void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) override;

	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);

    friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);

protected:
	void onCommitLoad(LLUICtrl* ctrl);

private:
	std::string			mURLHome;
	std::string			mURLWebProfile;
	LLMediaCtrl*		mWebBrowser;

	LLFrameTimer		mPerformanceTimer;
	bool				mFirstNavigate;

	boost::signals2::connection	mAvatarNameCacheConnection;
};

/**
* Panel for displaying Avatar's first life related info.
*/
class LLPanelProfileFirstLife
	: public LLPanelProfilePropertiesProcessorTab
{
public:
	LLPanelProfileFirstLife();
	/*virtual*/ ~LLPanelProfileFirstLife();

	void onOpen(const LLSD& key) override;

	BOOL postBuild() override;

    void processProperties(const LLAvatarData* avatar_data);
    void processProperties(void * data, EAvatarProcessorType type) override;
    void apply(LLAvatarData* data);
	void resetData() override;

    void setProfileImageUploading(bool loading);
    void setProfileImageUploaded(const LLUUID &image_asset_id);

    bool hasUnsavedChanges() override { return mHasUnsavedChanges; }
    void commitUnsavedChanges() override;

    friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);

protected:
	void setLoaded() override;

    void onUploadPhoto();
    void onChangePhoto();
    void onRemovePhoto();
    void onFirstLifePicChanged();   // <FS:Zi> Allow proper texture swatch handling
    void onCommitPhoto(const LLUUID& id);
    void setDescriptionText(const std::string &text);
    void onSetDescriptionDirty();
    void onSaveDescriptionChanges();
    void onDiscardDescriptionChanges();

	LLTextEditor*	mDescriptionEdit;
    // <FS:Zi> Allow proper texture swatch handling
    // LLIconCtrl*		mPicture;
    LLTextureCtrl* mPicture;
    // </FS:Zi>
    LLButton* mUploadPhoto;
    LLButton* mChangePhoto;
    LLButton* mRemovePhoto;
    LLButton* mSaveChanges;
    LLButton* mDiscardChanges;

    LLHandle<LLFloater>	mFloaterTexturePickerHandle;

    std::string		mCurrentDescription;
    LLUUID			mImageId;
    bool			mHasUnsavedChanges;
};

/**
 * Panel for displaying Avatar's notes and modifying friend's rights.
 */
class LLPanelProfileNotes
	: public LLPanelProfilePropertiesProcessorTab
{
public:
	LLPanelProfileNotes();
	/*virtual*/ ~LLPanelProfileNotes();

	void setAvatarId(const LLUUID& avatar_id) override;

	void onOpen(const LLSD& key) override;

	BOOL postBuild() override;

    void processProperties(LLAvatarNotes* avatar_notes);
    void processProperties(void * data, EAvatarProcessorType type) override;
	void resetData() override;

	void updateData() override;

    bool hasUnsavedChanges() override { return mHasUnsavedChanges; }
    void commitUnsavedChanges() override;

protected:
    void setNotesText(const std::string &text);
    void onSetNotesDirty();
    void onSaveNotesChanges();
    void onDiscardNotesChanges();

	LLTextEditor*       mNotesEditor;
    LLButton* mSaveChanges;
    LLButton* mDiscardChanges;

    std::string		mCurrentNotes;
    bool			mHasUnsavedChanges;
};


/**
* Container panel for the profile tabs
*/
class LLPanelProfile
    : public LLPanelProfileTab
{
public:
    LLPanelProfile();
    /*virtual*/ ~LLPanelProfile();

    BOOL postBuild() override;

    void updateData() override;
    void refreshName();

    void onOpen(const LLSD& key) override;

    void createPick(const LLPickData &data);
    void showPick(const LLUUID& pick_id = LLUUID::null);
    bool isPickTabSelected();
    bool isNotesTabSelected();
    bool hasUnsavedChanges() override;
    bool hasUnpublishedClassifieds();
    void commitUnsavedChanges() override;

    void showClassified(const LLUUID& classified_id = LLUUID::null, bool edit = false);
    void createClassified();

    LLAvatarData getAvatarData() { return mAvatarData; };
    void setAvatarData(const LLAvatarData* avatar_data){ mAvatarData = *avatar_data; };

    friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);

private:
    void onTabChange();

    LLPanelProfileSecondLife*   mPanelSecondlife;
    LLPanelProfileWeb*          mPanelWeb;
    LLPanelProfilePicks*        mPanelPicks;
    LLPanelProfileClassifieds*  mPanelClassifieds;
    LLPanelProfileFirstLife*    mPanelFirstlife;
    LLPanelProfileNotes*        mPanelNotes;
    LLTabContainer*             mTabContainer;

    // Todo: due to server taking minutes to update this needs a more long term storage
    // to reuse recently saved values if user opens floater again
    // Storage implementation depends onto how a cap will be implemented, if cap will be
    // enought to fully update LLAvatarPropertiesProcessor, then this storage can be
    // implemented there.
    LLAvatarData mAvatarData;
};

#endif //LL_LLPANELPROFILE_H
