// Copyright 2019 The Druid Authors.
//
// 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 at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A widget that provides simple visual styling options to a child.

use druid::widget::prelude::*;
use druid::{Color, Data, KeyOrValue, Point, WidgetPod};

use crate::{view, DruidAppData, MutableWidget, Payload, SingleChild};

struct BorderStyle {
    width: f64,
    color: Color,
}

/// A widget that provides simple visual styling options to a child.
pub struct Container {
    view: view::Container,
    inner: SingleChild,
}

impl Container {
    /// Create Container with a child
    pub fn new(view: view::Container) -> Self {
        Self {
            view,
            inner: SingleChild::new(),
        }
    }
}

impl MutableWidget for Container {
    fn mutate(
        &mut self,
        ctx: &mut EventCtx,
        body: Option<&crate::Payload>,
        mut_iter: crate::MutationIter,
    ) {
        if let Some(Payload::View(v)) = body {
            if let Some(v) = v.as_any().downcast_ref::<view::Container>() {
                self.view = v.clone();
                ctx.request_layout();
            }
        }
        self.inner.mutate(ctx, mut_iter);
    }
}

impl Widget<DruidAppData> for Container {
    fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut DruidAppData, env: &Env) {
        self.inner.event(ctx, event, data, env);
    }

    fn lifecycle(
        &mut self,
        ctx: &mut LifeCycleCtx,
        event: &LifeCycle,
        data: &DruidAppData,
        env: &Env,
    ) {
        self.inner.lifecycle(ctx, event, data, env)
    }

    fn update(
        &mut self,
        ctx: &mut UpdateCtx,
        old_data: &DruidAppData,
        data: &DruidAppData,
        env: &Env,
    ) {
        self.inner.update(ctx, old_data, data, env);
    }

    fn layout(
        &mut self,
        ctx: &mut LayoutCtx,
        bc: &BoxConstraints,
        data: &DruidAppData,
        env: &Env,
    ) -> Size {
        bc.debug_check("Container");

        // Shrink constraints by border offset
        let border_width = self.view.border_size.unwrap_or(0.);
        let child_bc = bc.shrink((2.0 * border_width, 2.0 * border_width));
        let size = self.inner.layout(ctx, &child_bc, data, env);

        let my_size = Size::new(
            size.width + 2.0 * border_width,
            size.height + 2.0 * border_width,
        );

        let origin = Point::new(border_width, border_width);
        if let Some(w) = self.inner.get_mut() {
            w.set_origin(ctx, data, env, origin);
            let my_insets = w.compute_parent_paint_insets(my_size);
            ctx.set_paint_insets(my_insets);
        }

        my_size
    }

    fn paint(&mut self, ctx: &mut PaintCtx, data: &DruidAppData, env: &Env) {
        if let Some(bgcolor) = &self.view.background {
            let panel = ctx.size().to_rect();
            ctx.fill(panel, bgcolor)
        }

        if let (Some(b_color), Some(b_width)) = (&self.view.border_color, self.view.border_size) {
            let border_rect = ctx.size().to_rect().inset(b_width / -2.0);
            ctx.stroke(border_rect, b_color, b_width);
        };

        self.inner.paint(ctx, data, env);
    }
}
