use std::sync::{Arc, Mutex, RwLock};
use std::cell::RefCell;
use super::cluster_alg::*;
use super::cluster_type::*;
use super::cluster_trait::*;
use super::cluster_helper::*;
use super::simple_thread_pool::*;
use crate::database::db_type::{RWDist};

use std::time::Duration;
use std::thread;
use num_cpus;

/*
fn get_fake_cluster() -> Result<Arc<Mutex<Vec<WinDistCenterPtr>>>, String> {
    let mut fake_clusters: Arc<Mutex<Vec<WinDistCenterPtr>>> = Arc::new(Mutex::new(Vec::new()));
    let mut lock_fake_clusters = fake_clusters.lock().unwrap();
    lock_fake_clusters.push(Arc::new(Mutex::new(WinDistCenter::new(
        Arc::new(WinDistNode::new(6, [30, 30, 30], 0))
    ))));
    lock_fake_clusters.push(Arc::new(Mutex::new(WinDistCenter::new(
        Arc::new(WinDistNode::new(7, [20, 20, 70], 0))
    ))));
    Ok(fake_clusters)
}
*/

fn get_fake_points() -> Result<Vec<WinDistNodePtr>, String> {
    let mut fake_points: Vec<WinDistNodePtr> = Vec::new();
    fake_points.push(Arc::new(WinDistNode::new(1, [10, 20, 70], 0)));
    fake_points.push(Arc::new(WinDistNode::new(2, [20, 20, 60], 0)));
    fake_points.push(Arc::new(WinDistNode::new(3, [30, 20, 50], 0)));
    fake_points.push(Arc::new(WinDistNode::new(4, [40, 20, 40], 0)));
    fake_points.push(Arc::new(WinDistNode::new(5, [50, 20, 30], 0)));
    Ok(fake_points)
}

pub fn testing(){
    
    let num_threads = 2 ;//num_cpus::get();
    
    let mut fake_clusters: Arc<Mutex<Vec<WinDistCenterPtr>>> = 
    Arc::new(Mutex::new(Vec::new()));
    fake_clusters.lock().unwrap().push(Arc::new(Mutex::new(WinDistCenter::new(
        Arc::new(WinDistNode::new(6, [10, 30, 300], 0))
    ))));
    fake_clusters.lock().unwrap().push(Arc::new(Mutex::new(WinDistCenter::new(
        Arc::new(WinDistNode::new(7, [20, 200, 70], 0))
    ))));
    
    let mut fake_points: Vec<WinDistNodePtr>   = get_fake_points().unwrap();

    let pool = ThreadPool::new(num_threads);
    for (_, fake_point_ref) in fake_points.iter().enumerate() {
        let fake_point = fake_point_ref.clone();
        let mut fake_clusters_unlock = fake_clusters.clone();
        pool.execute(move || {

            let mut min_centorid: WinDistCenterPtr = 
            Arc::new(Mutex::new(WinDistCenter::new(
                Arc::new(WinDistNode::new(-1, [0, 0, 0], 0))
            )));
            let mut min_dist = std::f64::MAX;

            for (_, centroid) in fake_clusters_unlock.lock().unwrap().iter().enumerate(){
                let dist = fake_point.cul_distance(centroid.clone()).unwrap();
                if dist < min_dist{
                    min_dist = dist;
                    min_centorid = centroid.clone();
                }
            }
            min_centorid.lock().unwrap().point_set.push(fake_point.clone());
            
        });
    }
    thread::sleep(Duration::from_secs(10));
    for (_, centroid) in fake_clusters.lock().unwrap().iter().enumerate(){
        centroid.lock().unwrap().update_centorid();
    }
}

