#!/usr/bin/env node
var express = require('express')
var request = require('request')
var route = express()
var slSystems = require('./slSystemsCrawler')
var Bacon = require('baconjs').Bacon
var _ = require('lodash')
var courts = require('../public/courts')
var webTimmi = require('./webTimmiCrawler')
var browserify = require('browserify-middleware')
var MongoClient = require('mongodb').MongoClient
var mongoUri = process.env.MONGOLAB_URI || process.env.MONGOHQ_URL || 'mongodb://localhost/test';
route.use('/front.min.js', browserify(__dirname + '/../public/front.js'))
route.use(express.static(__dirname + '/../public'))
var cache = {}
var expirationInMin = 120
route.get('/courts', freeCourts)
route.get('/courts2', freeCourts2)
route.get('/locations', locations)

module.exports = route

function freeCourts(req, res) {
    var isoDate = req.query.date
    var currentTimeMinusDelta = new Date().getTime() - 1000 * 60 * expirationInMin
    var cachedValue = cache[isoDate]
    if (cachedValue && cachedValue.timestamp > currentTimeMinusDelta) {
        console.log('fetching from cache for date', isoDate)
        res.send(cachedValue)
    } else {
        console.log('fetching from servers for date', isoDate)

        fetch(isoDate).onValue(function (obj) {
            cache[isoDate] = obj
            res.send(obj)
        })
    }
}

function getFromMongo(isoDate, callback) {
    MongoClient.connect(mongoUri, function (err, db) {
        var collection = db.collection('tennishelsinki')
        var filter = {date: new Date(isoDate)}
        collection.find(filter).toArray(function (err, docs) {
            var transformedDoc = docs.map(function (doc) {
                doc.created = doc._id.getTimestamp && doc._id.getTimestamp().toISOString()
                return doc
            })
            callback(err, transformedDoc)
            db.close()
        })
    })
}

function upsertToMongo(isoDate, obj) {
    MongoClient.connect(mongoUri, function (err, db) {
        var collection = db.collection('tennishelsinki')
        var date = new Date(isoDate)
        collection.updateOne({date: date}, {
            date:       date,
            freeCourts: obj.freeCourts,
            timestamp:  obj.timestamp
        }, {
            upsert: true
        }, function (err, rs) {
            console.log(err, rs && rs.result)
            db.close()
        })
    })
}

function freeCourts2(req, res) {
    var isoDate = req.query.date
    var forceRefresh = req.query.forceRefresh || false
    var currentTimeMinusDelta = new Date().getTime() - 1000 * 60 * expirationInMin
    if (forceRefresh) {
        console.log('fetching from servers for date', isoDate)
        fetch(isoDate).onValue(function (obj) {
            upsertToMongo(isoDate, obj)
            res.send(obj)
        })
    } else {
        getFromMongo(isoDate, function (err, data) {
            if (err) {
                res.status(500).send(err)
            } else if (data.length > 0 && data[0].timestamp > currentTimeMinusDelta) {
                console.log('fetching from db for date', isoDate)
                res.send(data)
            } else {
                console.log('fetching from servers for date', isoDate)
                fetch(isoDate).onValue(function (obj) {
                    upsertToMongo(isoDate, obj)
                    res.send(obj)
                })
            }
        })
    }
}

function fetch(isoDate) {
    return Bacon.combineAsArray([
        slSystems.getMeilahti,
        slSystems.getHerttoniemi,
        slSystems.getKulosaari,
        slSystems.getMerihaka,
        webTimmi.getAll].map(function (fn) { return fn(isoDate) }))
        .map(function (allData) {
            return {
                freeCourts: _.flatten(allData).map(function (reservation) {
                    reservation.isBubble = /kupla/i.test(reservation.field)
                    return reservation
                }),
                timestamp:  new Date().getTime()
            }
        })
}

function locations(req, res) {
    Bacon.combineAsArray(_.map(courts, function (val, key) {
        return getLocation(val.address).map(function (location) {
            return _.extend({title: key}, location, val)
        })
    })).onValue(function (val) { res.send(val) })
}

function getLocation(address) {
    return Bacon.fromNodeCallback(request.get, {
        url: 'http://maps.googleapis.com/maps/api/geocode/json?address=' + address + '&sensor=false'
    }).map('.body').map(JSON.parse).map('.results.0.geometry.location')
}

@@ -622,23 +622,8 @@
 '))%0A
-var cache = %7B%7D%0A
 var 
@@ -681,43 +681,8 @@
 ts)%0A
-route.get('/courts2', freeCourts2)%0A
 rout
@@ -794,32 +794,87 @@
  req.query.date%0A
+    var forceRefresh = req.query.forceRefresh %7C%7C false%0A
     var currentT
@@ -948,214 +948,25 @@
     
-var cachedValue = cache%5BisoDate%5D%0A    if (cachedValue && cachedValue.timestamp %3E currentTimeMinusDelta) %7B%0A        console.log('fetching from cache for date', isoDate)%0A        res.send(cachedValue)%0A    %7D else
+if (forceRefresh)
  %7B%0A 
@@ -1027,17 +1027,16 @@
 soDate)%0A
-%0A
         
@@ -1091,54 +1091,650 @@
     
-cache%5BisoDate%5D = obj%0A            res.send(obj)
+upsertToMongo(isoDate, obj)%0A            res.send(obj)%0A        %7D)%0A    %7D else %7B%0A        getFromMongo(isoDate, function (err, data) %7B%0A            if (err) %7B%0A                res.status(500).send(err)%0A            %7D else if (data.length %3E 0 && data%5B0%5D.timestamp %3E currentTimeMinusDelta) %7B%0A                console.log('fetching from db for date', isoDate)%0A                res.send(data)%0A            %7D else %7B%0A                console.log('fetching from servers for date', isoDate)%0A                fetch(isoDate).onValue(function (obj) %7B%0A                    upsertToMongo(isoDate, obj)%0A                    res.send(obj)%0A                %7D)%0A            %7D
 %0A   
@@ -2798,1022 +2798,8 @@
 %0A%7D%0A%0A
-function freeCourts2(req, res) %7B%0A    var isoDate = req.query.date%0A    var forceRefresh = req.query.forceRefresh %7C%7C false%0A    var currentTimeMinusDelta = new Date().getTime() - 1000 * 60 * expirationInMin%0A    if (forceRefresh) %7B%0A        console.log('fetching from servers for date', isoDate)%0A        fetch(isoDate).onValue(function (obj) %7B%0A            upsertToMongo(isoDate, obj)%0A            res.send(obj)%0A        %7D)%0A    %7D else %7B%0A        getFromMongo(isoDate, function (err, data) %7B%0A            if (err) %7B%0A                res.status(500).send(err)%0A            %7D else if (data.length %3E 0 && data%5B0%5D.timestamp %3E currentTimeMinusDelta) %7B%0A                console.log('fetching from db for date', isoDate)%0A                res.send(data)%0A            %7D else %7B%0A                console.log('fetching from servers for date', isoDate)%0A                fetch(isoDate).onValue(function (obj) %7B%0A                    upsertToMongo(isoDate, obj)%0A                    res.send(obj)%0A                %7D)%0A            %7D%0A        %7D)%0A    %7D%0A%7D%0A%0A
 func

Use mongo for caching