'use strict';

var request = require('request');
var r = require('rethinkdb');
var Promise = require('es6-promise').Promise;
var _ = require('lodash');

var Aggregator = function Aggregator(options) {
    var self = this;

    this.parseJSON = function parseJSON(body) {
        var data;
        try {
            data = JSON.parse(body);
        } catch (e) {
            return Promise.reject(e);
        }
        return Promise.resolve(data);
    };

    this.normalize = function normalize(json) {
        if (json.nodes) {
            json.nodes = json.nodes.map(function (node) {
                node.nodeinfo = node.nodeinfo || {};
                if (_.isArray(node.geo) && node.geo.length === 2) {
                    node.nodeinfo.location = {
                        type: 'Point',
                        coordinates: [node.geo[1], node.geo[0]]
                    };
                    delete node.geo;
                }
                if (node.firmware) {
                    node.nodeinfo.software = node.nodeinfo.software || {};
                    node.nodeinfo.software.firmware = node.firmware;
                    delete node.firmware;
                }
                return node;
            });
        }
        return json;
    };

    this.writeJSON = function (json) {
        var meta = {
            id: json.id,
            meta: json.meta
        };
        return r.db(self.dbConfig.db)
            .table('currentNetwork')
            .insert(meta, { returnChanges: false, conflict: 'replace' })
            .run(self.connection)
            .then(function () {
                return r.db(self.dbConfig.db)
                    .table('nodes')
                    .insert(json.nodes || [], { returnChanges: false, conflict: 'update' })
                    .run(self.connection);
            }).then(function () {
                return r.db(self.dbConfig.db)
                    .table('links')
                    .insert(json.links || [], { returnChanges: false, conflict: 'update' })
                    .run(self.connection);
            });
    };

    this.finish = function finish(res) {
        if (self.connection && self.connection.open) {
            self.connection.close();
        }
        return res;
    };

    _.merge(this, options);

    this.aggregate = function aggregate(backend, dbConfig) {
        self.dbConfig = dbConfig || self.dbConfig;
        return r.connect(dbConfig).then(function (c) {
            self.connection = c;
            return Promise.all(backend.endpoints.map(function (id) {
                return self.fetchData(backend.base + '/' + id)
                    .then(self.parseJSON)
                    .then(function addMetaDataData(json) {
                        json.id = backend.base + '/' + id;
                        if (!json.timestamp) {
                            json.timestamp = new Date().toISOString();
                        }
                        return json;
                    })
                    .then(self.normalize)
                    .then(self.writeJSON);
            }));
        }).then(self.finish);
    };
};

var api = {};

api.remote = new Aggregator({
    fetchData: function (path) {
        return new Promise(function (resolve, reject) {
            request(path, function (err, res, body) {
                if (err) {
                    reject(err);
                } else {
                    resolve(body);
                }
            });
        });
    }
});

api.local = new Aggregator({
    fetchData: function (path) {
        var fs = require('fs');

        return new Promise(function (resolve, reject) {
            fs.readFile(path, function (err, content) {
                if (err) {
                    reject(err);
                } else {
                    resolve(content);
                }
            });
        });
    }
});

module.exports = {
    for: function (type) {
        return api[type];
    }
};

@@ -1218,32 +1218,1265 @@
   %7D);%0A        %7D%0A
+        if (json.links) %7B%0A            json.links = json.links.map(function (link) %7B%0A                if (!link.type) %7B%0A                    link.type = 'node';%0A                %7D%0A                if (json.nodes &&%0A                    json.nodes%5Blink.target%5D &&%0A                    json.nodes%5Blink.target%5D.nodeinfo.location &&%0A                    json.nodes%5Blink.target%5D.nodeinfo.location.type === 'Point' &&%0A                    json.nodes%5Blink.source%5D &&%0A                    json.nodes%5Blink.source%5D.nodeinfo.location &&%0A                    json.nodes%5Blink.source%5D.nodeinfo.location.type === 'Point')%0A                %7B%0A                    var geo = %7B%0A                        type: 'LineString',%0A                        coordinates: %5B%0A                            json.nodes%5Blink.source%5D.nodeinfo.location.coordinates,%0A                            json.nodes%5Blink.target%5D.nodeinfo.location.coordinates%0A                        %5D%0A                    %7D;%0A                    link.geometry = geo;%0A                %7D%0A%0A                link.target = json.nodes && json.nodes%5Blink.target%5D.id %7C%7C link.target;%0A                link.source = json.nodes && json.nodes%5Blink.source%5D.id %7C%7C link.source;%0A%0A                return link;%0A            %7D);%0A        %7D%0A
         return j

add information for links