/***********************************************************************************

    Copyright (C) 2007-2026 Ahmet Öztürk (aoz_2@yahoo.com)

    This file is part of Lifeograph.

    Lifeograph 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, either version 3 of the License, or
    (at your option) any later version.

    Lifeograph 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 Lifeograph.  If not, see <http://www.gnu.org/licenses/>.

***********************************************************************************/


#ifndef LIFEOGRAPH_CHART_HEADER
#define LIFEOGRAPH_CHART_HEADER


#include <gtkmm/widget.h>

#include "../helpers.hpp"
#include "../diaryelements/diarydata.hpp"
#include "chart_common.hpp"


namespace LoG
{

using namespace HELPERS;


class FiltererContainer; // forward declaration


class Chart : public ChartCommon
{
    public:
                                    Chart( Glib::RefPtr< Pango::Layout >& layout,
                                           const Pango::FontDescription& fd,
                                           bool F_printing_mode )
                                    : Chart( fd, F_printing_mode )
                                    {
                                        m_layout = layout;
                                    }
                                    Chart( const Pango::FontDescription& =
                                                Pango::FontDescription( "Sans 11" ),
                                           bool = false );
        virtual                     ~Chart() { }

        bool                        update_label_size() override;

        virtual void                refresh() override { }

    protected:
        template< class T >
        void draw_line3( const Cairo::RefPtr< Cairo::Context >& cr,
                        const T& values,
                        const bool F_underlay = false )
        {
            auto it_v{ values.begin() };
            std::advance( it_v, m_step_start - m_pre_steps );

            cr->move_to( m_x_offset + m_x_min - m_step_x * m_pre_steps,
                         m_y_offset + m_y_max
                                    - m_coefficient * ( ( F_underlay ? it_v->second.u
                                                                     : it_v->second.v )
                                                        - m_data.v_grid_min ) );

            for( int i = 1; i < m_step_count + m_pre_steps + m_post_steps; i++ )
            {
                ++it_v;

                //may not be needed if( vy != std::numeric_limits< double >::max() )
                cr->line_to( m_x_offset + m_x_min + m_step_x * ( i - m_pre_steps ),
                             m_y_offset + m_y_max
                                        - m_coefficient * ( ( F_underlay ? it_v->second.u
                                                                         : it_v->second.v )
                                                            - m_data.v_grid_min ) );
            }
            cr->stroke();
        }

        template< class T >
        void draw_bars3( const Cairo::RefPtr< Cairo::Context >& cr,
                        const T& values,
                        const bool F_underlay = false )
        {
            auto       it_v     { values.begin() };
            const bool F_show_v { !F_underlay &&
                                  ( m_step_x * Pango::SCALE ) > ( m_font_bold.get_size() * 4 ) };
            std::advance( it_v, m_step_start - m_pre_steps );

            if( F_show_v )
            {
                m_layout->set_font_description( m_font_bold );
                m_layout->set_width( m_step_x * 0.8 * Pango::SCALE );
                m_layout->set_alignment( Pango::Alignment::CENTER );
            }

            for( int i = 0; i < m_step_count + m_pre_steps + m_post_steps; i++ )
            {
                const auto bar_h{ m_coefficient * ( F_underlay ? it_v->second.u
                                                               : it_v->second.v ) };

                if( bar_h != 0 )
                    cr->rectangle( m_x_offset + m_x_min + m_step_x * ( i - m_pre_steps + 0.1 ),
                                   m_y_offset + m_y_0,
                                   m_step_x * 0.8,
                                   -bar_h );

                if( F_show_v && it_v->second.v != 0.0 )
                {
                    m_layout->set_text( STR::format_number( it_v->second.v ) );

                    cr->move_to( m_x_offset + m_x_min + m_step_x * ( i - m_pre_steps + 0.1 ),
                                 m_y_offset + m_y_0 - bar_h - ( bar_h < 0 ? 0 : m_label_height ) );
                    m_layout->show_in_cairo_context( cr );
                }

                ++it_v;
            }
            if( F_underlay )
                cr->stroke();
            else
                cr->fill();
        }

