import unicodecsv as csv
import json
import sys
import os
import copy
from datetime import datetime

CSV_HEADER_ROW = [
    "SortingIndex",
    "ItemType",
    "Label",
    "Response",
    "Comment",
    "MediaHypertextReference",
    "Latitude",
    "Longitude",
    "ItemScore",
    "ItemMaxScore",
    "ItemScorePercentage",
    "Mandatory",
    "FailedResponse",
    "Inactive",
    "ItemID",
    "ResponseID",
    "ParentID",
    "AuditOwner",
    "AuditAuthor",
    "AuditOwnerID",
    "AuditAuthorID",
    "AuditName",
    "AuditScore",
    "AuditMaxScore",
    "AuditScorePercentage",
    "AuditDuration",
    "DateStarted",
    "DateCompleted",
    "DateModified",
    "AuditID",
    "TemplateID",
    "TemplateName",
    "TemplateAuthor",
    "TemplateAuthorID",
    "ItemCategory",
    "RepeatingSectionParentID",
    "DocumentNo",
    "ConductedOn",
    "PreparedBy",
    "Location",
    "Personnel",
    "ClientSite",
    "AuditSite",
    "AuditArea",
    "AuditRegion",
    "Archived",
]

# audit item empty response
EMPTY_RESPONSE = ""

# audit item property constants
LABEL = "label"
COMMENTS = "comments"
TYPE = "type"
FAILED = "failed"
SCORE = "score"
MAX_SCORE = "max_score"
SCORE_PERCENTAGE = "score_percentage"
COMBINED_SCORE = "combined_score"
COMBINED_MAX_SCORE = "combined_max_score"
COMBINED_SCORE_PERCENTAGE = "combined_score_percentage"
PARENT_ID = "parent_id"
RESPONSE = "response"
INACTIVE = "inactive"
ID = "item_id"
MEDIAID = "media_id"
HREF = "href"
EXT = "file_ext"
SIGNATURE = "signature"
INFORMATION = "information"
MEDIA = "media"
RESPONSES = "responses"

# maps smartfield conditional statement IDs to the corresponding text
smartfield_conditional_id_to_statement_map = {
    # conditional statements for question field
    "3f206180-e4f6-11e1-aff1-0800200c9a66": "if response selected",
    "3f206181-e4f6-11e1-aff1-0800200c9a66": "if response not selected",
    "3f206182-e4f6-11e1-aff1-0800200c9a66": "if response is",
    "3f206183-e4f6-11e1-aff1-0800200c9a66": "if response is not",
    "3f206184-e4f6-11e1-aff1-0800200c9a66": "if response is one of",
    "3f206185-e4f6-11e1-aff1-0800200c9a66": "if response is not one of",
    # conditional statements for list field
    "35f6c130-e500-11e1-aff1-0800200c9a66": "if response selected",
    "35f6c131-e500-11e1-aff1-0800200c9a66": "if response not selected",
    "35f6c132-e500-11e1-aff1-0800200c9a66": "if response is",
    "35f6c133-e500-11e1-aff1-0800200c9a66": "if response is not",
    "35f6c134-e500-11e1-aff1-0800200c9a66": "if response is one of",
    "35f6c135-e500-11e1-aff1-0800200c9a66": "if response is not one of",
    # conditional statements for slider field
    "cda7c330-e500-11e1-aff1-0800200c9a66": "if slider value is less than",
    "cda7c331-e500-11e1-aff1-0800200c9a66": "if slider value is less than or equal to",
    "cda7c332-e500-11e1-aff1-0800200c9a66": "if slider value is equal to",
    "cda7c333-e500-11e1-aff1-0800200c9a66": "if slider value is not equal to",
    "cda7c334-e500-11e1-aff1-0800200c9a66": "if slider value is greater than or equal to",
    "cda7c335-e500-11e1-aff1-0800200c9a66": "if the slider value is greater than",
    "cda7c336-e500-11e1-aff1-0800200c9a66": "if the slider value is between",
    "cda7c337-e500-11e1-aff1-0800200c9a66": "if the slider value is not between",
    # conditional statements for checkbox field
    "4e671f40-e4ff-11e1-aff1-0800200c9a66": "if the checkbox is checked",
    "4e671f41-e4ff-11e1-aff1-0800200c9a66": "if the checkbox is not checked",
    # conditional statements for switch field
    "3d346f00-e501-11e1-aff1-0800200c9a66": "if the switch is on",
    "3d346f01-e501-11e1-aff1-0800200c9a66": "if the switch is off",
    # conditional statements for text field
    "7c441470-e501-11e1-aff1-0800200c9a66": "if text is",
    "7c441471-e501-11e1-aff1-0800200c9a66": "if text is not",
    # conditional statements for textsingle field
    "6ff300f0-e501-11e1-aff1-0800200c9a66": "if text is",
    "6ff300f1-e501-11e1-aff1-0800200c9a66": "if text is not",
    # conditional statements for signature field
    "831f8ff0-e500-11e1-aff1-0800200c9a66": "if signature exists",
    "831f8ff1-e500-11e1-aff1-0800200c9a66": "if the signature does not exist",
    "831f8ff2-e500-11e1-aff1-0800200c9a66": "if the signature name is",
    "831f8ff3-e500-11e1-aff1-0800200c9a66": "if the signature name is not",
    # conditional statements for barcode field
    "8259d900-12e3-11e4-9191-0800200c9a66": "if the scanned barcode is",
    "8259d901-12e3-11e4-9191-0800200c9a66": "if the scanned barcode is not",
}

