import os
import sys
import corpus2
import argparse
import networkx
from scipy import spatial

import saper
import similarity
import transformator

from grafon import sumoproc

try:
    import argcomplete
except ImportError:
    argcomplete = None

def make_parser():
    desc = "Podobienstwo dwoch dokumentow na zasadzie wydzielenia podgrafu z SUMO"
    parser = argparse.ArgumentParser(description = desc) 
    parser.add_argument('-g', '--graph-file', dest = 'graph_file',
            required = True)
    parser.add_argument('-n', '--normalize', dest = 'normalize', action = 'store_true')
    parser.add_argument('-s', '--simple', dest = 'simple', action = 'store_true',
            help = 'Simple processing. If set, then while the vectors are built '
                   'from the documents the number of occurence concept in the document '
                   'is ignored. There is binary information: occurs/notoccurs. '
                   'Build the binary-like vectors.')
    parser.add_argument('-o', '--out-csv', dest = 'out_csv', default = 'out.csv')
    parser.add_argument('-T', '--tf-idf', dest = 'tf_idf', action = 'store_true')
    parser.add_argument('-S', '--run-saper', dest = 'run_saper', action = 'store_true')
    parser.add_argument('-t', '--tagset', dest = 'tagset', 
            required = False, default = 'nkjp')
    if argcomplete:
        argcomplete.autocomplete(parser)
    return parser

def read_csv_graph(filename):
    g = networkx.Graph()
    with open(filename, 'rt') as fg:
        for line in fg:
            n1, n2 = line.strip().split(';')[0:2]
            g.add_path([n1, n2])
    return g


def any_subgraph(nlist, g):
    '''Returns a subgraph from g contains all nodes from nlist
    '''
    prs = []
    ng = networkx.Graph()
    for n1 in nlist:
        for n2 in nlist:
            if not sorted([n1, n2]) in prs:
                prs.append(sorted([n1, n2]))
                try:
                    ng.add_path(networkx.algorithms.shortest_path(g, n1, n2))
                except Exception, e:
                    # print e
                    pass
    mst = networkx.algorithms.mst.kruskal_mst(ng, weight=1)
    return mst

def build_vector(nodes, head, cfiles = None):
    '''
    cfiles - concepts from file.
    '''
    v = []
    for h in head:
        if h in nodes:
            v.append(1.0 if not cfiles else cfiles.get(h, 1.0))
        else:
            v.append(0.0)
    return v

def sum_normalization(vec):
    s = sum(vec)
    return [v/s for v in vec]

def save_vectors(vectors, header, files, filename):
    with open(filename, 'wt') as fout:
        with open(filename + '.mat', 'wt') as fout_cluto:
            fout_cluto_clabel = open(filename + '.mat.clabel', 'wt')
            first = True
            for h in header:
                if not first:
                    fout.write(',')
                else:
                    first = False
                fout.write('%s' % h)
                fout_cluto_clabel.write('%s\n' % h)
            fout.write(',class\n')
            
            fout_cluto_rlabel = open(filename + '.mat.rlabel', 'wt')
            nnz = 0
            for vec in vectors:
                for v in vec:
                    if v != 0:
                        nnz += 1
            fout_cluto.write('%d %d %d\n' % (len(vectors), len(vectors[0]), nnz))
            for i, vec in enumerate(vectors):
                first = True
                for c, v in enumerate(vec):
                    if not first:
                        fout.write(',')
                    else:
                        first = False
                    fout.write('%f' % (v))
                    if v != 0:
                        fout_cluto.write('%d %f ' % (c + 1, v))
                fout.write(',%s\n' % files[i])
                fout_cluto.write('\n')
                fout_cluto_rlabel.write('%s\n' % files[i])

def run_saper(workdir, infiles, outfiles):
    s_config = '/mnt/data/repos/saper/cfg/pkedzia'

    for i, ifile in enumerate(infiles):
        print >> sys.stderr, 'Running saper for file: %s...' % ifile
        s_args = [ '-c', s_config,
               '-t', 'plain',
               os.path.join(workdir, ifile), 
               '-o', os.path.join(workdir, outfiles[i])]
        saper.saper_run.main(s_args)