        double draw_x_values_str_prepare( const Cairo::RefPtr< Cairo::Context >& cr )
        {
            if( m_data.get_style() == ChartData::STYLE_LINE )
            {
                cr->rectangle( m_x_offset, m_y_offset + m_y_max, m_width, m_h_x_values );
                cr->set_source_rgb( 0.9, 0.9, 0.9 );
                cr->fill();
            }

            m_layout->set_font_description( m_font_main );
            m_layout->set_width( 1.3 * m_h_x_values * Pango::SCALE );
            m_layout->set_alignment( Pango::Alignment::LEFT );
            m_layout->set_ellipsize( Pango::EllipsizeMode::END );

            cr->set_source_rgb( 0.0, 0.0, 0.0 );
            return( m_y_offset + m_height - m_ov_height - m_h_x_values );
        }
        void draw_x_value_str_column( const Cairo::RefPtr< Cairo::Context >& cr,
                                      const Ustring& txt,
                                      int i ,
                                      const double bar_top )
        {
            if( m_data.get_style() == ChartData::STYLE_BARS )
                cr->move_to( m_x_offset + m_x_min + m_step_x * ( i + 0.5 ), bar_top );
            else
                cr->move_to( m_x_offset + m_x_min + m_step_x * i, bar_top );

            if( m_data.get_style() == ChartData::STYLE_LINE )
            {
                cr->rel_line_to( 0, m_label_height );
                cr->rel_move_to( m_border_label, -m_label_height );
            }

            cr->save();
            cr->rotate_degrees( 45 );
            m_layout->set_text( txt );
            m_layout->show_in_cairo_context( cr );
            cr->restore();
        }

        void draw_x_values_num( const Cairo::RefPtr< Cairo::Context >& cr )
        {
            auto&&      it_v        { m_data.values_num.begin() };
            const int   step_grid   { 1 }; //( int ) ceil( WIDTH_COL_MIN / m_step_x ) };
            const auto  bar_top     { draw_x_values_str_prepare( cr ) };

            for( int i = 0; i < ( int ) m_step_count; i += step_grid )
            {
                draw_x_value_str_column( cr, STR::format_number( it_v->first ), i, bar_top );
                ++it_v; //std::advance( it_v, step_grid );
            }
        }

        void draw_x_values_str( const Cairo::RefPtr< Cairo::Context >& cr )
        {
            auto&&      it_v        { m_data.values_index2str.begin() };
            const auto  bar_top     { draw_x_values_str_prepare( cr ) };

            for( int i = 0; i < ( int ) m_step_count; i++ )
            {
                draw_x_value_str_column( cr, it_v->second, i, bar_top );
                ++it_v;
            }
        }

        void                        draw_line( const Cairo::RefPtr< Cairo::Context >& );
        void                        draw_line2( const Cairo::RefPtr< Cairo::Context >&, bool );
        void                        draw_bars( const Cairo::RefPtr< Cairo::Context >& );
        void                        draw_bars2( const Cairo::RefPtr< Cairo::Context >&, bool );
        void                        draw_x_values( const Cairo::RefPtr< Cairo::Context >& );
        void                        draw_x_values_date( const Cairo::RefPtr< Cairo::Context >& );
        void                        draw_y_levels( const Cairo::RefPtr< Cairo::Context >& );
        void                        draw_milestones( const Cairo::RefPtr< Cairo::Context >& );
        void                        draw_tooltip( const Cairo::RefPtr< Cairo::Context >& );
        void                        draw_overview( const Cairo::RefPtr< Cairo::Context >& );
        bool                        draw( const Cairo::RefPtr< Cairo::Context >&, int, int );

        // GEOMETRY
        Glib::RefPtr< Pango::Layout > m_layout;
        Pango::FontDescription      m_font_main;
        Pango::FontDescription      m_font_bold;
        Pango::FontDescription      m_font_big;
        const static std::valarray< double >
                                    s_dash_pattern;

        // FLAGS
        bool                        m_F_button_pressed   { false };
        bool                        m_F_overview_hovered { false };
        bool                        m_F_widget_hovered   { false };
        bool                        m_F_printing_mode    { false };
};

} // end of namespace LoG

#endif
