"""
Saper is configurable parser for semantic annotation of texts in polish
language.
"""
import argparse
import corpus2
import os
from config import ConfigLoader
from flow import FlowController
import saperio.utils as io_utils
try:
  import argcomplete
except ImportError:
  argcomplete = None


def create_arg_parser(argv):
  arg_parser = argparse.ArgumentParser(description='Some cool military' +
                           ' style application')
  arg_parser.add_argument('input_file', help='input file')
  arg_parser.add_argument('-o', '--output', type=str, default=None,
              help='output file or folder in batch mode')
  arg_parser.add_argument('-r', '--relations_output',
              help='path to relation output file if not' +
                 ' present and output file path is selected' +
                 ' relations will be saved to *.rel.xml file.')
  arg_parser.add_argument('-ra', '--append_relations', action="store_true",
              help=("whether to append extracted relations to an existing"
                    "relation's file or not"))
  arg_parser.add_argument('-c', '--config', type=str, required=True,
              help='Path to configuration file')
  arg_parser.add_argument('-t', '--input_type', type=str,
              default='ccl', help='input type parameter' +
              ' available types: ccl, plain')
  arg_parser.add_argument('-b', '--batch', default=False, action='store_true',
              help='application treats input file as batch file')
  arg_parser.add_argument('--continue-on-exception', default=False,
              action='store_true', dest='cont_on_exc',
              help=('Only for batch mode. While processing a single file an '
              'exception may occur. Thus, if this flag is set to True the next '
              'file will be processed. Otherwise the whole process will stop.'))
  arg_parser.add_argument('--tagset', default='nkjp', help='used tagset')
  if argcomplete:
    argcomplete.autocomplete(arg_parser)
  args = arg_parser.parse_args(argv)
  return args


def batch_processing(tagset, input_list, input_type, output, config, exc_cont,
                     append_relations=False):
  """
  The method processes a list of given files according to the configured
  workflow. If the output directory is given, the files will be saved there,
  otherwise data will be printed to the standard output.

  The input_list can be a batch file or a simple python list.

  @type tagset: str
  @type input_list: str or list
  @type input_type: str
  @type output: str
  @type config: ConfigLoader
  @type exc_cont: bool
  @type append_relations: bool
  """
  tagset = corpus2.get_named_tagset(tagset)
  # The documents variable is a generator
  documents = io_utils.load_documents(input_list, input_type, config)
  flow = FlowController(config)
  problematic_files = []

  for document in documents:
    try:
      out_document = flow.process_flow(document)
      if output:
        ccl_path, rel_path = document.path().split(';')
        ccl_path = os.path.join(output, os.path.basename(ccl_path))
        if not ccl_path.endswith('.xml'):
          ccl_path += '.xml'
        rel_path = os.path.join(
          output,
          os.path.basename(rel_path).replace('.xml', '.rel.xml'))
        if not rel_path.endswith('.rel.xml'):
          rel_path += '.rel.xml'
        io_utils.write_ccl_file(out_document, ccl_path, tagset)
        # Even if the processed document has no relation, the empty
        # relation file should be written - it provides information
        # about the document
        if append_relations and os.path.exists(rel_path):
          io_utils.write_document_relations(
            out_document,
            rel_path,
            io_utils.load_document(rel_path, input_type, config)
          )
        else:
          io_utils.write_document_relations(out_document, rel_path)

      else:
        io_utils.print_ccl_file(out_document, tagset)
        io_utils.print_document_relations(out_document)
    except Exception as exc:
      problematic_files.append(document.path())
      if not exc_cont:
        raise exc

  if problematic_files:
    print ("The list of problematic files that caused exceptions and were "
           "not fully processed. Thus, were not saved."
           "\n{}".format("\n".join(problematic_files)))


def single_file_processing(args, config):
  tagset = corpus2.get_named_tagset(args.tagset)
  document = io_utils.load_document(args.input_file, args.input_type, config)
  flow = FlowController(config)
  processed_document = flow.process_flow(document)
  if args.output:
    io_utils.write_ccl_file(processed_document, args.output, tagset)
    if len(processed_document.relations()):
      if args.relations_output:
        rel_filename = args.relations_output
      else:
        directory, filename = os.path.split(args.output)
        splited_filename = filename.split('.')
        if len(splited_filename) >= 2:
          rel_filename = \
            "%s.rel.%s" % ('.'.join(splited_filename[:-1]),
                          splited_filename[-1])
        else:
          rel_filename = 'rel_%s' % splited_filename[0]
        rel_filename = os.path.join(directory, rel_filename)
      if args.append_relations and os.path.exists(rel_filename):
        io_utils.write_document_relations(
          processed_document,
          rel_filename,
          io_utils.load_document(rel_filename, args.input_type, config)
        )
      else:
        io_utils.write_document_relations(processed_document, rel_filename)
  else:
    io_utils.print_ccl_file(processed_document, tagset)
    if len(processed_document.relations()):
      io_utils.print_document_relations(processed_document)


def load_config(cfg_file_path):
  """! Load a configuration file and create a ConfigObject. """
  return ConfigLoader(cfg_file_path)


def main(argv = None):
  args = create_arg_parser(argv)
  config = ConfigLoader(args.config)
  if args.input_file:
    if args.batch:
      batch_processing(args.tagset, args.input_file, args.input_type,
               args.output, config, args.cont_on_exc, args.append_relations)
    else:
      single_file_processing(args, config)


if __name__ == '__main__':
  main()
