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

This file is part of the Luminescent Dreams Tools.

Luminescent Dreams Tools 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.

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

use chrono::{Datelike, Utc};
use ifc as IFC;
use iron::headers;
use iron::middleware::Handler;
use iron::modifiers::Header;
use iron::prelude::*;
use iron::status;
use mustache::{compile_str, Template};
use router::Router;
use serde::Serialize;

pub const STYLES: &'static str = include_str!("static/styles.css");
pub const INDEX: &'static str = include_str!("static/index.html");

pub struct IndexHandler {
    pub template: Template,
}

#[derive(Serialize)]
pub struct DayEntry {
    day: u8,
    highlight: String,
}

#[derive(Serialize)]
pub struct Week {
    days: Vec<DayEntry>,
}

impl Week {
    fn new(start_day: u8, today: u8) -> Week {
        Week {
            days: (1..8)
                .map(|d| DayEntry {
                    day: d + start_day,
                    highlight: if today == (d + start_day) {
                        String::from("today")
                    } else {
                        String::from("")
                    },
                })
                .collect(),
        }
    }
}

#[derive(Serialize)]
pub struct IndexTemplateParams {
    month: String,
    year: i32,
    weeks: Vec<Week>,
}

impl IndexTemplateParams {
    fn new(date: IFC::IFC) -> IndexTemplateParams {
        let day = date.day() as u8;
        IndexTemplateParams {
            month: String::from(IFC::Month::from(date.month())),
            year: date.year(),
            weeks: (0..4).map(|wn| Week::new(wn * 7, day)).collect(),
        }
    }
}

impl Handler for IndexHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        let d = IFC::IFC::from(Utc::today());
        Ok(Response::with((
            status::Ok,
            Header(headers::ContentType(iron::mime::Mime(
                iron::mime::TopLevel::Text,
                iron::mime::SubLevel::Html,
                vec![],
            ))),
            self.template
                .render_to_string(&IndexTemplateParams::new(d))
                .expect("the template to render"),
        )))
    }
}

fn css(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((
        status::Ok,
        Header(headers::ContentType(iron::mime::Mime(
            iron::mime::TopLevel::Text,
            iron::mime::SubLevel::Css,
            vec![],
        ))),
        STYLES,
    )))
}

fn main() {
    let mut router = Router::new();
    router.get(
        "/",
        IndexHandler {
            template: compile_str(INDEX).expect("the template to compile"),
        },
        "index",
    );

    router.get("/css", css, "styles");

    Iron::new(router).http("127.0.0.1:3000").unwrap();
}
