<commit_before>//
//  yas_ui_collection_layout.cpp
//

#include "yas_delaying_caller.h"
#include "yas_property.h"
#include "yas_ui_collection_layout.h"
#include "yas_ui_layout.h"
#include "yas_ui_layout_guide.h"
#include "yas_fast_each.h"

using namespace yas;

#pragma mark - ui::collection_layout::line

bool ui::collection_layout::line::operator==(line const &rhs) const {
    if (this->new_line_min_offset != rhs.new_line_min_offset) {
        return false;
    }

    auto const cell_count = this->cell_sizes.size();

    if (cell_count != rhs.cell_sizes.size()) {
        return false;
    }

    auto each = make_fast_each(cell_count);
    while (yas_each_next(each)) {
        auto const &idx = yas_each_index(each);
        if (this->cell_sizes.at(idx) != rhs.cell_sizes.at(idx)) {
            return false;
        }
    }

    return true;
}

bool ui::collection_layout::line::operator!=(line const &rhs) const {
    return !(*this == rhs);
}

#pragma mark - ui::colleciton_layout::impl

struct ui::collection_layout::impl : base::impl {
    struct cell_location {
        std::size_t line_idx;
        std::size_t cell_idx;
    };

    property<float> _row_spacing_property;
    property<float> _col_spacing_property;
    property<ui::layout_alignment> _alignment_property;
    property<ui::layout_direction> _direction_property;
    property<ui::layout_order> _row_order_property;
    property<ui::layout_order> _col_order_property;
    property<std::size_t> _preferred_cell_count_property;
    property<ui::size> _default_cell_size_property;
    property<std::vector<ui::collection_layout::line>> _lines_property;

    ui::layout_guide_rect _frame_guide_rect;
    ui::layout_guide_rect _border_guide_rect;
    std::vector<ui::layout_guide_rect> _cell_guide_rects;
    ui::layout _left_border_layout;
    ui::layout _right_border_layout;
    ui::layout _bottom_border_layout;
    ui::layout _top_border_layout;
    ui::layout_borders const _borders;
    subject_t _subject;

    impl(args &&args)
        : _frame_guide_rect(std::move(args.frame)),
          _preferred_cell_count_property({.value = args.preferred_cell_count}),
          _default_cell_size_property(
              {.value = std::move(args.default_cell_size),
               .validator = [](auto const &value) { return value.width >= 0.0f && value.height >= 0.0f; }}),
          _lines_property({.value = std::move(args.lines),
                           .validator =
                               [](auto const &value) {
                                   for (auto const &line : value) {
                                       if (line.new_line_min_offset < 0.0f) {
                                           return false;
                                       }

                                       for (auto const &cell_size : line.cell_sizes) {
                                           if (cell_size.width < 0.0f || cell_size.height < 0.0f) {
                                               return false;
                                           }
                                       }
                                   }
                                   return true;
                               }}),
          _row_spacing_property(
              {.value = args.row_spacing, .validator = [](auto const &value) { return value >= 0.0f; }}),
          _col_spacing_property(
              {.value = args.col_spacing, .validator = [](auto const &value) { return value >= 0.0f; }}),
          _alignment_property({.value = args.alignment}),
          _direction_property({.value = args.direction}),
          _row_order_property({.value = args.row_order}),
          _col_order_property({.value = args.col_order}),
          _left_border_layout(ui::make_layout({.source_guide = _frame_guide_rect.left(),
                                               .destination_guide = _border_guide_rect.left(),
                                               .distance = args.borders.left})),
          _right_border_layout(ui::make_layout({.source_guide = _frame_guide_rect.right(),
                                                .destination_guide = _border_guide_rect.right(),
                                                .distance = -args.borders.right})),
          _bottom_border_layout(ui::make_layout({.source_guide = _frame_guide_rect.bottom(),
                                                 .destination_guide = _border_guide_rect.bottom(),
                                                 .distance = args.borders.bottom})),
          _top_border_layout(ui::make_layout({.source_guide = _frame_guide_rect.top(),
                                              .destination_guide = _border_guide_rect.top(),
                                              .distance = -args.borders.top})),
          _borders(std::move(args.borders)) {
        if (args.borders.left < 0 || args.borders.right < 0 || args.borders.bottom < 0 || args.borders.top < 0) {
            throw "borders value is negative.";
        }
    }

