#!/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/>.
#

SENTGRAPH_DESCRIPTION = '''
Dla zadanego dokumentu tworzy graf. Graf taki następnie może być zapisany do
pliku w postaci graficznej. Na tak zbudowanym grafie istnieje możliwość 
obliczenia rankingu węzłów grafu za pomocą algorytmu PageRank.
'''
import logging
import os, sys
try:
    import argcomplete
except ImportError:
    argcomplete = None

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

def make_parser(desc = ''):
  """!
  Makes parser for Grafon
  """
  aparser = grafon_base.make_parser(desc)
  aparser.add_argument('-f', '--cclfile', dest='ccl',
                       required=True, type=str,
                       help=(
                         'Ccl file. For each sentences into file, '
                         'the graphs will be build.'))
  aparser.add_argument('-r', '--relcclfile', dest='relccl',
                       required=True, type=str,
                       help=(
                         'Relccl file. Depends on the edge '
                         'builders relccl file may be used for build edges.'))
  aparser.add_argument('-ns', '--node-sim', dest='node_sim_filename',
                       required=False, type=str, help=(
                         'If option is given, then in given filename will be '
                         'stored similarity between all nodes using '
                         'SIDD measure.'))
  aparser.add_argument('-n', '--n-jobs', dest='njobs',
                       required=False, type=int,
                       help=(
                         'If the option is given, the the merging will be run '
                         'on the given number of processes. If not given, '
                         'then the grafon will be run on single process.'))
  aparser.add_argument('-pr', '--pagerank', dest='pagerank',
                       action='store_true', default=False,
                       help = (
                         'If option is given, then for build graph the '
                         'PageRank will be run'))
  if argcomplete:
    argcomplete.autocomplete(aparser)
  return aparser

def main(argv = None):
  p = make_parser(SENTGRAPH_DESCRIPTION)
  args = p.parse_args(argv)

  if args.verbose_mode:
    print >> sys.stderr, 'Parsing grafon config and reading resources...'
  cfg = GrafonConfig(args.config)

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

  if args.njobs:
    if args.verbose_mode:
      print >> sys.stderr, \
        'Running grafon in multiprocess mode (%d jobs)...' % args.njobs
    logging.info(
      'Running grafon in multiprocess mode (%d jobs)...' % args.njobs)
  else:
    if args.verbose_mode:
      print >> sys.stderr, 'Running grafon in single process mode...'
    logging.info('Running grafon in single process mode...')

  bg = BaseGraph(node, filters)
  logging.info('Updating resources into base graph...')
  bg.update_resources(cfg)
  #
  sgraph = bg.resources[constants.RESOURCES_SUMO_HNDL]
  plwngraph = bg.resources[constants.RESOURCES_PLWN_HNDL]

  reducers = cfg.reducers() if cfg.reducers() else None
  try:
    relccl = args.relccl if os.path.exists(args.relccl) else args.ccl
    bgbuilder = GraphBuilder()
    bgbuilder.build_graph_from_file(bg, args.ccl, relccl, tagset)
  except Exception, e:
    logging.error("Exception: {}".format(e))
    return 0

  """
  k = bg.graph_dict.keys()[0]
  v = bg.graph_dict[k]
  bg.graph_dict.clear()
  bg.graph_dict[k] = v
  """
  for ebuilder in cfg.ebuilders():
    logging.info('Adding edges into graph using builder {}'.format(ebuilder))
    ebuilder.add_edges(bg)

  for rebuilder in cfg.rebuilders():
    logging.info('Rebuilding graph usingr ebuilder {}'.format(rebuilder))
    rebuilder.rebuild_base_graph(bg)

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

  if args.njobs:
    all_ghs = grafon_base.merge_graphs_in_proc(
      bg, smerger, sgraph, pmerger, plwngraph, reducers, args.njobs)
  else:
    all_ghs = grafon_base.merge_graphs(
      bg, smerger, sgraph, pmerger, plwngraph, reducers)

  gid = 'G'
  if args.merge_sents:
    all_ghs = grafon_base.merge_graphs_into_one(bg, gid, all_ghs)

  # 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_ghs)

  if args.out_graph_dir:
    grafon_base.save_graphs_into_files(
      bg, all_ghs, args.out_graph_dir, args.out_graph_format)

  # Calculate similarity
  if args.node_sim_filename:
    grafon_base.calculate_sim_between_all_nodes(
      cfg, all_ghs, args.node_sim_filename)

  # run PageRank
  if args.pagerank:
    grafon_base.run_pagerank_for_graphs(all_ghs)

  if args.visualise_dir:
    grafon_base.vis_graphs_into_files(
      bg, all_ghs, args.visualise_dir,
      oformat=args.visualise_format, 
      plwn_to_str=plwngraph != None)

  logging.info('Grafon - Everything has been done ;>')