# maps default answer IDs to corresponding Text
standard_response_id_map = {
    "8bcfbf00-e11b-11e1-9b23-0800200c9a66": "Yes",
    "8bcfbf01-e11b-11e1-9b23-0800200c9a66": "No",
    "8bcfbf02-e11b-11e1-9b23-0800200c9a66": "N/A",
    "b5c92350-e11b-11e1-9b23-0800200c9a66": "Safe",
    "b5c92351-e11b-11e1-9b23-0800200c9a66": "At Risk",
    "b5c92352-e11b-11e1-9b23-0800200c9a66": "N/A",
}

# maps header fields to their static IDs
header_field_id = {
    "DocumentNo": "f3245d46-ea77-11e1-aff1-0800200c9a66",
    "ConductedOn": "f3245d42-ea77-11e1-aff1-0800200c9a66",
    "PreparedBy": "f3245d43-ea77-11e1-aff1-0800200c9a66",
    "Location": "f3245d44-ea77-11e1-aff1-0800200c9a66",
    "Personnel": "f3245d45-ea77-11e1-aff1-0800200c9a66",
    "ClientSite": "f3245d41-ea77-11e1-aff1-0800200c9a66",
}


def get_json_property(obj, *args):
    """
    Returns json property if it exists. If it does not exist, returns an empty string
    :param obj:     JON Object
    :param args:    target path, list of keys
    :return:        if path exists, return value, otherwise return empty string
    """
    for arg in args:
        if isinstance(obj, list) and isinstance(arg, int):
            if len(obj) == 0:
                return EMPTY_RESPONSE
            obj = obj[arg]
        elif isinstance(obj, dict) and arg in obj.keys():
            obj = obj[arg]
        else:
            return EMPTY_RESPONSE
    return obj if obj is not None else EMPTY_RESPONSE


