var ua = require("resip_ua");
var logger = require("logger");
var async = require("async");
var zmq = require("zmq");
var system = require("system");
var assert = require("assert");

logger.init(
  "subscribe.log",
  logger.DEBUG,
  "%h-%M-%S.%i: %t", // format
  true, // compress
  3 //purge after 3 days
);
logger.setLevel(logger.DEBUG);
ua.setLogLevel(ua.Log_Debug);

var profiles = new Object();
var accounts = new Object();
accounts.did_9292732360 = { aor : "TTB2360@as.pressone.net", did : "9292732360", auth_user : "TTB2360", auth_pass : "86UwakP743PB", auth_realm : "as.pressone.net" };
accounts.did_9292732361 = { aor : "TTB2361@as.pressone.net", did : "9292732361", auth_user : "TTB2361", auth_pass : "155681" , auth_realm : "as.pressone.net" };
accounts.did_9292732362 = { aor : "TTB2362@as.pressone.net", did : "9292732362", auth_user : "TTB2362", auth_pass : "123456" , auth_realm : "as.pressone.net" };
accounts.did_9292732363 = { aor : "TTB2363@as.pressone.net", did : "9292732363", auth_user : "TTB2363", auth_pass : "123456" , auth_realm : "as.pressone.net" };

profiles.TTB2360 = new ua.UserProfile();
profiles.TTB2361 = new ua.UserProfile();
profiles.TTB2362 = new ua.UserProfile();
profiles.TTB2363 = new ua.UserProfile();

var init_profile = function(profile, account)
{
  profile.account = account;
  profile.setDefaultFrom("sip:" + account.aor);
  profile.setDigestCredential(account.aor, account.auth_user, account.auth_pass);
} 

init_profile(profiles.TTB2360, accounts.did_9292732360);
init_profile(profiles.TTB2361, accounts.did_9292732361);
init_profile(profiles.TTB2362, accounts.did_9292732362);
init_profile(profiles.TTB2363, accounts.did_9292732363);

var get_account_by_aor = function (aor)
{
  for (var item in accounts) {
    if (typeof accounts[item] === "object" && ("aor" in accounts[item]) && accounts[item].aor == aor) {
      return accounts[item];
    }
  }
  return undefined;
}

var get_profile_by_aor = function (aor)
{
  for (var item in profiles) {
    if (typeof profiles[item] === "object" && ("account" in profiles[item]) && profiles[item].account.aor == aor) {
      return profiles[item];
    }
  }
  return undefined;
}

var sipStack = new ua.SipStack();
var dum = new ua.DialogUsageManager(sipStack);
var mwi = new ua.ClientSubscriptionHandler();
var dialog = new ua.ClientSubscriptionHandler();

var profile = new ua.MasterProfile();
profile.addSupportedMethod(ua.NOTIFY);
profile.validateAcceptEnabled(false);
profile.validateContentEnabled(false);
profile.setUserAgent("oss_core test subscriber");

dum.setMasterProfile(profile);
dum.addClientSubscriptionHandler("message-summary", mwi);
dum.addClientSubscriptionHandler("dialog", dialog);
dum.overrideContact("52.191.239.84", 45062);

sipStack.addTransport(ua.UDP, 45062);
sipStack.addTransport(ua.TCP, 45062);


var pub_mwi_port = 9062;
var pub_mwi_ip = system.NET_IPV4;
var pub_mwi_url = "tcp://" + pub_mwi_ip + ":" + pub_mwi_port;
var pub_mwi = new zmq.ZMQSocket(zmq.PUB);
if (!pub_mwi.bind(pub_mwi_url)) {
    logger.log_error("Unable to bind PUB endpoint via " + pub_mwi_url);
    system.exit(-1);
} else {
    logger.log_info("PUB endpoint started receiving messages via " + pub_mwi_url);
}

var pub_dialog_port = 9063;
var pub_dialog_ip = system.NET_IPV4; 
var pub_dialog_url = "tcp://" + pub_dialog_ip + ":" + pub_dialog_port;
var pub_dialog = new zmq.ZMQSocket(zmq.PUB);
if (!pub_dialog.bind(pub_dialog_url)) {
    logger.log_error("Unable to bind PUB endpoint via " + pub_dialog_url);
    system.exit(-1);
} else {
    logger.log_info("PUB endpoint started receiving messages via " + pub_dialog_url);
}

mwi.onUpdatePending(function(event){
    pub_mwi.publish(JSON.stringify(event));
    logger.log_info("mwi::onUpdatePending-->" + JSON.stringify(event));
});

mwi.onUpdateActive(function(event){
    pub_mwi.publish(JSON.stringify(event));
    logger.log_info("mwi::onUpdateActive-->" + JSON.stringify(event));
});

mwi.onNewSubscription(function(event){
    logger.log_info("mwi::onNewSubscription-->" + JSON.stringify(event));
});

mwi.onNotifyNotReceived(function(event){
    logger.log_info("mwi::onNotifyNotReceived-->" + JSON.stringify(event));
});

mwi.onTerminated(function(event){
    logger.log_info("mwi::onTerminated-->" + JSON.stringify(event));
    async.setTimeout(send_subscribe, 5000, [event.key, "message-summary"]);
});

dialog.onUpdatePending(function(event){
    pub_dialog.publish(JSON.stringify(event));
    logger.log_info("dialog::onUpdatePending-->" + JSON.stringify(event));
});

dialog.onUpdateActive(function(event){
    pub_dialog.publish(JSON.stringify(event));
    logger.log_info("dialog::onUpdateActive-->" + JSON.stringify(event));
});

dialog.onNewSubscription(function(event){
    logger.log_info("dialog::onNewSubscription-->" + JSON.stringify(event));
});

