var fs = require('fs');
var express = require('express');
var bitcore = require('bitcore');
var Address = bitcore.Address;
var util = bitcore.util;
var Script = bitcore.Script;
var P2P = require('bitcore-p2p');
var Pool = P2P.Pool;
var Messages = P2P.Messages;
var http = require('http');
var socket = require('socket.io');
var Networks = bitcore.Networks;
var Peer = P2P.Peer;
var startTime = new Date();
var pool;

exports.BitflowServer = function(config) {

  // defaults
  
  if ( config['host'] == undefined )
    config['host'] = 'http://127.0.0.1';
  if ( config['port'] == undefined )
    config['port'] = '80';
  if ( config['debug'] == undefined )
    config['debug'] = false;
  if ( config['network'] == undefined ) 
    config['network'] = 'livenet';
  if ( config['max_peers'] == undefined ) 
    config['max_peers'] = 6;
  

  // init variables
  var site_url,
  known_tx_hashes = {},
  known_tx_hashes_max_length = 5000,
  known_tx_hashes_length = 0,
  tx_dates = [],
  network = null,
  web = null,
  app = null,
  io = null,
  peermanager = null,
  server = null,
  websockets = [];
  
  if ( config['port'].toString() != '80' ) {
    site_url = config['host']+':'+config['port'];
  } else {
    site_url = config['host'];
  }
  
  // define functions
  
  var handle_socket_connection = function(websocket) {
    websockets.push( websocket );
    websocket.on('end', function () {
      var i = websockets.indexOf(socket)
      websockets.splice(i, 1)
    });
  }
  
  var calculate_tx_rates = function(){
    var l = tx_dates.length;
    var second_ago = new Date() - 1000; // one second
    var minute_ago = new Date() - 1000 * 60; // one minute
    var hour_ago = new Date() - 1000 * 60 * 60; // one hour
    var tx_rate_per_second = 0;
    var tx_rate_per_minute = 0;
    var tx_rate_per_hour = 0;
    for (var i=0; i<l;i++){
      if ( tx_dates[i] > second_ago ) {
        tx_rate_per_second++;
      }
      if ( tx_dates[i] > minute_ago ) {
        tx_rate_per_minute++;
      }
      if ( tx_dates[i] > hour_ago ) {
        tx_rate_per_hour++;
      } 
      if ( tx_dates[i] < hour_ago ){
        // remove the date
        tx_dates.splice(i, 1);
      }
    }
    return [tx_rate_per_second, tx_rate_per_minute, tx_rate_per_hour];
  }
  
  var handle_tx = function(peer, message) {
    
    var tx = message.transaction;
    
    var outputs = [];
    
    for (var i=0; i < tx.outputs.length; i++ ) {
      
      var script = tx.outputs[i].script;
      var satoshis = tx.outputs[i].satoshis;
      var address = 'unknown';
      
      if (script.isPublicKeyHashOut() || script.isScriptHashOut()) {
        address = script.toAddress(Networks.defaultNetwork);
      }
      
      outputs.push( { address : address.toString(), value : satoshis / 100000000} );
    }

    var hash = tx.hash;

    if ( known_tx_hashes[hash] == undefined ) {
      
      // do not use too much memory
      if ( known_tx_hashes_length >= known_tx_hashes_max_length ) {
        known_tx_hashes = {};
        known_tx_hashes_length = 0;
      } 
      
      known_tx_hashes[hash] = true;
      known_tx_hashes_length++;
      
      tx_dates.push(new Date());
      
      var tx_rates = calculate_tx_rates();
      
      //broadcast transaction
      for ( var i = 0; i < websockets.length; i++ ) {
        websockets[i].emit('tx', { 
          hash: hash, 
          outputs: outputs, 
          rates: tx_rates, 
          uptime: new Date() - startTime,
          peers: pool.numberConnected(),
          peersKnown: pool._addrs.length
        });
      }
    }
  }
  
  var handle_inv = function(peer, message) {
    for ( var i = 0; i < websockets.length; i++ ) {
    	websockets[i].emit('inv', { message: message });
    }
    var peerMessage = new Messages.GetData(message.inventory);
    peer.sendMessage(peerMessage);
  }
  
  // initialize
  
  web = express();
  web.set('views', __dirname + '/bitflowui');
  web.set('view engine', 'ejs');
  web.get('/', function(req, res, next){
    res.render('index.ejs', { site_url: site_url }, function(err, html){
      res.send(html);
    });
  });
  web.use('/static', express.static(__dirname + '/bitflowui'));
  app = http.createServer(web);
  io = socket.listen(app, {log: config['debug']} );
  app.listen( config['port'] );
  
  if ( config['network'] == 'livenet' ) {
    network = Networks.livenet;
  } else if ( config['network'] == 'testnet' ) {
    network = Networks.testnet;
  }

  io.sockets.on('connection', handle_socket_connection );

  pool = new Pool(network);
  pool.on('peerinv', handle_inv);
  pool.on('peertx', handle_tx);
  pool.connect();

}
