extern crate uuid;
extern crate indradb;
extern crate common;
extern crate serde_json;


use serde_json::de::from_str;
use uuid::Uuid;

use common::{datastore};
use indradb::{EdgeKey, VertexQuery, Type};

// Traits!
use indradb::{Datastore, Transaction};


fn create_vertex<T: Transaction>(trans: &T, node_type: &Type, name: &str) -> indradb::Result<Uuid> {
    let uuid = trans.create_vertex(node_type)?;
    trans.set_vertex_metadata(
        &VertexQuery::Vertices { ids: vec![uuid] },
        "name",
        &from_str(&format!(r#""{}""#, name)).unwrap(),
    )?;
    Ok(uuid)
}


fn main() {
    let station = Type::new("station".to_owned()).unwrap();
    let watcher = Type::new("watcher".to_owned()).unwrap();
    let feeds = Type::new("feeds".to_owned()).unwrap();
    let observes = Type::new("observes".to_owned()).unwrap();
    let indra = datastore();
    let (vertices, _edges) = {
        let trans = indra.transaction().expect("txn");

        let v1 = create_vertex(&trans, &station, "Intake station").expect("v1");
        let v2 = create_vertex(&trans, &station, "Processing station").expect("v2");
        let v3 = create_vertex(&trans, &station, "Output station").expect("v3");
        let w1 = create_vertex(&trans, &watcher, "Watcher").expect("w1"); 
        let e1 = trans.create_edge(&EdgeKey::new(v1, feeds.clone(), v2));
        let e2 = trans.create_edge(&EdgeKey::new(v2, feeds.clone(), v3));
        let e3 = trans.create_edge(&EdgeKey::new(w1, feeds.clone(), v2));
        let e4 = trans.create_edge(&EdgeKey::new(w1, observes.clone(), v1));
        let e5 = trans.create_edge(&EdgeKey::new(w1, observes.clone(), v3));
        let e6 = trans.create_edge(&EdgeKey::new(w1, observes.clone(), v1));
        (vec![v1, v2, v3, w1], vec![e1, e2, e3, e4, e5, e6])
    };

    {
        let trans = indra.transaction().expect("txn");

        let watched_stations = VertexQuery::Vertices { ids: vec![vertices[3]] }
            .outbound_edges(Some(observes.clone()), None, None, 64)
            .inbound_vertices(64);
        println!("Watched stations:");

        let names = trans.get_vertex_metadata(&watched_stations, "name").expect("get names");
        for metadata in names {
            println!("  {}", metadata.value.as_str().expect("json string"));
        }
    }
}