
extern crate piston_window;
extern crate sprite;
extern crate winit;
extern crate serde_json; 
extern crate ai_behavior;
extern crate music;

use piston_window::*;
use sprite::*;
use serde_json::{Result, Value};
use ai_behavior::*;

fn find_files(dir: &str) -> Vec<std::string::String>
{
    let paths = std::fs::read_dir(dir).unwrap();
    let mut files : Vec<std::string::String> = vec![];
    for path in paths {
        let p = path.unwrap();
        if p.file_type().unwrap().is_dir()
        {
            files.append( &mut find_files( p.path().to_str().unwrap() ) );
        }
        else
        {
            files.push( p.path().into_os_string().into_string().unwrap() );
        }
    }
    files
}

#[derive(Copy, Clone, Hash, PartialEq, Eq)]
enum Music {
    Musa,
}

#[derive(Copy, Clone, Hash, PartialEq, Eq)]
enum Sound {
    Jumalauta,
}


fn main() {
    let file_path = "./stuff";
    let files = find_files(file_path);

    // que?
    std::env::set_var("LD_LIBRARY_PATH", ".");

    let music_str : Option<&std::string::String> = 
        files.iter().find(|s| s.to_lowercase().ends_with(".mp3") || s.to_lowercase().ends_with(".ogg") );


    // match found filenames to ones in json, if exists, otherwise take all
    let images : Vec<&std::string::String> = match files.iter().find( |s| s.to_lowercase().ends_with(".json") && !s.contains("debug") && !s.contains("/.") ) {
        Some(filename) => {
            let file = std::fs::File::open(filename);
            let reader = std::io::BufReader::new(file.unwrap());
            let u : Result<serde_json::Value> = serde_json::from_reader(reader);
            u.unwrap().as_array().unwrap().iter().map(
                |s| files.iter().find(|k| k.ends_with(s[0].as_str().unwrap())).unwrap()
            ).collect()
        }
        None => {
            files.iter().filter(|s|
                s.to_lowercase().ends_with(".jpg") || s.to_lowercase().ends_with(".png")
            ).collect()
        }
    };

    // Get timestamps from json if exists, otherwise spread evenly across the song
    // Read the same JSON for a second time with copy paste 'cause I don't know Rust
    let music_length = 120000;
    let music_posses : Vec<u32> = match files.iter().find( |s| s.to_lowercase().ends_with(".json") && !s.contains("debug") && !s.contains("/.") ) {
        Some(filename) => {
            let file = std::fs::File::open(filename);
            let reader = std::io::BufReader::new(file.unwrap());
            let u : Result<serde_json::Value> = serde_json::from_reader(reader);
            u.unwrap().as_array().unwrap().iter().map(
                |s| s[1].as_i64().unwrap() as u32
            ).collect()
        }
        None => {
            (0..images.len()).map(
                |s| (s as u32 *music_length/images.len() as u32 )
            ).collect()
        }
    };

    // Get sprite animation parameters json if exists
    // Read the same JSON for a third time with copy paste 'cause I don't know Rust
    let anime_params : Vec<Vec<f64>> = match files.iter().find( |s| s.to_lowercase().ends_with(".json") && !s.contains("debug") && !s.contains("/.") ) {
        Some(filename) => {
            let file = std::fs::File::open(filename);
            let reader = std::io::BufReader::new(file.unwrap());
            let u : Result<serde_json::Value> = serde_json::from_reader(reader);
            u.unwrap().as_array().unwrap().iter().map(
                |s| s[2].as_array().unwrap().iter().map(
                    |s2| s2.as_f64().unwrap()
                ).collect()
            ).collect()
        }
        None => {
            (0..images.len()).map(
                |s| vec![0.0, 0.0,0.0, 0.0,0.0, 0.0, 0.0]
            ).collect()
        }
    };

    // fuck it. use winit to get screen resolution as piston sucks
    //let events_loop = winit::EventsLoop::new();
    // might be get_current_monitor() but no clue which one piston will use
    //let monitor: winit::MonitorId = events_loop.get_primary_monitor();
    //let (screen_width, screen_height) = monitor.get_dimensions();
    let screen_width = 1920;
    let screen_height = 1080;

    let opengl = OpenGL::V3_2;
    let mut window: PistonWindow = WindowSettings::new("kauhanen", [screen_width,screen_height])
        .exit_on_esc(true)
        .graphics_api(opengl)
        .fullscreen(true)
        .build()
        .unwrap();


    let mut texture_context = TextureContext {
      factory: window.factory.clone(),
      encoder: window.factory.create_command_buffer().into()
    };
    // load images  and create textures
    let mut images_loaded : Vec<std::rc::Rc<_>> =
        images.iter().map(|s| 
            std::rc::Rc::new(Texture::from_path(
              &mut texture_context,
              s,
              Flip::None,
              &TextureSettings::new()
            ).unwrap())
        )
        .collect();


    println!("wifth: {:?} {:?}", screen_height, screen_width);
    let mut last = 0;
    let mut scene = sprite::Scene::new();
    let mut image_iter = images_loaded.iter();
    let mut anime_iter = anime_params.iter();

    music::start::<Music, Sound, _>(16, || {
        music::bind_music_file(Music::Musa, music_str.unwrap());
        music::set_volume(music::MAX_VOLUME);
        music::play_music(&Music::Musa, music::Repeat::Times(1));
        let start = std::time::SystemTime::now();

        while let Some(e) = window.next() {
            let mut pos = std::time::SystemTime::now()
                .duration_since(start).unwrap().as_millis();
            if last < music_posses.len() && pos >= music_posses[last] as u128
            {
                let mut tex = image_iter.next().unwrap();
                let mut spr = sprite::Sprite::from_texture(tex.clone());
                let child_id = scene.add_child(spr);

                // animation parameters
                let anime_prs = anime_iter.next().unwrap();
                if anime_prs[0] > 0.0 {
                    scene.child_mut(child_id).unwrap().set_position(anime_prs[1], anime_prs[2]);
                    scene.child_mut(child_id).unwrap().set_rotation(anime_prs[5]);
                    let anime_move = sprite::Animation::MoveTo(
                        anime_prs[0], anime_prs[3], anime_prs[4]
                    );
                    let anime_rotate = sprite::Animation::RotateTo(
                        anime_prs[0], anime_prs[6]
                    );
                    let anime_move_b = Behavior::Action(anime_move);
                    let anime_rotate_b = Behavior::Action(anime_rotate);
                    scene.run(child_id, &anime_move_b);
                    scene.run(child_id, &anime_rotate_b);
                } else {
                    scene.child_mut(child_id).unwrap().set_position( screen_width as f64 /2.,screen_height as f64 /2.);
                }

                last = last + 1;
            }

            scene.event(&e);
            window.draw_2d(&e, |c, g, _| {
                clear([1.0, 1.0, 1.0, 1.0], g);
                scene.draw(c.transform, g);
            });
            let is_playing = pos < music_length as u128;
            if is_playing == false
            {
            return;
            }
        }
    })

}