dialog.onNotifyNotReceived(function(event){
    logger.log_info("dialog::onNotifyNotReceived-->" + JSON.stringify(event));
});

dialog.onTerminated(function(event){
    logger.log_info("dialog::onTerminated-->" + JSON.stringify(event));
    async.setTimeout(send_subscribe, 5000, [event.key, "dialog"]);
});

sipStack.run();
dum.run();

var send_subscribe = function (aor, event)
{
    var uri = "sip:" + aor;
    var profile = get_profile_by_aor(aor);
    dum.sendClientSubscription(profile, uri, event, 3600, 3580);
}

send_subscribe("TTB2360@as.pressone.net", "dialog");
send_subscribe("TTB2360@as.pressone.net", "message-summary");

send_subscribe("TTB2361@as.pressone.net", "dialog");
send_subscribe("TTB2361@as.pressone.net", "message-summary");

send_subscribe("TTB2362@as.pressone.net", "dialog");
send_subscribe("TTB2362@as.pressone.net", "message-summary");

send_subscribe("TTB2363@as.pressone.net", "dialog");
send_subscribe("TTB2363@as.pressone.net", "message-summary");


///////////////////////////////////////// CALL CONTROL /////////////////////////////////////////////////////

var uuid_map = Array(0);
var map_uuid = function (call_id, uuid) 
{
  var obj = { call_id: call_id, uuid : uuid };
  uuid_map.push(obj);
}

var del_uuid = function (uuid) 
{
  var items = uuid_map.length;
  for (var i = 0; i < items; i++) {
    var obj = uuid_map[i];
    if (obj.uuid == uuid) {
      uuid_map.splice(i, 1);
      break;
    }
  }
}

var get_uuid = function(call_id)
{
  var items = uuid_map.length;
  for (var i = 0; i < items; i++) {
    var obj = uuid_map[i];
    if (obj.call_id == call_id) {
      return obj.uuid;
    }
  }
  return undefined;
}



var pub_url = "tcp://switch.ossapp.com:9068";
var responder_url = "tcp://switch.ossapp.com:9069";


var sub = new zmq.ZMQSocket(zmq.SUB);
assert(sub.connect(pub_url));
sub.subscribe("");

var req = new zmq.ZMQSocket(zmq.PUSH);
assert(req.connect(responder_url));

logger.log_info("connected to " + pub_url);


var set_credentials = function(uuid, account)
{
  var cmd = new Object();
  cmd.method = "switch_uuid_set_credential";
  cmd.args = { uuid : uuid, account : account };
  var request = new Buffer(JSON.stringify(cmd));
  req.send(request);
}

sub.start(function() {
  try {
	  var msg = new Buffer(8092);
	  sub.receive(msg);
	  var event = JSON.parse(msg.toString());
 
	  if (event.hasOwnProperty("Event-Name") && event["Event-Name"] === "CHANNEL_CALLSTATE") {
		if (event.hasOwnProperty("Channel-Call-State") && (event["Channel-Call-State"] === "ACTIVE" || event["Channel-Call-State"] === "HANGUP") ) {
                        if (event["Call-Direction"] === "inbound") {
		  		logger.log_info(JSON.stringify(event, undefined, 2));
                                var destination = event["Caller-Destination-Number"];
                                var caller = event["Caller-Username"];
				var uuid = event["Unique-ID"];
                                
                                if (event["Channel-Call-State"] === "ACTIVE") {
	                          var call_id = event["sip_call_id"];
	                          if (typeof call_id === "string") {
				    map_uuid(call_id, uuid);
	                          }
                                  var account_id = "did_" + destination;
				  if (accounts.hasOwnProperty(account_id)) {
				    var account = accounts[account_id];
				    set_credentials(uuid, account);
				  }
                                } else if (event["Channel-Call-State"] === "HANGUP") {
                                  del_uuid(uuid);
                                }				
                        }
		}
	  }

  } catch(err) {
     logger.log_info(err);
  }
});

/////////////////////////////////////////////////////////  JSON-RPC //////////////////////////////////////////////////////////////

var rpc_port = 9064;
var rpc_ip = system.NET_IPV4; 
var rpc_url = "tcp://" + rpc_ip + ":" + rpc_port;
var rpc = new zmq.ZMQSocket(zmq.REP);
if (!rpc.bind(rpc_url)) {
    logger.log_error("Unable to bind JSON-RPC " + rpc_url);
    system.exit(-1);
} else {
    logger.log_info("JSON-RPC endpoint started receiving messages via " + rpc_url);
}

rpc.start(function() {
    var msg = new Buffer(2048);
    rpc.receive(msg);
    logger.log_info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Receive JSON-RPC <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n" + msg.toString());
    var rpc_request = JSON.parse(msg.toString());
    if (rpc_request.hasOwnProperty("method") && rpc_request.hasOwnProperty("params")) {
      var cmd = new Object();
      cmd.method = rpc_request.method;
      cmd.args = rpc_request.params;
      
      if (rpc_request.method === "uuid_deflect") {
        cmd.args.uuid = get_uuid(rpc_request.params.call_id);
        if (!cmd.args.uuid) {
          var rpc_result = new Object();
          rpc_result.jsonrpc = "2.0";
          rpc_result.result = false;
          rpc_result.error = "UUID not present";
          rpc_result.id = rpc_request.id;
          var rpc_response = new Buffer(JSON.stringify(rpc_result));
          rpc.send(rpc_response);
          return;
        }
      }

      var request = new Buffer(JSON.stringify(cmd));
      req.send(request);
    }
    var rpc_result = new Object();
    rpc_result.jsonrpc = "2.0";
    rpc_result.result = true;
    rpc_result.id = rpc_request.id;
    var rpc_response = new Buffer(JSON.stringify(rpc_result));
    rpc.send(rpc_response);
});













