var express = require("express");
var fs = require("fs");
var net = require("net");


var app = express();

// home page
var search_html = fs.readFileSync("public/index.html").toString();

// connections with computing nodes
var computing_node_count = 0;
var computing_hosts = [ ];
var computing_hosts_hash = { };


// connections with storage nodes
var storage_node_count = 0;
var storage_hosts = [];
var storage_hosts_hash = { };


// root redirect to index.html
app.get("/", function(req, res) {
    console.log("get /");
    res.redirect("/index.html");
});

// index.html 
app.get("/index.html", function(req, res) {
    console.log("get /index.html");
    var rand1 = Math.floor(Math.random() * computing_node_count);
    var rand2 = Math.floor(Math.random() * storage_node_count);
    var content = 
        search_html.replace("COMPUTING_NODE_HOST", computing_hosts[rand1])
                   .replace("STORAGE_NODE_HOST", storage_hosts[rand2]);         
    
    res.send(content);
});

// accept new computing node
app.get("/new_computing_node", function(req, res) {
    function create_connection(addr, port) {
        var host = addr + ":" + port;
        var sock = new net.Socket();

        sock.connect(port, addr, function() {
            computing_hosts[computing_node_count] = host;
            computing_hosts_hash[host] = computing_node_count;
            ++computing_node_count;

            console.log(computing_node_count); console.log(computing_hosts); console.log(computing_hosts_hash);
        });
        
        sock.on("close", function() {
            index = computing_hosts_hash[host];

            if (!(index >= 0)) 
                return;

            delete computing_hosts[index];
            delete computing_hosts_hash[host];
            --computing_node_count;

            if (index != computing_node_count) {
                computing_hosts[index] = computing_hosts[computing_node_count];
                computing_hosts_hash[computing_hosts[computing_node_count]] = index;
                delete computing_hosts[computing_node_count];
                delete computing_hosts_hash[host];
            }

            console.log(computing_node_count); console.log(computing_hosts); console.log(computing_hosts_hash);
        });

        sock.on("error", function(error) { console.log(error); });
        // TODO timeout callback arguments?
        sock.on("timeout", function(timeout) { console.log(timeout); });
        sock.on("data", function(data) { console.log(data); });
    }


    if ("addr" in req.query && "port" in req.query) {
        var host = req.query.addr + ":" + req.query.port;
        if (!(host in computing_hosts_hash)) {
            create_connection(req.query.addr, req.query.port);
            res.send("Try to connect to " + host + ". ");
        } else {
            res.send(host + " already in computing hosts list. ");
        }
    } else {
        res.send("Address or port of computing node isn't provided. ");
    } 
});

// accept new storage node
app.get("/new_storage_node", function(req, res) {
    function create_connection(addr, port) {
        var host = addr + ":" + port;
        var sock = new net.Socket();

        sock.connect(port, addr, function() {
            storage_hosts[storage_node_count] = host;
            storage_hosts_hash[host] = storage_node_count;
            ++storage_node_count;

            console.log(storage_node_count); console.log(storage_hosts); console.log(storage_hosts_hash);
        });
        
        sock.on("close", function() {
            index = storage_hosts_hash[host];

            if (!(index >= 0)) 
                return;

            delete storage_hosts[index];
            delete storage_hosts_hash[host];
            --storage_node_count;

            if (index != storage_node_count) {
                storage_hosts[index] = storage_hosts[storage_node_count];
                storage_hosts_hash[storage_hosts[storage_node_count]] = index;
                delete storage_hosts[storage_node_count];
                delete storage_hosts_hash[host];
            }

            console.log(storage_node_count); console.log(storage_hosts); console.log(storage_hosts_hash);
        });

        sock.on("error", function(error) { console.log(error); });
        // TODO timeout callback arguments?
        sock.on("timeout", function(timeout) { console.log(timeout); });
        sock.on("data", function(data) { console.log(data); });
    }


    if ("addr" in req.query && "port" in req.query) {
        var host = req.query.addr + ":" + req.query.port;
        if (!(host in storage_hosts_hash)) {
            create_connection(req.query.addr, req.query.port);
            res.send("Try to connect to " + host + ". ");
        } else {
            res.send(host + " already in storage hosts list. ");
        }
    } else {
        res.send("Address or port of computing node isn't provided. ");
    } 
});

// overview
app.get("/overview", function(req, res) {
    var content = "Computing nodes: \n";
    for (var key in computing_hosts_hash)
        content += computing_hosts[computing_hosts_hash[key]] + "\n";
    content += "\n";

    content += "Storage nodes: \n";
    for (var key in storage_hosts_hash)
        content += storage_hosts[storage_hosts_hash[key]] + "\n";
    content += "\n";

    res.set('Content-Type', 'text/plain');
    res.send(content);
});


// search at public dir
app.use(express.static("public"));

// 404
app.use(function(req, res, next) {
    res.status(404).send('<h1>404 Not Found</h1>');
});

var server = app.listen(3000, function () {
    var host = server.address().address;
    var port = server.address().port;

    console.log('DISE web server listening at http://%s:%s', host, port);
});

@@ -1,12 +1,33 @@
+#!/usr/bin/env node%0A%0A
 var express 
@@ -1120,32 +1120,47 @@
 onnection(addr, 
+http_port, tcp_
 port) %7B%0A        
@@ -1175,32 +1175,37 @@
  = addr + %22:%22 + 
+http_
 port;%0A        va
@@ -1245,32 +1245,36 @@
    sock.connect(
+tcp_
 port, addr, func
@@ -2591,32 +2591,64 @@
 n req.query && %22
+http_port%22 in req.query && %22tcp_
 port%22 in req.que
@@ -2697,32 +2697,37 @@
 %22:%22 + req.query.
+http_
 port;%0A        if
@@ -2811,32 +2811,57 @@
 addr, req.query.
+http_port, req.query.tcp_
 port);%0A         

update web server