// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License in the LICENSE-APACHE file or at:
//     https://www.apache.org/licenses/LICENSE-2.0

//! Custom theme demo
#![cfg_attr(feature = "gat", feature(generic_associated_types))]

use std::cell::Cell;

use kas::draw::color::Rgba;
use kas::draw::*;
use kas::prelude::*;
use kas::theme::Theme;
use kas::widgets::*;

use kas::theme::FlatTheme;

/// A demo theme
///
/// We set a custom background colour and use `FlatTheme` for everything else.
#[derive(Clone, Default)]
pub struct CustomTheme {
    inner: FlatTheme,
}

thread_local! {
    // Cell is not thread-safe. Lazy way to solve that :-D
    static BACKGROUND: Cell<Rgba> = Cell::new(Rgba::grey(1.0));
}

impl<DS: DrawSharedImpl> Theme<DS> for CustomTheme
where
    DS::Draw: DrawRoundedImpl,
{
    type Config = kas::theme::Config;
    type Window = <FlatTheme as Theme<DS>>::Window;

    #[cfg(not(feature = "gat"))]
    type DrawHandle = <FlatTheme as Theme<DS>>::DrawHandle;
    #[cfg(feature = "gat")]
    type DrawHandle<'a> = <FlatTheme as Theme<DS>>::DrawHandle<'a>;

    fn config(&self) -> std::borrow::Cow<Self::Config> {
        Theme::<DS>::config(&self.inner)
    }

    fn apply_config(&mut self, config: &Self::Config) -> TkAction {
        Theme::<DS>::apply_config(&mut self.inner, config)
    }

    fn init(&mut self, shared: &mut SharedState<DS>) {
        self.inner.init(shared);
    }

    fn new_window(&self, dpi_factor: f32) -> Self::Window {
        Theme::<DS>::new_window(&self.inner, dpi_factor)
    }

    fn update_window(&self, window: &mut Self::Window, dpi_factor: f32) {
        Theme::<DS>::update_window(&self.inner, window, dpi_factor);
    }

    #[cfg(not(feature = "gat"))]
    unsafe fn draw_handle(
        &self,
        draw: DrawIface<DS>,
        window: &mut Self::Window,
    ) -> Self::DrawHandle {
        Theme::<DS>::draw_handle(&self.inner, draw, window)
    }
    #[cfg(feature = "gat")]
    fn draw_handle<'a>(
        &'a self,
        draw: DrawIface<'a, DS>,
        window: &'a mut Self::Window,
    ) -> Self::DrawHandle<'a> {
        Theme::<DS>::draw_handle(&self.inner, draw, window)
    }

    fn clear_color(&self) -> Rgba {
        BACKGROUND.with(|b| b.get())
    }
}

impl ThemeControl for CustomTheme {
    fn set_font_size(&mut self, size: f32) -> TkAction {
        self.inner.set_font_size(size)
    }

    fn list_schemes(&self) -> Vec<&str> {
        self.inner.list_schemes()
    }

    fn set_scheme(&mut self, scheme: &str) -> TkAction {
        self.inner.set_scheme(scheme)
    }
}

#[derive(Clone, Debug, VoidMsg)]
enum Item {
    White,
    Red,
    Green,
    Yellow,
}

fn main() -> kas::shell::Result<()> {
    env_logger::init();

    let widgets = make_widget! {
        #[widget{
            layout = grid: {
                1, 1: self.label;
                0, 1: self.white;
                1, 2: self.red;
                2, 1: self.yellow;
                1, 0: self.green;
            };
        }]
        #[handler(msg = Item)]
        struct {
            #[widget] label = Label::new("Custom theme demo\nChoose your colour!"),
            #[widget] white = TextButton::new_msg("&White", Item::White),
            #[widget] red = TextButton::new_msg("&Red", Item::Red),
            #[widget] yellow = TextButton::new_msg("&Yellow", Item::Yellow),
            #[widget] green = TextButton::new_msg("&Green", Item::Green),
        }
    };

    let theme = CustomTheme::default();

    let window = Window::new(
        "Theme demo",
        make_widget! {
            #[widget{
                layout = single;
            }]
            #[handler(msg = VoidMsg)]
            struct {
                #[widget(use_msg = handler)] _ = widgets,
            }
            impl Self {
                fn handler(&mut self, _: &mut EventMgr, item: Item) {
                    match item {
                        Item::White => BACKGROUND.with(|b| b.set(Rgba::WHITE)),
                        Item::Red => BACKGROUND.with(|b| b.set(Rgba::rgb(0.9, 0.2, 0.2))),
                        Item::Green => BACKGROUND.with(|b| b.set(Rgba::rgb(0.2, 0.9, 0.2))),
                        Item::Yellow => BACKGROUND.with(|b| b.set(Rgba::rgb(0.9, 0.9, 0.2))),
                    };
                }
            }
        },
    );

    kas::shell::Toolkit::new(theme)?.with(window)?.run()
}
