/**
 * @file lltabcontainer.h
 * @brief LLTabContainer class
 *
 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, 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_TABCONTAINER_H
#define LL_TABCONTAINER_H

#include "llpanel.h"
#include "lltextbox.h"
#include "llframetimer.h"
#include "lliconctrl.h"
#include "llbutton.h"

class LLTabTuple;

class LLTabContainer : public LLPanel
{
public:
    enum TabPosition
    {
        TOP,
        BOTTOM,
        LEFT
    };
    typedef enum e_insertion_point
    {
        START,
        END,
        LEFT_OF_CURRENT,
        RIGHT_OF_CURRENT
    } eInsertionPoint;

    struct TabPositions : public LLInitParam::TypeValuesHelper<LLTabContainer::TabPosition, TabPositions>
    {
        static void declareValues();
    };

    struct TabParams : public LLInitParam::Block<TabParams>
    {
        Optional<LLUIImage*>                tab_top_image_unselected,
                                            tab_top_image_selected,
                                            tab_top_image_flash,
                                            tab_bottom_image_unselected,
                                            tab_bottom_image_selected,
                                            tab_bottom_image_flash,
                                            tab_left_image_unselected,
                                            tab_left_image_selected,
                                            tab_left_image_flash;
        TabParams();
    };

    struct Params
    :   public LLInitParam::Block<Params, LLPanel::Params>
    {
        Optional<TabPosition, TabPositions> tab_position;
        Optional<S32>                       tab_width,
                                            tab_min_width,
                                            tab_max_width,
                                            tab_height,
                                            label_pad_bottom,
                                            label_pad_left;

        Optional<bool>                      hide_tabs;
        Optional<bool>                      hide_scroll_arrows;
        Optional<S32>                       tab_padding_right;

        Optional<TabParams>                 first_tab,
                                            middle_tab,
                                            last_tab;

        /**
         * Tab label horizontal alignment
         */
        Optional<LLFontGL::HAlign>          font_halign;

        /**
         * Tab label ellipses
         */
        Optional<bool>                      use_ellipses;

        /**
         * Use LLCustomButtonIconCtrl or LLButton in LLTabTuple
         */
        Optional<bool>                      use_custom_icon_ctrl;

        /**
         * Open tabs on hover in drag and drop situations
         */
        Optional<bool>                      open_tabs_on_drag_and_drop;

        /**
         * Enable tab flashing
         */
        Optional<bool>                      enable_tabs_flashing;
        Optional<LLUIColor>                 tabs_flashing_color;

        /**
         *  Paddings for LLIconCtrl in case of LLCustomButtonIconCtrl usage(use_custom_icon_ctrl = true)
         */
        Optional<S32>                       tab_icon_ctrl_pad;

        Optional<bool> use_tab_offset;

        Params();
    };

protected:
    LLTabContainer(const Params&);
    friend class LLUICtrlFactory;

public:
    //LLTabContainer( const std::string& name, const LLRect& rect, TabPosition pos,
    //              bool bordered, bool is_vertical);

    /*virtual*/ ~LLTabContainer();

    // from LLView
    /*virtual*/ void setValue(const LLSD& value);

    /*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true);
    /*virtual*/ void draw();
    /*virtual*/ bool handleMouseDown( S32 x, S32 y, MASK mask );
    /*virtual*/ bool handleHover( S32 x, S32 y, MASK mask );
    /*virtual*/ bool handleMouseUp( S32 x, S32 y, MASK mask );
    /*virtual*/ bool handleToolTip(S32 x, S32 y, MASK mask);
    /*virtual*/ bool handleKeyHere(KEY key, MASK mask);
    /*virtual*/ bool handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
                                       EDragAndDropType type, void* cargo_data,
                                       EAcceptance* accept, std::string& tooltip);
    /*virtual*/ LLView* getChildView(std::string_view name, bool recurse = true) const;
    /*virtual*/ LLView* findChildView(std::string_view name, bool recurse = true) const;
    /*virtual*/ void initFromParams(const LLPanel::Params& p);
    /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
    /*virtual*/ bool postBuild();

    struct TabPanelParams : public LLInitParam::Block<TabPanelParams>
    {
        Mandatory<LLPanel*>         panel;

        Optional<std::string>       label;
        Optional<bool>              select_tab,
                                    is_placeholder;
        Optional<S32>               indent;
        Optional<eInsertionPoint>   insert_at;
        Optional<void*>             user_data;

        TabPanelParams()
        :   panel("panel", NULL),
            label("label"),
            select_tab("select_tab"),
            is_placeholder("is_placeholder"),
            indent("indent"),
            insert_at("insert_at", END)
        {}
    };

    void        addTabPanel(LLPanel* panel);
    void        addTabPanel(const TabPanelParams& panel);
    void        addPlaceholder(LLPanel* child, const std::string& label);
    void        removeTabPanel( LLPanel* child );
    void        lockTabs(S32 num_tabs = 0);
    void        unlockTabs();
    S32         getNumLockedTabs() { return mLockedTabCount; }
    void        enableTabButton(S32 which, bool enable);
    void        deleteAllTabs();
    LLPanel*    getCurrentPanel();
    S32         getCurrentPanelIndex();
    S32         getTabCount();
    LLPanel*    getPanelByIndex(S32 index);
    S32         getIndexForPanel(LLPanel* panel);
    S32         getPanelIndexByTitle(std::string_view title);
    LLPanel*    getPanelByName(std::string_view name);
    S32         getTotalTabWidth() const;
    void        setCurrentTabName(const std::string& name);

    void        selectFirstTab();
    void        selectLastTab();
    void        selectNextTab();
    void        selectPrevTab();
    bool        selectTabPanel( LLPanel* child );
    bool        selectTab(S32 which);
    bool        selectTabByName(std::string_view title);
    void        setCurrentPanelIndex(S32 index) { mCurrentTabIdx = index; }

    bool        getTabPanelFlashing(LLPanel* child);
    void        setTabPanelFlashing(LLPanel* child, bool state);
    void        setTabImage(LLPanel* child, std::string img_name, const LLColor4& color = LLColor4::white);
    void        setTabImage(LLPanel* child, const LLUUID& img_id, const LLColor4& color = LLColor4::white);
    void        setTabImage(LLPanel* child, LLIconCtrl* icon);
    void        setTitle( const std::string& title );
    const std::string getPanelTitle(S32 index);

    void        setTopBorderHeight(S32 height);
    S32         getTopBorderHeight() const;

    void        setRightTabBtnOffset( S32 offset );
    void        setPanelTitle(S32 index, const std::string& title);

    TabPosition getTabPosition() const { return mTabPosition; }
    void        setMinTabWidth(S32 width) { mMinTabWidth = width; }
    void        setMaxTabWidth(S32 width) { mMaxTabWidth = width; }
    S32         getMinTabWidth() const { return mMinTabWidth; }
    S32         getMaxTabWidth() const { return mMaxTabWidth; }

    void setTabVisibility( LLPanel const *aPanel, bool );

    void        startDragAndDropDelayTimer() { mDragAndDropDelayTimer.start(); }

    void onTabBtn( const LLSD& data, LLPanel* panel );
    void onNextBtn(const LLSD& data);
    void onNextBtnHeld(const LLSD& data);
    void onPrevBtn(const LLSD& data);
    void onPrevBtnHeld(const LLSD& data);
    void onJumpFirstBtn( const LLSD& data );
    void onJumpLastBtn( const LLSD& data );