pub fn testing_normal(){
    let num_threads = num_cpus::get();
    let x: WinDistNodePtr = Arc::new(WinDistNode::new(1, [10, 20, 70], 0));
    let y: WinDistCenterPtr = Arc::new(Mutex::new(WinDistCenter::new(x.clone())));
    let z: WinDistNodePtr = Arc::new(WinDistNode::new(2, [20, 30, 50], 0));

    let mut b_y = y.lock().unwrap();
    let x1 = Arc::new(WinDistNode::new(3, [20, 30, 50], 0));
    b_y.point_set.push(x1.clone());
    b_y.point_set.push(Arc::new(WinDistNode::new(4, [10, 40, 50], 0)));
    b_y.point_set.push(Arc::new(WinDistNode::new(5, [30, 50, 20], 0)));
    b_y.update_centorid();
    
    println!("is_diff{:?}", b_y.has_diff());

    b_y.update_centorid();
    println!("is_diff{:?}", b_y.has_diff());

    b_y.clear_pointset();
    /*
    let t1 = thread::spawn( move ||{
        for i in 1..1000{
            y.update_centorid();
        }
    });
    let t2 = thread::spawn( move ||{
        for i in 1..1000{
            y1.update_centorid();
        }
    });

    t1.join().unwrap();
    t2.join().unwrap();
    */
}

pub fn testing_thread_pool(){
    let num_threads = num_cpus::get();
    let mut pool = ThreadPool::new(num_threads);

    for i in 0..num_threads*10 {
        pool.execute(move || {
            println!("Task {} executed in thread {:?}", i, thread::current().id());
            thread::sleep(Duration::from_secs(1)); 
        });
    }
    println!("thread emit done!!!!!!!!!!!");
    pool.shutdown();
    thread::sleep(Duration::from_secs(2)); 
    println!("main thread done!!!");
}

#[derive(Debug)]
struct Mystruct {
    pub a: i32,
}

impl Mystruct{
    pub fn new(input:i32) -> Self {
        Mystruct{
            a: input,
        }
    }
}

pub fn testing_multi_thread(){
    let x = Arc::new(Mystruct::new(1));
    let pool = ThreadPool::new(2);
    let mut y  = Arc::new(Mutex::new(WinDistNode::new(1, [10, 20, 70], 0)));
    //let mut r_y = y.clone();      ------>
    for i in 0..5 {              //    |   放到循环外就不可以了
        let mut r_y = y.clone(); // <---
        pool.execute(move || {
            r_y.lock().unwrap().origin_count += 1;
            println!("{:?}", r_y);
        });
    }
    println!("last---{:?}", y);
    thread::sleep(Duration::from_secs(2)); 
}

pub fn testing_cluster_alg(){
    let mut point_set = get_fake_points().unwrap();
    let mut km = KmeansPP::new(2, point_set);
    println!("kmeans++:{:?}", km.choose_init());
    println!("kmeans++:{:?}", km.choose_init());
    println!("kmeans++:{:?}", km.choose_init());
    println!("len!!!:{:?}", km.cluster_set.lock().unwrap().len());
    km.work();
    println!("len!!!:{:?}", km.cluster_set.lock().unwrap().len());
    for (idx, cluster) in km.cluster_set.lock().unwrap().iter().enumerate(){
        println!("km centroid:{:?}-{:?}", idx, cluster);
    }
    println!("index:::{:?}", km.cluster_set.lock().unwrap().get(0));
    println!("index:::{:?}", km.cluster_set.lock().unwrap().get(1));
    println!("len!!!:{:?}", km.cluster_set.lock().unwrap().len());
}

pub fn testing_cluster() {
    //let hands = get_all_hands();
    println!("begin create points!");
    let points = get_points().unwrap();
    println!("get points done!");
    let mut clusters: Arc<Mutex<Vec<WinDistCenterPtr>>> = 
    Arc::new(Mutex::new(Vec::new()));
    println!("all points:{:?}", points.len());
    let mut km = KmeansPP::new(8, points);
    println!("create KmeansPP done!");
    let mut notDone = true;
    let mut count = 0;
    
    println!("begin init centroid!");
    while notDone==true{
        notDone = km.choose_init().unwrap();
        count += 1;
        //println!("count {:?} -- result:{:?}", count, notDone);
    }
    //println!("{:?}", km.cluster_set);
    
    km.work();
    println!("len!!!:{:?}", km.cluster_set.lock().unwrap().len());
    for (idx, cluster) in km.cluster_set.lock().unwrap().iter().enumerate(){
        println!("km centroid:{:?}-{:?}", idx, cluster.lock().unwrap().point_set.len());
    }
    
}