var config = require('./config.json');

var pathPhotos = config.pathPhotos;
var previewWidth = config.previewWidth;
var previewHeight = config.previewHeight;
var cardAddr = config.broadcastAddr;
var cardPath = null;
var pathPreviews = './public/previews';

var itvPing = null;
var cardFound = false;
var alreadySearching = false;
var alreadyDownloading = false;
var downloadPrevious = true;
var downloadList = new Array();

var os = require('os');
var http = require('http');
var path = require('path');
var net = require('net');
var dgram = require('dgram');
var fs = require('fs');
var gm = require('gm');

/* Express */

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var latestPhoto = require('./routes/latest');
var allPhotos = require('./routes/all');

var app = express();

process.title = 'WiPho';
var gracefulShutdown = function() {
  console.log("Shutting down...");
  process.exit();
}

process.on ('SIGTERM', gracefulShutdown);
process.on ('SIGINT', gracefulShutdown);   

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
//app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/latest', latestPhoto);
app.use('/all', allPhotos);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

module.exports = app;

/* WiPho */

photos = new Array();
photoIndex = 0;

console.log("#########################################");
console.log("# Make sure you shoot JPEG or RAW+JPEG! #");
console.log("#########################################");

findCard();

function downloadPhotos() {

	if(alreadyDownloading == true || downloadList.length < 1)
		return true;
		
	alreadyDownloading = true;
	var photo = downloadList.pop();
	var localFile = pathPhotos+'/'+photo;
	var localPreview = pathPreviews+'/'+photo;
	console.log('['+photo+'] Downloading from http://'+cardAddr+cardPath+'/'+photo);
	
	var file = fs.createWriteStream(localFile);
		
	file.on('error', function(err) {
		console.log("FS: "+err);
	});
	
	file.on('finish', function() {
		file.close();
		alreadyDownloading = false;
		console.log('['+photo+'] Saved as '+localFile);
		
		gm(localFile).autoOrient().resize(previewWidth, previewHeight).write(localPreview, function (err) {
			if (!err) {
				console.log('['+photo+'] Resized to '+previewWidth+'x'+previewHeight);						
				if(photos.length == 0 || photo != photos[photos.length-1].name) {
					photos.push({id: photoIndex, name: photo});
					photoIndex++;
				}
			
			}else{
				console.log('Photo resize error: '+err);
			}
			
		});

		if(downloadPrevious == true) {
			getPhotoList();
		}
		
		if(downloadList.length > 0) {
			downloadPhotos();
		}else{
			console.log("All photos downloaded, waiting for new ones...");
		}
		
	});
	
	var options = {
		hostname: cardAddr,
		port: 80,
		path: cardPath+'/'+photo,
		method: 'GET'
	};
	
	var request = http.get(options, function(response) {
	  response.pipe(file);
	});
	
	request.on('error', function(e) {
		console.log("HTTP Error: " + e.message);
	});

}

function getPhotoList() {

	downloadPrevious = false;

	var options = {
		host: cardAddr,
		port: 80,
		path: '/cgi-bin/tslist?PATH=/www'+cardPath+'&keepfresh='+Date.now().toString()
	};

	http.get(options, function(resp){
		console.log("Getting list of photos on card...");
		resp.on('data', function(data){
			var strFiles = data.toString().split(os.EOL)[2];
			var regex = /FileName\d+=([a-zA-Z0-9_\.]+)&FileType\d+=File&/g;
			var arrPhotos = new Array();
			while (match = regex.exec(strFiles)) {
				arrPhotos.push(match[1]);
			}
			var i = 0;
			arrPhotos.forEach(function(photo) {
				fs.exists(pathPhotos+'/'+photo, function(exists) {
					if (exists) {
						//console.log('['+photo+'] Photo '+photo+' already downloaded!');
					}else{
						console.log('['+photo+'] Photo '+photo+' not downloaded yet, adding to download list!');
						downloadList.push(photo);
					}
					i++;
					if(i == arrPhotos.length-1) {
						if(downloadList.length > 0) {
							downloadPhotos();
						}else{
							console.log("All photos already downloaded!");
						}
					}
				});
			});
		});
	}).on("error", function(e){
		console.log("Error getting photo list: " + e.message);
		getPhotoList();
	});

}


function enableShootAndView(ip) {

	var client = net.connect({port: 5566, host: ip}, function() {
		console.log('Enabling Shoot & View...');
	});
	
	client.on('connect', function() {
		console.log('Shoot & View enabled, waiting for photos...');
		if(cardPath != null) {
			getPhotoList();
		}
	});
	
	client.on('error', function(err) {
		console.log('Shoot & View error: '+err);
		findCard();
	});
	
	client.on('data', function(data) {
		var path = data.toString().substr(5).replace(/\0/g, '');
		var photo = path.split('/').pop();
		cardPath = path.substring(0, path.lastIndexOf('/'));
		downloadList.push(photo);
		downloadPhotos();
	});

	client.on('end', function() {
		console.log('Shoot & View stopped!');
	});

}


function pingCard(ip) {

	req = http.get('http://'+ip+'/', function(res) {
		//console.log('Card is alive!');
		req.destroy();
	});
	
	req.on('error', function(err) {
		cardFound = false;
		console.log('ERROR: ' + err);
		req.destroy();
		clearInterval(itvPing);
		findCard();
	});
	
	req.setTimeout(5000, function() {
		cardFound = false;
		downloadPrevious = true;
		console.log('Card has disappeared!');
		req.destroy();
		clearInterval(itvPing);
		findCard();
	});
	
}


function findCard() {

	if(alreadySearching == true)
		return;
	else
		alreadySearching = true;
		
	console.log("Searching for card...");

	var socket = dgram.createSocket('udp4');
	var message = new Buffer('dummy');
	var itvSearch;
	
	socket.bind(58255, function() {
		socket.setBroadcast(true);
	});
	
	socket.on('error', function (err) {
		console.log("socket error:\n" + err.stack);
		socket.close();
		findCard();
	});

	socket.on('message', function (msg, rinfo) {
		clearInterval(itvSearch);
		socket.close();
		msg = msg.toString();
		cardAddr = msg.match(/ip=(.*)/)[1];
		cardFound = true;
		console.log("Found card on "+cardAddr);
		enableShootAndView(cardAddr);
		itvPing = setInterval(function() {
			pingCard(cardAddr);
		}, 5000);
		alreadySearching = false;
	});

	socket.on('listening', function () {
		var address = socket.address();
		sendSearch();
		itvSearch = setInterval(function() {
			sendSearch();
		}, 2000);
		
		function sendSearch() {
			socket.send(message, 0, message.length, 55777, cardAddr, function(err, bytes) {
				if(err != null)
					console.log("socket error:\n" + err.stack);
			});
		}
		
	});
	
}