
function newickParser(dataset, callback){

	var newickParser = require('newick_parser');

	if (Object.keys(dataset).length == 0) {
		callback({error: 'Dataset does not exists.'});
		return false;
	}

	try{
		JSONnewick = newickParser.parser.parse(dataset.newick);
	}
	catch(err){
		var graph ={};
		graph.error = 'Newick parser error: ' + err.message;
		callback(graph);
		return false;
	}

	countTransitionNodes = 0;

	var nodes = {};
	var links = [];
	var graph = {};
	var sameProfileHas = {};
	var maxLinkValue = -1;
	var objectofnodes = {};
	var arrayofnodes = [];
	var newickRoot = "";


	checkChildren(JSONnewick, function(){

		//createDistanceMatrix(JSONnewick, function(distanceMatrix){
 
			checkIsolates(dataset, function(){

				console.log(Object.keys(nodes));

				graph.nodes = Object.keys(nodes).map(function(k) { return nodes[k] }); // nodeObject to array
				graph.links = links;
				graph.schemeGenes = dataset.schemegenes;
				graph.metadata = dataset.metadata;
				graph.key = dataset.key;
				graph.data_type = dataset.data_type;
				graph.dataset_name = dataset.name;
				graph.JSONnewick = dataset.newick;
				//graph.distanceMatrix = distanceMatrix;

				//if(Object.keys(dataset.distanceMatrix).length == 0) graph.distanceMatrix = {}; //graph.positions = JSON.parse(dataset.positions);
				//else graph.distanceMatrix = dataset.distanceMatrix;

				if(Object.keys(dataset.positions).length == 0) graph.positions = {}; //graph.positions = JSON.parse(dataset.positions);
				else graph.positions = dataset.positions;

				callback(graph);

			})	
		//});	
	});



	function checkChildren(JSONnewick, callback){

		var firstTime = true;
		JSONnewick.visit(function(node) {
			var nodeName = '';

			if(firstTime == true){
				newickRoot = node;
				firstTime = false;
			}
			
			if (node.data == '') nodeName = 'TransitionNode' + String(node.id);
			else nodeName = node.data;
				
			nodes[nodeName] = {key : nodeName, isolates: [], profile: []};

			for(i in node.children){
				targetName = '';
				node.children[i].parent_id = node.id;
				if (node.children[i].data == '') targetName = 'TransitionNode' + String(node.children[i].id);
				else targetName = node.children[i].data;

				links.push({source: nodeName, target: targetName, value: node.children[i].branchlength, bootstrap: node.children[i].bootstrap});	
				
				if (maxLinkValue < node.children[i].branchlength) maxLinkValue = node.children[i].branchlength;
			}

		});

		callback();

	}

	function createDistanceMatrix(JSONnewick, callback){

		var distanceMatrix = [];
		var countValues = 0;

		constructArray(JSONnewick, function(){
			console.log(arrayofnodes.length);

			for(i = 0; i<arrayofnodes.length; i++){
				distanceMatrix.push([]);
				for(j=i; j<arrayofnodes.length; j++){
					//countValues +=1;
					//console.log(countValues +=1, commonAncestor(arrayofnodes[i], arrayofnodes[j]));
					distanceMatrix[i].push(commonAncestor(arrayofnodes[i], arrayofnodes[j]));
				}
			}
			//console.log(countValues);
			callback(distanceMatrix);

		});


	}

	function parents(node) {
	  var parents = [];
	  var distances = [];
	  //console.log(node);
	  try{
	  	while(node.parent_id != null){
		  	parents.unshift(node.id);
		  	distances.unshift(node.branchlength);
		  	node = objectofnodes[node.parent_id];

		 }
	  }
	  catch(err){
	  }
	  parents.unshift(newickRoot.id);
	  distances.unshift(0);
	  return [parents, distances];
	}

	function commonAncestor(node1, node2) {
	  var results1 = parents(node1);
	  var results2 = parents(node2);

	  var parents1 = results1[0];
	  var parents2 = results2[0];
	  var distances1 = results1[1];
	  var distances2 = results2[1];

	  if (parents1[0] != parents2[0]) throw "No common ancestor!"

	  for (var i = 0; i < parents1.length; i++) {
	    if (parents1[i] != parents2[i]){
	    	
	    	var newdistances1 = distances1.slice(i-1, distances1.length);
	    	var dist1 = 0;
	    	for (i in newdistances1) dist1 += parseFloat(newdistances1[i]);
	    	var newdistances2 = distances2.slice(i-1, distances2.length);
	    	var dist2 = 0;
	    	for (i in newdistances2) dist2 += parseFloat(newdistances2[i]);

	    	//console.log(parents1, parents2);
	    	//console.log([parents1[i - 1], newdistances2 + newdistances1]);
	    	//console.log(node1.id, node2.id);
	    	//console.log(dist2 + dist1);
	    	return parseFloat(dist2 + dist1);
	    }
	  }
	  var newdistances1 = distances1.slice(i, distances1.length);
	  var dist1 = 0;
	  for (i in newdistances1) dist1 += parseFloat(newdistances1[i]);
      var newdistances2 = distances2.slice(i, distances2.length);
	  var dist2 = 0;
	  for (i in newdistances2) dist2 += parseFloat(newdistances2[i]);
	  return dist2 + dist1;
	}

	function constructArray(JSONnewick, callback){
		JSONnewick.visit(function(node) {
			arrayofnodes.push(node);
			objectofnodes[node.id] = node;
		});
		callback();
	}


	function checkIsolates(dataset, callback){

		dataset.isolates.forEach(function(isolate){

			if (sameProfileHas.hasOwnProperty(isolate[dataset.key])){
				isolate[dataset.key] = sameProfileHas[isolate[dataset.key]];
			}

			if(nodes[isolate[dataset.key]]){
				var arr = [];
				for (i in dataset.metadata) arr.push(isolate[dataset.metadata[i]]);
				//var arr = Object.keys(isolate).map(function(k) { return isolate[k]; });
			}

			try{
				nodes[isolate[dataset.key]].isolates.push(arr);
			}
			catch (err){
				var x = true;
			}
			
		});

		callback();
	}
}


module.exports = function(JSONnewick, callback){

	newickParser(JSONnewick, function(graph){
		callback(graph);
	});
}