extern crate cairo;
#[macro_use] extern crate failure;
extern crate pango;
extern crate pangocairo;
extern crate rrecutils;
extern crate rsvg;

mod markup;
mod data;

use markup::Weight;

use std::{fs,io};
use rsvg::HandleExt;

const SCALE: i32 = 3;

fn draw_card(card: &data::Card) -> Result<(), failure::Error> {
    use data::CardType::*;

    let surf = cairo::ImageSurface::create(
        cairo::Format::Rgb24,
        4 * SCALE * 100,
        1 * SCALE * 100,
    ).map_err(|e| format_err!("Unable to create Cairo surface: {:?}", e))?;

    let ctx = cairo::Context::new(&surf);
    ctx.scale(SCALE as f64, SCALE as f64);
    ctx.set_source_rgb(1.0, 1.0, 1.0);
    ctx.paint();

    ctx.set_source_rgb(0.56, 0.56, 0.56);
    ctx.rectangle(10.0, 10.0, 80.0, 80.0);
    ctx.stroke();

    ctx.move_to(105.0, 30.0);
    ctx.line_to(105.0, 90.0);
    ctx.stroke();

    ctx.set_source_rgb(0.0, 0.0, 0.0);

    ctx.move_to(100.0, 8.0);
    let mut buf = markup::MarkupBuffer::new();

    match card.card_type {
        Weapon { ref weapon_type, .. } =>
            buf.push(&format!("{} (Weapon, {:?})", card.name, weapon_type)),
        Monster { ref hp, ref melee, ref ranged, ref arcane, ref defense, .. } => {
            buf.push(&format!("{} (Beast ", card.name));

            buf.markup().size(8).weight(Weight::Heavy).push("HP");
            buf.push(&format!("{}", hp));

            if let &Some(ref m) = melee {
                buf.space();
                buf.markup().size(8).weight(Weight::Heavy).push("M");
                buf.push(m);
            }

            if let &Some(ref m) = ranged {
                buf.space();
                buf.markup().size(8).weight(Weight::Heavy).push("R");
                buf.push(m);
            }

            if let &Some(ref m) = arcane {
                buf.space();
                buf.markup().size(8).weight(Weight::Heavy).push("A");
                buf.push(m);
            }

            if let &Some(ref m) = defense {
                buf.space();
                buf.markup().size(8).weight(Weight::Heavy).push("D");
                buf.push(m);
            }
            buf.push(")");
        }
        Generic { ref kind, .. } =>
            buf.push(&format!("{} ({:?})", card.name, kind)),
    };

    buf.show_with_font(
        &ctx,
        markup::Font::new("Fira Sans").size(12).weight(Weight::Bold),
        None,
    )?;

    ctx.move_to(115.0, 26.0);
    let mut buf = markup::MarkupBuffer::new();

    match card.card_type {
        Weapon { ability, effect, .. } => {
            buf.markup().weight(Weight::Bold).push(&format!("{}: ", ability));
            buf.push(effect);
        },
        Monster { action, effect, .. } => {
            buf.markup().weight(Weight::Bold).push(&format!("{}: ", action));
            buf.push(effect);
        },
        Generic { effect, .. } => {
            buf.push(effect);
        },
    };

    buf.show_with_font(
        &ctx,
        markup::Font::new("Fira Sans").size(10),
        Some(390 - 115)
    )?;

    let icon = rsvg::Handle::new_from_file(&card.icon)
        .map_err(|_| format_err!("Error loading image: {}", card.icon))?;
    ctx.translate(10.0, 10.0);
    ctx.scale(0.9, 0.9);
    icon.render_cairo(&ctx);


    let path = format!("cards/{}_{}.png", card.type_name(), card.card_name());
    let mut f = fs::File::create(&path)?;
    println!("Writing to {}", path);
    surf.write_to_png(&mut f)?;

    Ok(())
}

fn run() -> Result<(), failure::Error> {
    let mut f = io::BufReader::new(fs::File::open("cards.rec")?);
    let recfile = rrecutils::Recfile::parse(&mut f)?;

    for w in recfile.iter() {
        if w.rec_type.is_some() {
            let card = data::Card::from_record(w)?;
            draw_card(&card)?;
        }
    }

    Ok(())
}

fn main() {
    run().unwrap();
}