private:

    void initButtons();

    bool        setTab(S32 which);

    LLTabTuple* getTab(S32 index)       { return mTabList[index]; }
    LLTabTuple* getTabByPanel(LLPanel* child);
    void insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point);

    S32 getScrollPos() const            { return mScrollPos; }
    void setScrollPos(S32 pos)          { mScrollPos = pos; }
    S32 getMaxScrollPos() const         { return mMaxScrollPos; }
    void setMaxScrollPos(S32 pos)       { mMaxScrollPos = pos; }
    S32 getScrollPosPixels() const      { return mScrollPosPixels; }
    void setScrollPosPixels(S32 pixels) { mScrollPosPixels = pixels; }

    void setTabsHidden(bool hidden)     { mTabsHidden = hidden; }
    bool getTabsHidden() const          { return mTabsHidden; }

    void scrollPrev() { mScrollPos = llmax(0, mScrollPos-1); } // No wrap
    void scrollNext() { mScrollPos = llmin(mScrollPos+1, mMaxScrollPos); } // No wrap

    void updateMaxScrollPos();
    void commitHoveredButton(S32 x, S32 y);

    // updates tab button images given the tuple, tab position and the corresponding params
    void update_images(LLTabTuple* tuple, TabParams params, LLTabContainer::TabPosition pos);
    void reshapeTuple(LLTabTuple* tuple);

    // Variables

    typedef std::vector<LLTabTuple*> tuple_list_t;
    tuple_list_t                    mTabList;

    S32                             mCurrentTabIdx;
    bool                            mTabsHidden;
    bool                            mHideScrollArrows;

    bool                            mScrolled;
    LLFrameTimer                    mScrollTimer;
    S32                             mScrollPos;
    S32                             mScrollPosPixels;
    S32                             mMaxScrollPos;

    LLTextBox*                      mTitleBox;

    S32                             mTopBorderHeight;
    TabPosition                     mTabPosition;
    S32                             mLockedTabCount;
    S32                             mMinTabWidth;
    LLButton*                       mPrevArrowBtn;
    LLButton*                       mNextArrowBtn;

    bool                            mIsVertical;

    // Horizontal specific
    LLButton*                       mJumpPrevArrowBtn;
    LLButton*                       mJumpNextArrowBtn;

    S32                             mRightTabBtnOffset; // Extra room to the right of the tab buttons.

    S32                             mMaxTabWidth;
    S32                             mTotalTabWidth;
    S32                             mTabHeight;

    // Padding under the text labels of tab buttons
    S32                             mLabelPadBottom;
    // Padding to the left of text labels of tab buttons
    S32                             mLabelPadLeft;

    LLFrameTimer                    mDragAndDropDelayTimer;

    LLFontGL::HAlign                mFontHalign;
    const LLFontGL*                 mFont;

    TabParams                       mFirstTabParams;
    TabParams                       mMiddleTabParams;
    TabParams                       mLastTabParams;

    bool                            mCustomIconCtrlUsed;
    bool                            mOpenTabsOnDragAndDrop;
    bool                            mEnableTabsFlashing;
    LLUIColor                       mTabsFlashingColor;
    S32                             mTabIconCtrlPad;
    bool                            mUseTabEllipses;
    LLFrameTimer                    mMouseDownTimer;

    bool mUseTabOffset;
};

#endif  // LL_TABCONTAINER_H