//------------------------------------------------------------------------------
// emPackLayout.h
//
// Copyright (C) 2015 Oliver Hamann.
//
// Homepage: http://eaglemode.sourceforge.net/
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License version 3 as published by the
// Free Software Foundation.
//
// 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 version 3 for
// more details.
//
// You should have received a copy of the GNU General Public License version 3
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

#ifndef emPackLayout_h
#define emPackLayout_h

#ifndef emBorder_h
#include <emCore/emBorder.h>
#endif


//==============================================================================
//================================ emPackLayout ================================
//==============================================================================

class emPackLayout : public emBorder {

public:

        // A panel of this class automatically lays out its child panels within
        // the content area by a special "pack" algorithm, which allows to give
        // each child panel a weight (area proportion) and a preferred tallness
        // (height/width ratio). This should be used only for up to about seven
        // child panels. With more, the algorithm may not find an optimal
        // layout.
        //
        //                    Pack layout
        //   +---------------------------------------------+
        //   | +------------------+  +---------+  +-----+  |
        //   | |                  |  |         |  |     |  |
        //   | |                  |  |         |  |     |  |
        //   | |                  |  |         |  |     |  |
        //   | |                  |  |         |  +-----+  |
        //   | |                  |  |         |           |
        //   | |                  |  |         |  +-----+  |
        //   | |                  |  |         |  |     |  |
        //   | +------------------+  |         |  |     |  |
        //   |                       |         |  |     |  |
        //   | +------------------+  |         |  |     |  |
        //   | |                  |  |         |  |     |  |
        //   | |                  |  |         |  |     |  |
        //   | +------------------+  +---------+  +-----+  |
        //   +---------------------------------------------+
        //
        // The algorithm recursively divides the available area and the child
        // panel set into two areas and two child panel sets until each area has
        // only one panel. Thereby, the order of child panels is kept. The area
        // proportions are calculated from the given weights. The decision where
        // (at which child panel) and how (horizontally or vertically) the
        // dividing in each recursive step is made, is determined by iterating
        // multiple possibilities until a solution is found which satisfies the
        // preferred tallnesses best possible. Because this would be too time
        // consuming for large sets, the algorithm reduces the number of
        // iterations in a recursive step depending on the size of the set (down
        // to zero for large sets). This way, an optimum is guaranteed only for
        // up to seven child panels.
        //
        // By default, a panel of this class is not focusable and has no border,
        // because it is meant as a pure layout programming tool. For other use,
        // please see the derived class emPackGroup.

        emPackLayout(
                ParentArg parent, const emString & name,
                const emString & caption=emString(),
                const emString & description=emString(),
                const emImage & icon=emImage()
        );
                // Like emBorder, but sets non-focusable.

        virtual ~emPackLayout();
                // Destructor.

        int GetMinCellCount() const;
        void SetMinCellCount(int minCellCount);
                // Minimum number of cells to be generated. The layout algorithm
                // behaves like if there were at least this number of child
                // panels. The additional cells are simply making up unused
                // space. The default is zero.

        double GetChildWeight(int index) const;
        void SetChildWeight(int index, double weight);
                // Get or set the weight of a child panel. The bigger the weight
                // of a child panel, the bigger is the proportion of the
                // available area given to that panel by the layout algorithm.
                // It is a simple linear relation. The index argument denotes a
                // child panel. Zero means first child, one means second, and so
                // on. The default weight is 1.0.

        void SetChildWeight(double weight);
                // Set the weight of all child panels to the given value.

        double GetPrefChildTallness(int index) const;
        void SetPrefChildTallness(int index, double pct);
                // Get or set the preferred tallness (height/width ratio) of a
                // child panel. The index argument denotes a child panel. Zero
                // means first child, one means second, and so on. The default
                // preferred tallness is 0.2.

        void SetPrefChildTallness(double pct);
                // Set the preferred tallness of all child panels to the given
                // value.

protected:

        virtual void LayoutChildren();
                // Lays out all child panels in the content area (except for an
                // auxiliary panel, which is laid out in the border).

private:

        struct TmpPanelInfo {
                double PCT;
                double CumulativeWeight;
                double CumulativeLogPCT;
                emPanel * Panel;
        };

        struct TmpInfo {
                TmpPanelInfo * TPIs;
                emColor CanvasColor;
        };

        int CountCells();
        void FillTPIs(int count);
        double GetTPIWeightSum(int index, int count) const;
        double GetTPILogPCTSum(int index, int count) const;

        double RateCell(int index, double w, double h);

        double Pack1(
                int index,
                double x, double y, double w, double h,
                bool execute
        );

        double Pack2(
                int index,
                double x, double y, double w, double h,
                double bestError, bool execute
        );

        double Pack3(
                int index,
                double x, double y, double w, double h,
                double bestError, bool execute
        );

        double PackN(
                int index, int count,
                double x, double y, double w, double h,
                double bestError, bool execute
        );

        double RateHorizontally(
                int index, int count, int div,
                double x, double y, double w1, double w2, double h,
                double bestError
        );

        double RateVertically(
                int index, int count, int div,
                double x, double y, double w, double h1, double h2,
                double bestError
        );

        double DefaultWeight;
        double DefaultPCT;
        emArray<double> WeightArray;
        emArray<double> PCTArray;
        int MinCellCount;
        TmpInfo * TI;
        int Ratings;
};


inline int emPackLayout::GetMinCellCount() const
{
        return MinCellCount;
}


#endif