    void prepare(ui::collection_layout &layout) {
        this->_border_guide_rect.set_value_changed_handler([weak_layout = to_weak(layout)](auto const &) {
            if (auto layout = weak_layout.lock()) {
                layout.impl_ptr<impl>()->_update_layout();
            }
        });

        auto weak_layout = to_weak(layout);

        auto property_handler = [weak_layout](ui::collection_layout::method const &method) {
            if (auto layout = weak_layout.lock()) {
                auto layout_impl = layout.impl_ptr<impl>();
                layout_impl->_update_layout();
                layout_impl->_subject.notify(method, layout);
            }
        };

        this->_property_observers.emplace_back(_row_spacing_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::row_spacing_changed);
            }));

        this->_property_observers.emplace_back(_col_spacing_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::col_spacing_changed);
            }));

        this->_property_observers.emplace_back(_alignment_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::alignment_changed);
            }));

        this->_property_observers.emplace_back(_direction_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::direction_changed);
            }));

        this->_property_observers.emplace_back(_row_order_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::row_order_changed);
            }));

        this->_property_observers.emplace_back(_col_order_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::col_order_changed);
            }));

        this->_property_observers.emplace_back(_preferred_cell_count_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::preferred_cell_count_changed);
            }));

        this->_property_observers.emplace_back(_default_cell_size_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::default_cell_size_changed);
            }));

        this->_property_observers.emplace_back(_lines_property.subject().make_observer(<commit_msg>collection_layout this<commit_after>//
//  yas_ui_collection_layout.cpp
//

#include "yas_delaying_caller.h"
#include "yas_property.h"
#include "yas_ui_collection_layout.h"
#include "yas_ui_layout.h"
#include "yas_ui_layout_guide.h"
#include "yas_fast_each.h"

using namespace yas;

#pragma mark - ui::collection_layout::line

bool ui::collection_layout::line::operator==(line const &rhs) const {
    if (this->new_line_min_offset != rhs.new_line_min_offset) {
        return false;
    }

    auto const cell_count = this->cell_sizes.size();

    if (cell_count != rhs.cell_sizes.size()) {
        return false;
    }

    auto each = make_fast_each(cell_count);
    while (yas_each_next(each)) {
        auto const &idx = yas_each_index(each);
        if (this->cell_sizes.at(idx) != rhs.cell_sizes.at(idx)) {
            return false;
        }
    }

    return true;
}

bool ui::collection_layout::line::operator!=(line const &rhs) const {
    return !(*this == rhs);
}

#pragma mark - ui::colleciton_layout::impl

struct ui::collection_layout::impl : base::impl {
    struct cell_location {
        std::size_t line_idx;
        std::size_t cell_idx;
    };

    property<float> _row_spacing_property;
    property<float> _col_spacing_property;
    property<ui::layout_alignment> _alignment_property;
    property<ui::layout_direction> _direction_property;
    property<ui::layout_order> _row_order_property;
    property<ui::layout_order> _col_order_property;
    property<std::size_t> _preferred_cell_count_property;
    property<ui::size> _default_cell_size_property;
    property<std::vector<ui::collection_layout::line>> _lines_property;

    ui::layout_guide_rect _frame_guide_rect;
    ui::layout_guide_rect _border_guide_rect;
    std::vector<ui::layout_guide_rect> _cell_guide_rects;
    ui::layout _left_border_layout;
    ui::layout _right_border_layout;
    ui::layout _bottom_border_layout;
    ui::layout _top_border_layout;
    ui::layout_borders const _borders;
    subject_t _subject;

    impl(args &&args)
        : _frame_guide_rect(std::move(args.frame)),
          _preferred_cell_count_property({.value = args.preferred_cell_count}),
          _default_cell_size_property(
              {.value = std::move(args.default_cell_size),
               .validator = [](auto const &value) { return value.width >= 0.0f && value.height >= 0.0f; }}),
          _lines_property({.value = std::move(args.lines),
                           .validator =
                               [](auto const &value) {
                                   for (auto const &line : value) {
                                       if (line.new_line_min_offset < 0.0f) {
                                           return false;
                                       }

                                       for (auto const &cell_size : line.cell_sizes) {
                                           if (cell_size.width < 0.0f || cell_size.height < 0.0f) {
                                               return false;
                                           }
                                       }
                                   }
                                   return true;
                               }}),
          _row_spacing_property(
              {.value = args.row_spacing, .validator = [](auto const &value) { return value >= 0.0f; }}),
          _col_spacing_property(
              {.value = args.col_spacing, .validator = [](auto const &value) { return value >= 0.0f; }}),
          _alignment_property({.value = args.alignment}),
          _direction_property({.value = args.direction}),
          _row_order_property({.value = args.row_order}),
          _col_order_property({.value = args.col_order}),
          _left_border_layout(ui::make_layout({.source_guide = _frame_guide_rect.left(),
                                               .destination_guide = _border_guide_rect.left(),
                                               .distance = args.borders.left})),
          _right_border_layout(ui::make_layout({.source_guide = _frame_guide_rect.right(),
                                                .destination_guide = _border_guide_rect.right(),
                                                .distance = -args.borders.right})),
          _bottom_border_layout(ui::make_layout({.source_guide = _frame_guide_rect.bottom(),
                                                 .destination_guide = _border_guide_rect.bottom(),
                                                 .distance = args.borders.bottom})),
          _top_border_layout(ui::make_layout({.source_guide = _frame_guide_rect.top(),
                                              .destination_guide = _border_guide_rect.top(),
                                              .distance = -args.borders.top})),
          _borders(std::move(args.borders)) {
        if (args.borders.left < 0 || args.borders.right < 0 || args.borders.bottom < 0 || args.borders.top < 0) {
            throw "borders value is negative.";
        }
    }

    void prepare(ui::collection_layout &layout) {
        this->_border_guide_rect.set_value_changed_handler([weak_layout = to_weak(layout)](auto const &) {
            if (auto layout = weak_layout.lock()) {
                layout.impl_ptr<impl>()->_update_layout();
            }
        });

        auto weak_layout = to_weak(layout);

        auto property_handler = [weak_layout](ui::collection_layout::method const &method) {
            if (auto layout = weak_layout.lock()) {
                auto layout_impl = layout.impl_ptr<impl>();
                layout_impl->_update_layout();
                layout_impl->_subject.notify(method, layout);
            }
        };

        this->_property_observers.emplace_back(this->_row_spacing_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::row_spacing_changed);
            }));

        this->_property_observers.emplace_back(this->_col_spacing_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::col_spacing_changed);
            }));

        this->_property_observers.emplace_back(this->_alignment_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::alignment_changed);
            }));

        this->_property_observers.emplace_back(this->_direction_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::direction_changed);
            }));

        this->_property_observers.emplace_back(this->_row_order_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::row_order_changed);
            }));

        this->_property_observers.emplace_back(this->_col_order_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::col_order_changed);
            }));

        this->_property_observers.emplace_back(this->_preferred_cell_count_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::preferred_cell_count_changed);
            }));

        this->_property_observers.emplace_back(this->_default_cell_size_property.subject().make_observer(
            property_method::did_change, [property_handler](auto const &context) {
                property_handler(ui::collection_layout::method::default_cell_size_changed);
            }));

        this->_property_observers.emplace_back(this->_lines_property.subject().make_observer(
{'fraction_non_alphanumeric': 0.11218999319685818, 'fraction_numerical': 0.0022264827756818604, 'mean_word_length': 2.247640088371159, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 78, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 64, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2467829', 'n_tokens_mistral': 4532, 'n_tokens_neox': 4368, 'n_words': 608}