#!/usr/bin/env python 

################################################################################
### COPYRIGHT ##################################################################

# New York Genome Center

# SOFTWARE COPYRIGHT NOTICE AGREEMENT
# This software and its documentation are copyright (2017) by the New York
# Genome Center. All rights are reserved. This software is supplied without
# any warranty or guaranteed support whatsoever. The New York Genome Center
# cannot be responsible for its use, misuse, or functionality.

# Version: 0.1
# Author: Andre Corvelo

################################################################# /COPYRIGHT ###
################################################################################



################################################################################
### MODULES ####################################################################

from optparse import OptionParser
from sys import stdin, stdout, stderr, exit
from numpy import cumsum

################################################################### /MODULES ###
################################################################################



################################################################################
### FUNCTIONS ##################################################################
	
def lca(ts):
	if len(ts) != 1:	
		f = ts[0].split(':')
		l = ts[-1].split(':')
		for i in xrange(len(f)):
			if f[i] != l[i]:
				return f[i-1]	
			else:
				continue
		return f[-1]
	else:
		return ts[0].split(':')[-1]	


def find_lowest_rank(taxpath, tax_d):
	ranks = set(['species', 'genus', 'family', 'order', 'class', 'phylum', 'kingdom', 'root'])
	for rank in (tax_d[t][1] for t in taxpath.split(':')[::-1]):
		if rank in ranks:
			return rank
	
def abs_lowest_rank(taxpath1, taxpath2, tax_d):
	ranks = ['species', 'genus', 'family', 'order', 'class', 'phylum', 'kingdom', 'root']
	for rank in ranks:
		if rank in [tax_d[t][1] for t in taxpath1.split(':') + taxpath2.split(':')]:
			return rank
		
################################################################# /FUNCTIONS ###
################################################################################



################################################################################
### ARGUMENTS,OPTIONS ##########################################################

parser = OptionParser(usage="\n%prog -t tax file", version="%prog 0.1")

parser.add_option(
	"-i",
	metavar = "FILE",
	type = "string",
	dest = "class_file",
	default = 'stdin',
	help="Input classification file (default = 'stdin')"
	)

parser.add_option(
	"-t",
	metavar = "FILE",
	type = "string",
	dest = "tax_file",
	default = None,
	help = "Taxonomic table file (Mandatory)"
	)


(opt, args) = parser.parse_args()

if opt.tax_file == None:
	parser.print_help()
	exit(-1)
     
######################################################### /ARGUMENTS,OPTIONS ###
################################################################################



################################################################################
### CONSTANTS ##################################################################

################################################################# /CONSTANTS ###
################################################################################



################################################################################
### MAIN #######################################################################

if __name__ == '__main__':
	# read tax info
	tax_d = {}
	tax_file = open(opt.tax_file, 'r')	
	for l in tax_file:
		la = l.strip().split('\t')
		if la[1] == 'subkingdom' or la[1]=='superkingdom':
			la[1] = 'kingdom'
		tax_d[la[0]] = la
	tax_file.close()
	tax_d['0'] = ['0', 'no rank', 'unmapped', '0']
	tax_d['1'] = ['1', 'root', 'root', '1']
	tax_d['-'] = ['-', 'no rank', 'filtered out', '0:-']
	
	ranks = ['species', 'genus', 'family', 'order', 'class', 'phylum', 'kingdom', 'root']
	cons_d = {}
	pos_d = {}
	
	for rank in ranks:
		cons_d[rank] = 0
		pos_d[rank] = 0

	# read classification file
	if opt.class_file != 'stdin':
		class_file = open(opt.class_file, 'r')
	else:
		class_file = stdin
	for l in class_file:	
		taxid1 = l.strip().split('\t')[1]
		taxid2 = l.strip().split('\t')[2]
		if taxid1 != '0' and taxid2 != '0' :
			taxpath1 = tax_d[taxid1][3]
			taxpath2 = tax_d[taxid2][3]
			lowest_pos = abs_lowest_rank(taxpath1, taxpath2, tax_d)
			pos_d[lowest_pos] += 1

			if taxid1 == taxid2 or set(taxpath2.split(':')).issubset(set(taxpath1.split(':'))):
				lowest_cons = find_lowest_rank(taxpath1, tax_d)
			elif set(taxpath1.split(':')).issubset(set(taxpath2.split(':'))):
				lowest_cons = find_lowest_rank(taxpath2, tax_d)
			else:
				lowest_cons = find_lowest_rank(tax_d[lca(sorted([taxpath1,taxpath2]))][3], tax_d)

			cons_d[lowest_cons] +=1
			
	if opt.class_file != 'stdin':
		class_file.close()

		
	cons_cum = list(cumsum([cons_d[rank] for rank in ranks]))
	pos_cum = list(cumsum([pos_d[rank] for rank in ranks]))

	print 'Rank\tCConcordance'
	for i in xrange(len(ranks)):
		print '\t'.join([ranks[i], str(float(cons_cum[i])/pos_cum[i])])


###################################################################### /MAIN ###
################################################################################
