#![allow(dead_code)]
// Import and use floor.rs
use env_logger;
use log;
use parkett::constants::{PLANKMAX, PLANKMIN, PLANKWIDTH, PLAY, ROOMDEPTH, ROOMLENGTH, SAWBLADE};
use parkett::{Cut, Floor, MaterialStorage, Row};

fn main() {
    env_logger::init();

    println!("Halloj golvläggare!\n");

    println!("Room dimensions: {} x {} mm", ROOMLENGTH, ROOMDEPTH);
    println!("Plank play: {} mm", PLAY);
    println!("Sawblade size: {} mm", SAWBLADE);
    println!("Plank width: {} mm", PLANKWIDTH);
    println!("Plank length: {} mm", PLANKMAX);

    // Create a pool of planks
    // To change, modify constants.rs
    let mut ms = MaterialStorage::default();

    // Create an empty "room", floor with no planks
    let mut floor: Floor = Floor::default();

    floor_build(&mut floor, &mut ms);

    println!("{floor}");
    println!("Lycka till!");
    println!("Number of rows: {}", floor.rows_count());
    println!(
        "Number of planks required: {}",
        ms.total_planks - ms.planks_new.len() as u32
    );

    println!("Number of leftover cut planks: {}", ms.get_used_count());
}

fn floor_build(floor: &mut Floor, ms: &mut MaterialStorage) {
    while floor.get_coverage() < ROOMDEPTH {
        let previous_row = floor.rows().last();
        match build_row(ms, previous_row) {
            Some(row) => {
                floor.add(row);
                floor.add_coverage(PLANKWIDTH);
            }
            None => {
                println!("Error: Unable to add more rows.\nExiting");
                return;
            }
        }
    }
    floor.set_complete();
}

fn build_row(ms: &mut MaterialStorage, adjacent_row: Option<&Row>) -> Option<Row> {
    // New empty row
    let mut row: Row = Default::default();

    // Create an initial plank
    let mut plank;

    while row.get_coverage() < row.get_max_length() {
        // Get a plank, used or new, and continue
        plank = ms.try_get_used()?;

        let mut required_length = row.get_max_length() - row.get_coverage();

        if required_length <= PLANKMIN {
            // try to redo previous plank
            // Remove previous plank
            log::info!("Removing plank ending at: {}", row.get_coverage());
            row.pop(ms);
            // Calculate new required length but divide by two
            required_length = (row.get_max_length() - row.get_coverage()) / 2;
        }

        match plank.length() {
            length if length < PLANKMIN => {
                log::info!("Invalid plank case");
                // Check if the plank is too short, then take a new one
                ms.discard_unusable(plank);
            }
            length if length > required_length => {
                log::info!("Cut plank case");
                // Cut the plank to length
                let (plankpart, leftover) = plank.cut_to_length(required_length);

                // Add the remainder of plank to the row (move)
                row.add(plankpart);
                // Add the remaining plank to material storage
                ms.store_used(leftover);
            }
            length if length == (required_length) => {
                log::info!("Exact length plank case");
                // If the plank is the same length as the room, no need to cut

                // Use the whole plank
                row.add(plank);
            }
            _ => {
                // Plank is shorter than the room, need multiple
                log::info!("Short plank case");

                // Use the whole plank
                row.add(plank);
            }
        }
        if let Some(adjacent_row) = adjacent_row {
            // Check if the newly added plank lands too close to a previous cut
            // or a new one
            let coordinate = row.get_coverage();
            if !adjacent_row.check_if_cut_is_valid(Cut::new(coordinate)) {
                log::info!("Invalid cut at {coordinate}!!! Swapping places");
                log::info!("Row:\n{adjacent_row}");
                log::info!("Adding:\n{row}");
                if row.planks_count() >= 2 {
                    row.swap_latest(ms);
                } else {
                    log::error!("Can't swap with only one:\n{row}");
                }
            }
        }
    }
    // The row is now full
    row.set_full();
    // Set first and last planks as endpieces
    row.set_first_and_last_as_endpieces();

    Some(row)
}