/*
Copyright 2024, Savanni D'Gerinel <savanni@luminescent-dreams.com>

This file is part of FitnessTrax.

FitnessTrax 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.

FitnessTrax 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 FitnessTrax. If not, see <https://www.gnu.org/licenses/>.
*/

//! ActionGroup and related structures

use glib::Object;
use gtk::{prelude::*, subclass::prelude::*};

#[derive(Default)]
pub struct ActionGroupPrivate;

#[glib::object_subclass]
impl ObjectSubclass for ActionGroupPrivate {
    const NAME: &'static str = "ActionGroup";
    type Type = ActionGroup;
    type ParentType = gtk::Box;
}

impl ObjectImpl for ActionGroupPrivate {}
impl WidgetImpl for ActionGroupPrivate {}
impl BoxImpl for ActionGroupPrivate {}

glib::wrapper! {
    pub struct ActionGroup(ObjectSubclass<ActionGroupPrivate>) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable;
}

impl ActionGroup {
    fn new(builder: ActionGroupBuilder) -> Self {
        let s: Self = Object::builder().build();
        s.set_orientation(builder.orientation);

        let primary_button = builder.primary_action.button();
        let secondary_button = builder.secondary_action.map(|action| action.button());
        let tertiary_button = builder.tertiary_action.map(|action| action.button());

        if let Some(button) = tertiary_button {
            s.append(&button);
        }

        s.set_halign(gtk::Align::End);
        if let Some(button) = secondary_button {
            s.append(&button);
        }
        s.append(&primary_button);

        s
    }

    pub fn builder() -> ActionGroupBuilder {
        ActionGroupBuilder {
            orientation: gtk::Orientation::Horizontal,
            primary_action: Action {
                label: "Ok".to_owned(),
                action: Box::new(|| {}),
            },
            secondary_action: None,
            tertiary_action: None,
        }
    }
}

struct Action {
    label: String,
    action: Box<dyn Fn()>,
}

impl Action {
    fn button(self) -> gtk::Button {
        let button = gtk::Button::builder().label(self.label).build();
        button.connect_clicked(move |_| (self.action)());
        button
    }
}

pub struct ActionGroupBuilder {
    orientation: gtk::Orientation,
    primary_action: Action,
    secondary_action: Option<Action>,
    tertiary_action: Option<Action>,
}

impl ActionGroupBuilder {
    pub fn orientation(mut self, orientation: gtk::Orientation) -> Self {
        self.orientation = orientation;
        self
    }

    pub fn primary_action<A>(mut self, label: &str, action: A) -> Self
    where
        A: Fn() + 'static,
    {
        self.primary_action = Action {
            label: label.to_owned(),
            action: Box::new(action),
        };
        self
    }

    pub fn secondary_action<A>(mut self, label: &str, action: A) -> Self
    where
        A: Fn() + 'static,
    {
        self.secondary_action = Some(Action {
            label: label.to_owned(),
            action: Box::new(action),
        });
        self
    }

    pub fn tertiary_action<A>(mut self, label: &str, action: A) -> Self
    where
        A: Fn() + 'static,
    {
        self.tertiary_action = Some(Action {
            label: label.to_owned(),
            action: Box::new(action),
        });
        self
    }

    pub fn build(self) -> ActionGroup {
        ActionGroup::new(self)
    }
}
