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

import redcap, os
from docx import Document
import argparse


def redcap_project_access(API_KEY):
    """
    Gets access to redcap form
    :param API_KEY:String obtained as argparse argument object
    :return: redcap Project object
    """
    project = redcap.Project('https://redcap.vanderbilt.edu/api/', API_KEY)
    return project

def participant_filter(project,OPTIONS):
    """
    Filter participant data from export data. 
    :param project: redcap.Project object
    :param OPTIONS: parsed from user
    no return
    """
    data = redcap_field_fetch(project)
    participant_id = splitter(OPTIONS.participant_id)
    for participant_data in data:
        for participant in participant_id:
            if(participant in participant_data.values()):
                document = document_template_open(OPTIONS.file) 
                doc = replace_field(project,participant_data,document,participant,OPTIONS)

def replace_field(project,data,document,participant,OPTIONS):
    """
    Loops through the document and replaces the field string with
    appropriate values from redcap form
    :param project: REDCap project
    :param data: json object
    :param document: docx document object
    :param participant: participant ID value
    :param OPTIONS: arguments parsed from user
    :return: docx.Document object
    """
    replacements = splitter(OPTIONS.replacement)
    for replacement in replacements:
        for para in document.paragraphs:
            if "sex" in replacement:                #replace his/her with appropriate pronoun
                if('his/her' in para.text):
                    inline = para.runs
                    for i in range(len(inline)):
                        if( 'his/her' in inline[i].text):
                            text = inline[i].text.replace('his/her', 'her') \
                                if data.get(replacement)=='0' \
                                else inline[i].text.replace('his/her', 'his')
                            inline[i].text=text 
            else:
                if replacement in para.text:        #replace field
                    inline = para.runs
                    for i in range(len(inline)):
                        if replacement in inline[i].text:
                            text = inline[i].text.replace(replacement, data.get(replacement))
                            inline[i].text = text
        doc = replace_in_tables(data, document, replacement)
        save_doc(doc,OPTIONS.destination,participant)
        if OPTIONS.upload:
            upload_to_redcap(project,document,participant,OPTIONS)
    return document

def splitter(option):
    """
    Splits arguments by ','
    :param option: args parsed from user
    :return: list containing participants
    """
    if not option:
        return None 
    else:
        return option.split(',')

def save_doc(document,destination,participant_id):
    """
    Saves document with replaced fields with participant id as filename
    :param document: docx.document object
    :param destination: args parsed from user
    :param participant_id: participant id value
    no return
    """
    filename = destination+'/'+participant_id+'.docx'
    document.save(filename)

def upload_to_redcap(project,document,participant_id, OPTIONS):
    """
    Uploads the report back to redcap
    :param project: redcap project object
    :param document: docx.document object
    :param participant_id: participant id value
    :param OPTIONS: arguments 
    """
    filename = ''+participant_id+'.docx'
    project.import_file(participant_id,OPTIONS.upload,filename,document)

def replace_in_tables(data,document,replacement):
    """
    Loops through tables in the document and replaces the field string with
    the replacement data from redcap form
    :param data: json object
    :param document: docx document object
    :param replacement: string of redcap field variable name
    :return: docx.Document object
    """
    for table in document.tables:
        for row in table.rows:
            for cell in row.cells:
                for para in cell.paragraphs:
                    para.text = para.text.replace(replacement,data.get(replacement)) if not data.get(replacement)==None \
                                            else para.text.replace(replacement,'NA')
    return document

def document_template_open(file_path):
    """
    Opens the document template used for document generation
    :param filepath: path to template document
    :return: Document if exists
    """
    if os.path.exists(file_path):
        document = Document(file_path)
        return document
    else:
        print ("""Template file doesn't exist: Check filepath and filename provided
        Hint:Also check that suffix of filename is provided eg:docx in filename.docx""")

def redcap_field_fetch(project):
    """
    Exports data from the redcap form associated with the API Key. 
    Only the fields mentioned are pulled.
    :param project: redcap.Project object
    :return:json object with a list of dicts. Each participant info is a dict
    """
    data = project.export_records(format='json')
    return data

def add_to_parser():
    """
    Method to add arguments to default parser for Document generator.

    :return: parser object with new arguments
    """
    parser = argparse.ArgumentParser(prog='redcap_report_generate', description="REDCap Report Generator")
    parser.add_argument("-k","--key", dest='redcap_key', default=None, help='Redcap API Token')
    parser.add_argument("-r","--replace", dest='replacement',default=None, help=' \
                       words to be replaced')
    parser.add_argument("-f","--file", dest='file',default=None, help='Path to template document')
    parser.add_argument("-p","--participant", dest='participant_id', default=None,\
                        help='Participant Id')
    parser.add_argument("-d","--dest", dest='destination', default=None, \
                        help='Destination for output files')
    parser.add_argument("-u","--uploadTo", dest='upload', default=None, \
                        help='Redcap field where generated document is to be uploaded to')
    return parser

def run_document_generator():
    """
    Execution point of Document Generator

    :return: None
    """
    parser = add_to_parser()
    OPTIONS = parser.parse_args()
    project = redcap_project_access(OPTIONS.redcap_key)
    participant_filter(project,OPTIONS)

if __name__ == '__main__':
    run_document_generator()