class CsvExporter:
    """
    provides tools to convert single json audit to CSV

    Attributes:
        audit_json(json): audit to be converted to CSV
        audit_table(list): the audit data converted to a table
    """

    def __init__(self, audit_json, export_inactive_items=True, header_only=False):
        """
        Constructor

        :param audit_json:      audit in JSON format to be converted to CSV
        """
        self.audit_json = audit_json
        self.export_inactive_items = export_inactive_items
        self.item_category = EMPTY_RESPONSE
        self.repeating_section_title = EMPTY_RESPONSE
        self.header_only = header_only
        self.item_map = {}
        self.map_items()
        self.audit_table = self.convert_audit_to_table()
        self.all_items = self.audit_items()

    def audit_id(self):
        """
        :return:    The audit ID
        """
        return self.audit_json["audit_id"]

    def audit_items(self):
        """
        :return:    All audit items, including header and non-header items
        """
        if self.header_only:
            return self.audit_json["header_items"]
        else:
            return self.audit_json["header_items"] + self.audit_json["items"]

    def map_items(self):
        """
        Creates a dictionary which maps each item to it's parent ID, Label, and Type.
        This tree can then be traversed recursively to find the Category or Section of a given item.
        """
        for item in self.audit_items():
            if item.get("item_id"):
                self.item_map[item["item_id"]] = {
                    "parent_id": item.get("parent_id") or EMPTY_RESPONSE,
                    "item_id": item.get("item_id") or EMPTY_RESPONSE,
                    "label": item.get("label") or EMPTY_RESPONSE,
                    "type": item.get("type") or EMPTY_RESPONSE,
                    "children": item.get("children") or EMPTY_RESPONSE,
                }

    def get_item_category(self, item_id):
        """
        Recursively traverses the item Map, following parent IDs until it gets to a Section or Category.
        When a Section or Category is found, the item Category is set to the label of that Section or Category.
        :param item_id: item ID to find Category for
        :return:        Category or Section label 
        """
        if not item_id:
            return EMPTY_RESPONSE
        elif (
            self.item_map[item_id]["type"] == "section"
            or self.item_map[item_id]["type"] == "category"
            or self.item_map[item_id]["type"] == "dynamicfield"
        ):
            return self.item_map[item_id]["label"] or EMPTY_RESPONSE
        else:
            return self.get_item_category(self.item_map[item_id]["parent_id"])

    def get_repeating_section_title(self, item_id, count):
        """
        Recursively traverses the item Map, following parent IDs until it gets to an element.
        When a Section or Category is found, the item ID is logged - it can then be used to group like questions together.
        Needed whenever questions are nested within a repeating section (e.g. within smart fields.)
        Count used to stop it running longer than needed.
        :param item_id: item ID to find Category for
        :return:        Item ID
        """
        if not item_id or count >= 10:
            return EMPTY_RESPONSE
        elif self.item_map[item_id]["type"] == "primeelement":
            return "primeelement"
        elif self.item_map[item_id]["type"] == "element":
            parent_id = self.item_map[item_id]["parent_id"]
            dynamic_field_id = self.item_map[parent_id]["item_id"]
            repeating_section_title = self.item_map[parent_id]["label"]
            children = self.item_map[parent_id]["children"]
            if children != "":
                index = children.index(item_id)
                return dynamic_field_id, repeating_section_title, index
            else:
                return item_id, repeating_section_title, ""

        else:
            count += 1
            return self.get_repeating_section_title(
                self.item_map[item_id]["parent_id"], count
            )

    def audit_custom_response_id_to_label_map(self):
        """
        :return:     dictionary mapping custom response_id's to their label
        """
        custom_response_sets = self.audit_json["template_data"]["response_sets"]
        audit_custom_response_id_to_label_map = dict()
        for response_set in custom_response_sets.keys():
            for response in custom_response_sets[response_set][RESPONSES]:
                audit_custom_response_id_to_label_map[response["id"]] = response[LABEL]
        return audit_custom_response_id_to_label_map

    def common_audit_data(self):
        """
        :return:    Selected sub-properties of the audit_data property of the audit JSON as a list
        """
        audit_data_property = self.audit_json["audit_data"]
        template_data_property = self.audit_json["template_data"]
        audit_date_completed = audit_data_property["date_completed"]
        header_data = self.audit_json["header_items"]
        audit_data_as_list = list()
        audit_data_as_list.append(audit_data_property["authorship"]["owner"])
        audit_data_as_list.append(audit_data_property["authorship"]["author"])
        audit_data_as_list.append(audit_data_property["authorship"]["owner_id"])
        audit_data_as_list.append(audit_data_property["authorship"]["author_id"])
        audit_data_as_list.append(audit_data_property["name"])
        audit_data_as_list.append(audit_data_property[SCORE])
        audit_data_as_list.append(audit_data_property["total_score"])
        audit_data_as_list.append(audit_data_property[SCORE_PERCENTAGE])
        audit_data_as_list.append(audit_data_property["duration"])
        audit_data_as_list.append(
            self.format_date_time(audit_data_property["date_started"])
        )
        audit_data_as_list.append(self.format_date_time(audit_date_completed))
        audit_data_as_list.append(
            self.format_date_time(audit_data_property["date_modified"])
        )
        audit_data_as_list.append(self.audit_id())
        audit_data_as_list.append(self.audit_json["template_id"])
        if (
            "name" in template_data_property["metadata"]
        ):  # check for rare case where very old templates/inspections may not include this key
            audit_data_as_list.append(template_data_property["metadata"]["name"])
        else:
            audit_data_as_list.append("Untitled Template")
        audit_data_as_list.append(template_data_property["authorship"]["author"])
        audit_data_as_list.append(template_data_property["authorship"]["author_id"])
        audit_data_as_list.append(self.item_category)
        audit_data_as_list.append(self.repeating_section_title)
        audit_data_as_list.append(self.get_header_item(header_data, "DocumentNo"))
        audit_data_as_list.append(self.get_header_item(header_data, "ConductedOn"))
        audit_data_as_list.append(self.get_header_item(header_data, "PreparedBy"))
        audit_data_as_list.append(self.get_header_item(header_data, "Location"))
        audit_data_as_list.append(self.get_header_item(header_data, "Personnel"))
        audit_data_as_list.append(self.get_header_item(header_data, "ClientSite"))
        audit_data_as_list.append(
            get_json_property(audit_data_property, "site", "name")
        )
        audit_data_as_list.append(
            get_json_property(audit_data_property, "site", "area", "name")
        )
        audit_data_as_list.append(
            get_json_property(audit_data_property, "site", "region", "name")
        )
        audit_data_as_list.append(self.audit_json["archived"])
        return audit_data_as_list

    @staticmethod
    def get_header_item(header_data, header_item_type):
        """
        Return standard header item response string
        :param header_data:         Audit JSON array of header items
        :param header_item_type:    Header type whose response is to be returned
        :return:    Header item response string
        """
        for item in header_data:
            if item.get("item_id") == header_field_id.get(header_item_type):
                if "responses" not in item.keys():
                    return EMPTY_RESPONSE
                if "text" in item["responses"].keys():
                    return get_json_property(item, "responses", "text")
                if "datetime" in item["responses"].keys():
                    return get_json_property(item, "responses", "datetime")
                if "location_text" in item["responses"].keys():
                    return get_json_property(item, "responses", "location_text")
        return EMPTY_RESPONSE

    @staticmethod
    def format_date_time(date):
        """
        Reformat datetime string from ISO format to 'DD Month YYYY HH:MM AM/PM'
        :param date:    date in the format: 2017-03-03T03:45:58.090Z
        :return:        date and time in the format: '03 March 2017 03:45 AM',
        """
        if date:
            date_object = datetime.strptime(date, "%Y-%m-%dT%H:%M:%S.%fZ")
            formatted_date = date_object.strftime("%d %B %Y")
            formatted_time = date_object.strftime("%I:%M:%S %p")
            return formatted_date + " " + formatted_time
        else:
            return EMPTY_RESPONSE

    def convert_audit_to_table(self):
        """
        Collects all audit item responses, appends common audit data and returns a 2-dimensional list.
        :return:    2 dimensional list, each list is a single item, which corresponds to a single row
        """
        self.audit_table = []
        for item in self.audit_items():
            if item.get("parent_id"):
                self.item_category = self.get_item_category(item["parent_id"])
                self.repeating_section_title = self.get_repeating_section_title(
                    item["parent_id"], 0
                )
            else:
                self.item_category = EMPTY_RESPONSE
                self.repeating_section_title = EMPTY_RESPONSE
            row_array = self.item_properties_as_list(item) + self.common_audit_data()
            if get_json_property(item, INACTIVE) and not self.export_inactive_items:
                continue
            self.audit_table.append(row_array)
        return self.audit_table

    def append_converted_audit_to_bulk_export_file(self, output_csv_path):
        """
        Appends audit data table to bulk export file at output_csv_path
        :param output_csv_path: The full path to the file to save
        """
        if (
            not os.path.isfile(output_csv_path)
            and self.audit_table[0] != CSV_HEADER_ROW
        ):
            self.audit_table.insert(0, CSV_HEADER_ROW)
        self.write_file(output_csv_path, "ab")

    def save_converted_audit_to_file(self, output_csv_path, allow_overwrite):
        """
        Saves audit data table to a file at output_csv_path
        :param output_csv_path:     The full path to the file to save
        :param allow_overwrite:     if True, allow function to overwrite existing file
        """
        file_exists = os.path.isfile(output_csv_path)
        if file_exists and not allow_overwrite:
            sys.exit(
                "File already exists at "
                + output_csv_path
                + "\nPlease set allow_overwrite to True in config.yaml file. See README.md for further instruction"
            )
        elif file_exists and allow_overwrite:
            print("Overwriting file at " + output_csv_path)
        elif self.audit_table[0] != CSV_HEADER_ROW:
            self.audit_table.insert(0, CSV_HEADER_ROW)
        self.write_file(output_csv_path, "wb")

    def write_file(self, output_csv_path, mode):
        """
        Saves audit data table to a file at 'path'
        :param output_csv_path: the full path to file to save
        :param mode:    write ('wb') or append ('ab') mode
        """
        try:
            csv_file = open(output_csv_path, mode)
            wr = csv.writer(csv_file, dialect="excel", quoting=csv.QUOTE_ALL)
            wr.writerows(self.audit_table)
            csv_file.close()
        except Exception as ex:
            print(str(ex) + ": Error saving audit_table to " + output_csv_path)

    def get_item_response(self, item):
        """
        Return item response value
        :param item:    single item in JSON format
        :return:        response property
        """
        response = EMPTY_RESPONSE
        item_type = get_json_property(item, TYPE)
        if item_type == "question":
            response = get_json_property(item, RESPONSES, "selected", 0, LABEL)
        elif item_type == "list":
            for single_response in get_json_property(item, RESPONSES, "selected"):
                if single_response:
                    response += get_json_property(single_response, LABEL) + "\n"
            response = response[:-1]
        elif item_type == "address":
            response = get_json_property(item, RESPONSES, "location_text")
        elif item_type == "checkbox":
            response = bool(get_json_property(item, RESPONSES, "value"))
        elif item_type == "switch":
            response = get_json_property(item, RESPONSES, "value")
        elif item_type == "slider":
            response = get_json_property(item, RESPONSES, "value")
        elif item_type == "drawing":
            response = get_json_property(item, RESPONSES, "image", "media_id")
        elif item_type == MEDIA:
            for image in get_json_property(item, MEDIA):
                response += "\n" + get_json_property(image, "media_id")
            if response:
                response = response[1:]
        elif item_type == SIGNATURE:
            response = get_json_property(item, RESPONSES, "name")
        elif item_type == "smartfield":
            response = get_json_property(item, "evaluation")
        elif item_type == "datetime":
            response = self.format_date_time(
                get_json_property(item, RESPONSES, "datetime")
            )
        elif item_type == "text" or item_type == "textsingle":
            response = get_json_property(item, RESPONSES, "text")
        elif (
            item_type == INFORMATION
            and get_json_property(item, "options", TYPE) == "link"
        ):
            response = get_json_property(item, "options", "link")
        elif item_type == "temperature":
            response = get_json_property(item, RESPONSES, "temperature")
        elif item_type in [
            "dynamicfield",
            "element",
            "primeelement",
            "asset",
            "scanner",
            "category",
            "section",
            INFORMATION,
        ]:
            pass
        else:
            print(
                "Unhandled item type: "
                + str(item_type)
                + " from "
                + self.audit_id()
                + ", "
                + item.get(ID)
            )
        return response

    @staticmethod
    def get_item_response_id(item):
        """
        :param item:    single item in JSON format
        :return:        response ID property
        """
        response_id = EMPTY_RESPONSE
        item_type = get_json_property(item, TYPE)
        if item_type == "question":
            response_id = get_json_property(item, RESPONSES, "selected", 0, "id")
        elif item_type == "list":
            for single_response in get_json_property(item, RESPONSES, "selected"):
                if single_response:
                    response_id += get_json_property(single_response, "id") + "\n"
            response_id = response_id[:-1]
        return response_id

    @staticmethod
    def get_item_score(item):
        """
        retrieve score property from item
        :param item:    single item in JSON format
        :return:        score property or empty string if property does not exist
        """
        if isinstance(get_json_property(item, "scoring", SCORE), int):
            return get_json_property(item, "scoring", SCORE)
        elif isinstance(get_json_property(item, "scoring", COMBINED_SCORE), int):
            return get_json_property(item, "scoring", COMBINED_SCORE)
        else:
            return EMPTY_RESPONSE

    @staticmethod
    def get_item_max_score(item):
        """
        retrieve max score property from item
        :param item:    single item in JSON format
        :return:        max score property or empty string if property does not exist
        """
        if isinstance(get_json_property(item, "scoring", MAX_SCORE), int):
            return get_json_property(item, "scoring", MAX_SCORE)
        elif isinstance(get_json_property(item, "scoring", COMBINED_MAX_SCORE), int):
            return get_json_property(item, "scoring", COMBINED_MAX_SCORE)
        else:
            return EMPTY_RESPONSE

    @staticmethod
    def get_item_score_percentage(item):
        """
        retrieve score percentage property from item
        :param item:    single item in JSON format
        :return:        score percentage property or empty string if property does not exist
        """
        if isinstance(get_json_property(item, "scoring", SCORE_PERCENTAGE), int):
            return get_json_property(item, "scoring", SCORE_PERCENTAGE)
        elif isinstance(
            get_json_property(item, "scoring", COMBINED_SCORE_PERCENTAGE), int
        ):
            return get_json_property(item, "scoring", COMBINED_SCORE_PERCENTAGE)
        else:
            return EMPTY_RESPONSE

    def get_item_label(self, item):
        """
        retrieve item label property
        :param item:    single item in JSON format
        :return:        label property
        """
        label = EMPTY_RESPONSE
        item_type = get_json_property(item, TYPE)
        if item_type == "smartfield":
            custom_response_id_to_label_map = (
                self.audit_custom_response_id_to_label_map()
            )
            conditional_id = get_json_property(item, "options", "condition")
            if conditional_id:
                label = (
                    copy.deepcopy(
                        smartfield_conditional_id_to_statement_map.get(conditional_id)
                    )
                    or EMPTY_RESPONSE
                )
            for value in get_json_property(item, "options", "values"):
                label += "|"
                if value in standard_response_id_map.keys():
                    label += standard_response_id_map[value]
                elif value in custom_response_id_to_label_map.keys():
                    label += custom_response_id_to_label_map[value]
                else:
                    label += str(value)
                label += "|"
            return label
        else:
            return get_json_property(item, LABEL)

    @staticmethod
    def get_item_type(item):
        """
        :param item:    single item in JSON format
        :return:        item type property
        """
        item_type = get_json_property(item, TYPE)
        if item_type == INFORMATION:
            item_type += " - " + get_json_property(item, "options", TYPE)
        return item_type

    @staticmethod
    def get_item_media(item):
        """
        :param item:    single item in JSON format
        :return:        item media href links
        """
        item_type = get_json_property(item, TYPE)
        if (
            item_type == INFORMATION
            and get_json_property(item, "options", TYPE) == MEDIA
        ):
            media_href = "{}.{}".format(
                get_json_property(item, "options", MEDIA, MEDIAID),
                get_json_property(item, "options", MEDIA, EXT),
            )
        elif item_type in ["drawing", SIGNATURE]:
            media_href = "{}.{}".format(
                get_json_property(item, RESPONSES, "image", MEDIAID),
                get_json_property(item, RESPONSES, "image", EXT),
            )
        else:
            media_list = []
            for image in get_json_property(item, MEDIA):
                if EXT in image.keys():
                    if image[EXT] is not None:
                        media_list.append(image[MEDIAID] + "." + image[EXT])
                else:
                    media_list.append(image[MEDIAID] + "." + "jpg")
            media_href = "\n".join(media_list)
            # media_href = '\n'.join(image[MEDIAID]+'.'+image[EXT] for image in get_json_property(item, MEDIA))
        if media_href == ".":
            media_href = None
        return media_href

    @staticmethod
    def get_item_location_coordinates(item):
        """
        :param item:    single item in JSON format
        :return:        comma separated longitude and latitude coordinates
        """
        item_type = get_json_property(item, TYPE)
        if item_type == "address":
            location_coordinates = get_json_property(
                item, "responses", "location", "geometry", "coordinates"
            )
            if isinstance(location_coordinates, list) and len(location_coordinates):
                return str(location_coordinates).strip("[]").split(",")
        return [EMPTY_RESPONSE, EMPTY_RESPONSE]

    def item_properties_as_list(self, item):
        """
        Returns selected properties of the audit item JSON as a list
        :param item:    single item in JSON format
        :return:        array of item data, in format that CSV writer can handle
        """
        location_coordinates = self.get_item_location_coordinates(item)
        latitude = location_coordinates[1]
        longitude = location_coordinates[0]
        return [
            "",
            self.get_item_type(item),
            self.get_item_label(item),
            self.get_item_response(item),
            get_json_property(item, RESPONSES, "text")
            if item.get(TYPE) not in ["text", "textsingle"]
            else EMPTY_RESPONSE,
            self.get_item_media(item),
            latitude,
            longitude,
            self.get_item_score(item),
            self.get_item_max_score(item),
            self.get_item_score_percentage(item),
            get_json_property(item, "options", "is_mandatory") or False,
            get_json_property(item, RESPONSES, FAILED) or False,
            get_json_property(item, INACTIVE) or False,
            get_json_property(item, ID),
            self.get_item_response_id(item),
            get_json_property(item, PARENT_ID),
        ]


def main():
    """
    saves JSON file as CSV. Path to JSON file provided as command line argument
    """
    for arg in sys.argv[1:]:
        audit_json = json.load(open(arg, "r"))
        csv_exporter = CsvExporter(audit_json)
        csv_exporter.save_converted_audit_to_file(
            os.path.splitext(arg.split("/")[-1])[0] + ".csv", allow_overwrite=True
        )
    print("Exiting")


if __name__ == "__main__":
    main()
