extern crate image;
extern crate rusty_machine;
extern crate serde;
extern crate argparse;
#[macro_use]
extern crate serde_json;



use std::fs;
use std::path::Path;
use argparse::{ArgumentParser, Store};
use image::{FilterType, DynamicImage, GenericImage};
use rusty_machine::linalg::{Matrix, BaseMatrix};
use rusty_machine::learning::k_means::{KMeansClassifier};
use rusty_machine::learning::UnSupModel;

//extern crate palette;


//fn get_color(px:image::Rgba<u8>) {
//    println!("{:?}",px);
//
//}
//
//fn modify(val:u8, percent:u32)-> u8{
//    let ret=((val as u32*percent)+50)/100;
//    ret.min(255) as u8
//}

fn convert(centroids:&Matrix<f64>) -> Vec<String>{

    let mut colorpalette = Vec::new();
    for i in 0..centroids.rows() {
        let colors = centroids.get_row(i).unwrap();
        let hex = format!("#{:02x}{:02x}{:02x}",colors[0] as u8, colors[1] as u8, colors[2] as u8);
        colorpalette.push(hex);
    }
    println!("{:?}", colorpalette);
    colorpalette
}

fn resize_image(img:&DynamicImage, maxpix: f64) -> DynamicImage{
    let dimensions = img.dimensions();
    //    Height = Ratio * Width, Area = Width * height, Width = sqrt(Area/Ratio)
    //    Width = sqrt(A*w0/h0)

    let new_width = (maxpix * dimensions.0 as f64 / dimensions.1 as f64).sqrt();
    let new_height = (maxpix * dimensions.1 as f64 / dimensions.0 as f64).sqrt();
    let scaled = img.resize(new_width as u32, new_height as u32, FilterType::Gaussian);
    scaled
}

fn main() {
    let mut maxpix = 100000.0;
    let mut resize = true;
    let mut clusters:usize = 10;
    let mut file:String = "".to_string();

    {  // this block limits scope of borrows by ap.refer() method
        let mut ap = ArgumentParser::new();
        ap.set_description("Use Neural networks to help group colors in a photo");

        ap.refer(&mut file)
            .add_argument("file", Store,
                          "The path to the file you want to read").required();
        ap.refer(&mut clusters)
            .add_option(&["-k"], Store,
                        "How many colors you want to group into");
        ap.refer(&mut maxpix)
            .add_option(&["--max"], Store,
                        "The maximum amount of pixels to have (will resize to fit)");
        ap.refer(&mut resize)
            .add_option(&["-r"], Store,
                        "Resize the image");
        ap.parse_args_or_exit();
    }


    let orig_img = image::open(Path::new(&file)).unwrap();
    let orig_dimensions = orig_img.dimensions();
    let mut img = orig_img;

    if orig_dimensions.0 * orig_dimensions.1 > maxpix as u32 && resize{
       img = resize_image(&img, maxpix);
    }

    let dimensions = img.dimensions();
    println!("dimensions {:?}",dimensions);

    let mut pixel_data = Vec::new();
    let pixeliter = img.pixels();
    for pixel in pixeliter {
        pixel_data.push(pixel.2[0] as f64);
        pixel_data.push(pixel.2[1] as f64);
        pixel_data.push(pixel.2[2] as f64);
    }
    println!("{:?} Total Pixels",(dimensions.0*dimensions.1) as usize);

    let a = Matrix::new((dimensions.0*dimensions.1) as usize,3,pixel_data);
    let mut model = KMeansClassifier::new(clusters);
    model.train(&a).unwrap();

    println!("{:?}",model);


    let centroids = model.centroids().as_ref().unwrap();
//    println!("Model Centroids:\n{:.0}", centroids);
    let palette = convert(centroids);

    let colors = json!({"image":file,"colors":palette});
    println!("{}",colors);
    let jsoncolor = match serde_json::to_string(&colors) {
        Ok(data) => data,
        Err(e) => "Not able to write data".to_string(),
    };


    fs::write("colors.json", jsoncolor);

//    let slice = MatrixSlice::from_matrix(&centroids, [0,0], 1, 3);
//    let slice = centroids.get_row(0).unwrap();
//
//    println!("{:?}", slice);
}