#!/usr/bin/env python3

import csv
import os
import traceback
from shutil import copyfile
import json
import distutils.util
from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument("-f", "--file", dest="file",
                    help="PATH to a CSV file to modify inline.", metavar="PATH", required=True)
parser.add_argument("-hr", "--header-row", type=distutils.util.strtobool, dest="header_row",
                    help="BOOLEAN where 'true' means the CSV's first row is used for column names.", metavar="BOOLEAN", required=True)
parser.add_argument("-il", "--id-location", dest="id_index",
                    help="Zero-based INDEX where the ID column should be filled in.", metavar="INDEX")
parser.add_argument("-bl", "--boolean-convert-locations", nargs="+", dest="bool_convert_indices", metavar="INDEXLIST",
                    help="Zero-based, space-separated INDEXLIST where boolean strings should be used.")
parser.add_argument("-cm", "--column-map", dest="column_map",
                    help="JSON or path to a JSON file that contains a column name map of the format '{\"originalName\": \"newName\", ...}'. Requires --header-row=true.", metavar="JSON")

args = parser.parse_args()
file_name = args.file
id_index = int(args.id_index)
bool_convert_indices = [int(i) for i in args.bool_convert_indices]
header_row = args.header_row
column_map = args.column_map
columnMapObj = None
if header_row == True:
    if os.path.isfile(column_map):
        columnMapObj = json.load(open(column_map))
    else:
        columnMapObj = json.loads(column_map)


initial_read_file = open(file_name, "r+")
reader = csv.reader(initial_read_file)

backup_file_path = file_name + ".backup"
copyfile(file_name, backup_file_path)

os.remove(file_name)
open(file_name, "a").close()
try:
    initial_write_file = open(file_name, "r+")
    writer = csv.writer(initial_write_file)
    row_num = 0
    data = []
    for row in reader:
        if header_row == False or row_num > 0:
            field_index = 0
            for field in row:
                if field_index in bool_convert_indices:
                    bool_int = distutils.util.strtobool(str(row[field_index]))
                    row[field_index] = True if bool_int == 1 else False
                field_index += 1
            row[id_index] = row_num
            data += row
        elif header_row == True and row_num == 0:
            column_index = 0
            for column in row:
                try:
                    row[column_index] = columnMapObj[column]
                except:
                    pass
                column_index += 1
        writer.writerow(row)
        row_num += 1

    initial_read_file.close()
    initial_write_file.close()
    os.remove(backup_file_path)
except Exception:
    os.remove(file_name)
    os.rename(backup_file_path, file_name)
    print(traceback.format_exc())

#!/usr/bin/env python3

import csv
import os
import traceback
from shutil import copyfile
import json
import distutils.util
from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument("-f", "--file", dest="file",
                    help="PATH to a CSV file to modify inline.", metavar="PATH", required=True)
parser.add_argument("-hr", "--header-row", type=distutils.util.strtobool, dest="header_row",
                    help="BOOLEAN where 'true' means the CSV's first row is used for column names.", metavar="BOOLEAN", required=True)
parser.add_argument("-il", "--id-location", dest="id_index",
                    help="Zero-based INDEX where the ID column should be filled in.", metavar="INDEX")
parser.add_argument("-bl", "--boolean-convert-locations", nargs="+", dest="bool_convert_indices", metavar="INDEXLIST",
                    help="Zero-based, space-separated INDEXLIST where boolean strings should be used.")
parser.add_argument("-cm", "--column-map", dest="column_map",
                    help="JSON or path to a JSON file that contains a column name map of the format '{\"originalName\": \"newName\", ...}'. Requires --header-row=true.", metavar="JSON")

args = parser.parse_args()
file_name = args.file
id_index = int(args.id_index)
bool_convert_indices = [int(i) for i in args.bool_convert_indices]
header_row = args.header_row
column_map = args.column_map
columnMapObj = None
if header_row == True:
    if os.path.isfile(column_map):
        columnMapObj = json.load(open(column_map))
    else:
        columnMapObj = json.loads(column_map)


initial_read_file = open(file_name, "r+")
reader = csv.reader(initial_read_file)

backup_file_path = file_name + ".backup"
copyfile(file_name, backup_file_path)

os.remove(file_name)
open(file_name, "a").close()
try:
    initial_write_file = open(file_name, "r+")
    writer = csv.writer(initial_write_file)
    row_num = 0
    data = []
    for row in reader:
        if header_row == False or row_num > 0:
            field_index = 0
            for field in row:
                if field_index in bool_convert_indices:
                    bool_int = distutils.util.strtobool(str(row[field_index]))
                    row[field_index] = True if bool_int == 1 else False
                field_index += 1
            row[id_index] = row_num
            data += row
        elif header_row == True and row_num == 0:
            column_index = 0
            for column in row:
                try:
                    row[column_index] = columnMapObj[column]
                except:
                    pass
                column_index += 1
        writer.writerow(row)
        row_num += 1

    initial_read_file.close()
    initial_write_file.close()
    os.remove(backup_file_path)
except Exception:
    os.remove(file_name)
    os.rename(backup_file_path, file_name)
    print(traceback.format_exc())

#!/usr/bin/env python3