use std::io::{self, Result, ErrorKind};
use std::collections::HashMap;
use std::error::Error;
use request;
use rustc_serialize::json;

pub struct Cosmos {
    host: String,
    planet: String
}

#[derive(RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Container {
    pub Container: String,
    pub Cpu: f32,
    pub Memory: u64,
}

#[derive(RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
struct Metrics {
    Planet: String,
    Containers: Vec<Container>,
}

pub struct Response {
    pub http_version: String,
    pub status_code: u16,
    pub status_message: String,
    pub headers: HashMap<String, String>,
    pub body: String
}

impl Cosmos {
    pub fn new(host: &str, planet: &str) -> Cosmos {
        let cosmos = Cosmos {
            host: host.to_string(),
            planet: planet.to_string()
        };
        return cosmos;
    }

    pub fn post_metrics(&self, containers: &Vec<Container>) -> Result<Response> {
        let metrics = Metrics {
            Planet: self.planet.clone(),
            Containers: containers.clone(),
        };
        
        let body = match json::encode(&metrics) {
            Ok(body) => body,
            Err(e) => {
                let err = io::Error::new(ErrorKind::InvalidInput,
                                         e.description());
                return Err(err);
            }
        };
        
        let url = format!("http://{}/metrics", self.host);
        let response = try!(self.post(&url, &body));
        return Ok(response);
    }

    fn post(&self, url: &str, body: &str) -> Result<Response> {
        let mut headers: HashMap<String, String> = HashMap::new();
        headers.insert("Accept".to_string(), "application/json".to_string());
        headers.insert("Content-Type".to_string(), "application/json".to_string());
        headers.insert("Connection".to_string(), "close".to_string());

        let response = match request::post(url, &mut headers, body.as_bytes()) {
            Ok(response) => response,
            Err(e) => { return Err(e); }
        };

        let cosmos_res = Response {
            http_version: response.http_version.clone(),
            status_code: response.status_code,
            status_message: response.status_message.clone(),
            headers: response.headers.clone(),
            body: response.body.clone()
        };

        return Ok(cosmos_res);
    }
}

impl Clone for Container {
    fn clone(&self) -> Self {
        let container = Container {
            Container: self.Container.clone(),
            Cpu: self.Cpu,
            Memory: self.Memory,
        };
        return container;
    }
}

#[test]
fn it_works() {
    
}