def main(argv = None):
    parser = make_parser()
    args = parser.parse_args(argv)
    tagset = corpus2.get_named_tagset(args.tagset)

    workdir = '/mnt/data/repos/grafon/grafon/resources/sample_texts'
    infiles = [
            't1-gazeta.txt',
            't2-wp.txt',
            't3-onet.txt',
            't4-wyborcza-pirat.txt',
            't5-wyborcza-ukraina.txt',
            't6-sport.txt',
            't7-sport.txt',
            't8-tvnsport.txt',
            't9-tvnsport.txt',
            't10-tvnsport.txt',
            't11-wp.txt',
            't12-wp.txt',
            't13-wp.txt',
            't14-gazeta.txt',
            't15-gazeta.txt',
            't16-onet.txt',
            't17-onet.txt',
            't18-onet.txt',
            't19-eurosport.txt',
            't20-facebook.txt',
            't21-facebook.txt',
            't22-plotek.txt']
    files = [
            't1-gazeta.ccl',
            't2-wp.ccl',
            't3-onet.ccl',
            't4-wyborcza-pirat.ccl',
            't5-wyborcza-ukraina.ccl',
            't6-sport.ccl',
            't7-sport.ccl',
            't8-tvnsport.ccl',
            't9-tvnsport.ccl',
            't10-tvnsport.ccl',
            't11-wp.ccl',
            't12-wp.ccl',
            't13-wp.ccl',
            't14-gazeta.ccl',
            't15-gazeta.ccl',
            't16-onet.ccl',
            't17-onet.ccl',
            't18-onet.ccl',
            't19-eurosport.ccl',
            't20-facebook.ccl',
            't21-facebook.ccl',
            't22-plotek.ccl']

    workdir = '/mnt/data/repos/grafon/grafon/resources/sample_texts2'
    infiles = [
            '1-koty.txt',
            '2-koty.txt',
            '3-koty.txt',
            '4-koty.txt',
            '5-ryby.txt',
            '6-ryby.txt',
            '7-ryby.txt',
            '8-ryby.txt',
            '9-gory.txt',
            '10-gory.txt',
            '11-gory.txt',
            '12-gory.txt',
            '13-rzeki.txt',
            '14-rzeki.txt',
            '15-rzeki.txt',
            '16-rzeki.txt']
    files = [
            '1-koty.ccl',
            '2-koty.ccl',
            '3-koty.ccl',
            '4-koty.ccl',
            '5-ryby.ccl',
            '6-ryby.ccl',
            '7-ryby.ccl',
            '8-ryby.ccl',
            '9-gory.ccl',
            '10-gory.ccl',
            '11-gory.ccl',
            '12-gory.ccl',
            '13-rzeki.ccl',
            '14-rzeki.ccl',
            '15-rzeki.ccl',
            '16-rzeki.ccl']

    if args.run_saper:
        run_saper(workdir, infiles, files)
    
    # sumo graph
    print >> sys.stderr, 'Reading graph'
    g = read_csv_graph(args.graph_file)

    # jak sie zrobi min span tree przed sps to dochodzi do sytuacji, ze z wezla a,
    # do wezla b trzeba isc bardzo okrezna sciezka, dlatego nie mozna tutaj 
    # zrobic mst!!
    # g = networkx.algorithms.mst.kruskal_mst(g, weight=1)

    # concepts from files
    concepts = []
    for f in files:
        print >> sys.stderr, 'Reading file:', f
        concepts.append(sumoproc.get_concepts_from_file(tagset, os.path.join(workdir, f)))
    
    # subgraphs from g contains concepts
    sgraphs = []
    for i, c in enumerate(concepts):
        print >> sys.stderr, 'Making subgraph:', files[i]
        sgraphs.append(any_subgraph(c.keys(), g))
    
    print >> sys.stderr, 'Building header...'
    head = set()
    for s in sgraphs:
        head = head.union(set(s))

    vectors = []
    for i, s in enumerate(sgraphs):
        if not args.simple:
            print >> sys.stderr, 'Building not-simple vector for file:', files[i]
            vectors.append(build_vector(s, head, cfiles = concepts[i]))
        else:
            print >> sys.stderr, 'Building simple vector for file:', files[i]
            vectors.append(build_vector(s, head))

    if args.normalize:
        for i, v in enumerate(vectors):
            print >> sys.stderr, 'Normalizing vector for file:', files[i]
            vectors[i] = sum_normalization(v)

    if args.tf_idf:
        print >> sys.stderr, 'Calculating tf/idf for built vectors...'
        t = transformator.TfIdf()
        vectors = t.calculate(vectors)


    calculated = []
    s = similarity.BhattacharyyaSimilarity()
    for i, v in enumerate(vectors):
        for j, v in enumerate(vectors):
            if i != j and not sorted([vectors[i], vectors[j]]) in calculated:
                calculated.append(sorted([vectors[i], vectors[j]]))
                # result = 1 - spatial.distance.cosine(vectors[i], vectors[j])
                result = s.calculate(vectors[i], vectors[j])
                print files[i], ';', files[j], ';', result

    save_vectors(vectors, head, files, args.out_csv)

if __name__ == '__main__':
    main()
