#!/usr/bin/python
# -*- coding: utf-8 -*-

# <one line to give the library's name and an idea of what it does.>
# Copyright (C) 2014  <copyright holder> <email>
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

'''
Oblicza podobieństwo między wszystkimi zdaniami dla przekazanych plików.
Dla każdego pliku, dla każdego zdania tworzy graf i porownuje do siebie 
te grafy. Oblicza podobienstwo tylko między dokumentami, nie oblicza 
podobieństwa między grafami powstałymi w tym samym dokumencie.
'''

import os
import sys
try:
  import argcomplete
except ImportError:
  argcomplete = None

import grafon_base
from grafon.graphs.basegraph import BaseGraph
from grafon.utils.grafonconfig import GrafonConfig
from grafon.gbuilders.graphbuilder import GraphBuilder

def make_parser(desc = ''):
  aparser = grafon_base.make_parser(desc)
  aparser.add_argument('-f1', '--cclfile-1', dest='ccl1',
                       required=True, type=str,
                       help='First ccl file. For each sentences into file, ' \
                         'the graphs will be build.')
  aparser.add_argument('-r1', '--relcclfile-1', dest='relccl1',
                       required=True, type=str,
                       help='First relccl file. Depends on the edge ' \
                         'builders relccl file may be used for build edges.')
  aparser.add_argument('-f2', '--cclfile-2', dest='ccl2',
                       required=True, type=str,
                       help='Second ccl file. For each sentences into file, ' \
                         'the graphs will be build.')
  aparser.add_argument('-r2', '--relcclfile-2', dest='relccl2',
                       required=True, type=str,
                       help='Second relccl file. Depends on the edge ' \
                         'builders relccl file may be used for build edges.')
  aparser.add_argument('-o', '--out-res-file', dest='out_res_file',
                       required=False, help=( 'If options is given then '
                         'then the results will be stroed into given filename. '
                         'If not gvien then the result will be stored into '
                         'standard output.'))
  if argcomplete:
    argcomplete.autocomplete(aparser)
  return aparser

def calculate_print_measures(measures, 
                             bg1, all_g1_graphs, g1id,
                             bg2, all_g2_graphs, g2id,
                             ofilename = None):
  """!
  General function to calculate and prints the similarity value for the given
  list of graphs. The similarity is calculated between all graphs from 
  the lists.
  """
  out = sys.stdout if not ofilename else open(ofilename, 'wt')
  # dictionaries with senrecnes
  g1sentences = dict()
  for p in bg1.document.paragraphs():
    for s in p.sentences():
      k = "%s:%s" % (g1id, s.id())
      g1sentences[k] = "\"%s\""%' '.join(t.orth_utf8() for t in s.tokens())
  g2sentences = dict()
  for p in bg2.document.paragraphs():
    for s in p.sentences():
      k = "%s:%s" % (g2id, s.id())
      g2sentences[k] = "\"%s\""%' '.join(t.orth_utf8() for t in s.tokens())

  out.write('SentG1; SentG2; ')
  for m in measures:
    out.write('%s;' % m)
  out.write('\n')

  for sid1, g1 in all_g1_graphs:
    for sid2, g2 in all_g2_graphs:
      s1 = g1sentences.get("%s:%s" % (g1id, sid1), "%s:%s" % (g1id, sid1))
      s2 = g2sentences.get("%s:%s" % (g2id, sid2), "%s:%s" % (g2id, sid2))
      out.write('%s;%s;' % (s1, s2))
      for m in measures:
        v = m.calculate(g1, g2)
        out.write('%f;' % v)
      out.write('\n')
  out.close()

def main(argv=None):
  p = make_parser(__doc__)
  args = p.parse_args(argv)
  if args.verbose_mode:
    print >> sys.stderr, 'Parsing grafon config and reading resources...'
  cfg = GrafonConfig(args.config)
  logging.info('Parsing grafon config and reading resources...')

  tagset = cfg.tagset()
  node = cfg.node(tagset)
  filters = cfg.filters(tagset)

  bg1 = BaseGraph(node, filters)
  bg2 = BaseGraph(node, filters)

  if args.verbose_mode:
    print >> sys.stderr, 'Updating resources into base graphs...'
  logging.info('Updating resources into base graphs...')
  bg1.update_resources(cfg)
  bg2.update_resources(cfg)

  smerger = cfg.sumo_merger(bg1)
  pmerger = cfg.plwn_merger(bg1)

  sgraph    = grafon_base.read_sumo_graph(cfg) if smerger else None
  plwngraph = grafon_base.read_plwn_graph(cfg) if pmerger else None
  reducers  = cfg.reducers() if cfg.reducers() else None

  try:
    relccl1 = args.relccl1 if os.path.exists(args.relccl1) else args.ccl1
    relccl2 = args.relccl2 if os.path.exists(args.relccl2) else args.ccl2
    bgbuilder = GraphBuilder()
    bgbuilder.build_graph_from_file(bg1, args.ccl1, relccl1, tagset)
    bgbuilder.build_graph_from_file(bg2, args.ccl2, relccl2, tagset)
  except Exception, e:
    logging.error("Exception: {}".format(e))
    return 0

  for ebuilder in cfg.ebuilders():
    logging.info('Adding edges into graph 1 using builder {}'.format(ebuilder))
    ebuilder.add_edges(bg1)
    logging.info('Adding edges into graph 2 using builder {}'.format(ebuilder))
    ebuilder.add_edges(bg2)
  for rebuilder in cfg.rebuilders():
    logging.info('Rebuilding graphs usingr ebuilder {}'.format(rebuilder))
    rebuilder.rebuild_base_graph(bg1)
    rebuilder.rebuild_base_graph(bg2)

  all_g1_graphs = \
    grafon_base.merge_graphs(bg1, smerger, sgraph, pmerger, plwngraph, reducers)
  all_g2_graphs = \
    grafon_base.merge_graphs(bg2, smerger, sgraph, pmerger, plwngraph, reducers)

  g1id = 'G1'
  g2id = 'G2'
  if args.merge_sents:
    all_g1_graphs = \
      grafon_base.merge_graphs_into_one(bg1, g1id, all_g1_graphs)
    all_g2_graphs = \
      grafon_base.merge_graphs_into_one(bg2, g2id, all_g2_graphs)

  # Filter graph by the min number of nodes and/or edges
  if cfg.min_edge_count() or cfg.min_node_count():
    grafon_base.filter_n_e_by_count(cfg, all_g1_graphs)
    grafon_base.filter_n_e_by_count(cfg, all_g2_graphs)

  logging.info('Calculating similarities...')
  calculate_print_measures(cfg.measures(),
                           bg1, all_g1_graphs, g1id,
                           bg2, all_g2_graphs, g2id,
                           args.out_res_file)

  if args.visualise_dir:
    grafon_base.vis_graphs_into_files(
      bg1, all_g1_graphs, args.visualise_dir, oformat=args.visualise_format)
    grafon_base.vis_graphs_into_files(
      bg2, all_g2_graphs, args.visualise_dir, oformat=args.visualise_format)

  logging.info('Grafon - Everything has been done ;>')
if __name__ == '__main__':
  main()
