#!/usr/bin/env python

import os
import sys
import traceback
import atexit

import readline
from sql4json.utils import split_on_any

from sql4json.sql4json import Sql4Json
from sql4json.flat_data import FlatData


def hack_remove_garbage_printed_by_readline(stdin_data):
    readline_garbage_data = ''.join((chr(0x1b), '[', '?', '1', '0', '3', '4', 'h'))

    if stdin_data.startswith(readline_garbage_data):
        stdin_data = stdin_data[len(readline_garbage_data):]

    return stdin_data


def readjson_from_stdin_and_reinit_stdin():
    stdin_data = sys.stdin.read()
    stdin_data = stdin_data.strip()
    stdin_data = hack_remove_garbage_printed_by_readline(stdin_data)

    try:
        if sys.platform == 'win32':
            sys.stdin = open("CON:", "r")
        else:
            sys.stdin = open('/dev/tty', 'r')
    except:
        raise Exception('Unable to read from stdin')

    return stdin_data


def set_history_file():
    histfile = os.path.join(os.path.expanduser("~"), ".sql4json")

    try:
        readline.read_history_file(histfile)
    except IOError:
        pass

    atexit.register(readline.write_history_file, histfile)
    del histfile


def print_error(error_str='', include_newline=True):
    output_str = '\033[91m' + error_str + '\x1B[m'
    print_info(output_str)


def print_info(info_str='', include_newline=True):
    if include_newline:
        print >> sys.stderr, (info_str)
    else:
        sys.stderr.write(info_str)


def print_csv_row(row):
    column_values = []

    for item in row:
        if item is None:
            column_values.append('')
        else:
            str_val = unicode(item)
            column_values.append(str_val.replace(',', '%2C'))

    print ','.join(column_values)


def print_usage():
    print_info('\r\nusage: sql4json options [SQL*]')
    print_info(
        '''\r\n* If SQL is not specified on the command line, an interactive session will begin where
        you will be prompted to provide SQL queries. Multiple queries can be run on the same data
        set until "quit" or "exit" is enterred''')

    print_info('\r\noptions:')
    print_info('\t--help             - Prints this help message')
    print_info('\t--csv              - Flattens data and outputs it as a csv')
    print_info(
        '\t--csv-with-headers - Flattens data and outputs it as a csv with the first row being the column headers')

    print_info('\r\nexamples:')

    print_info('\r\n\tRun SQL query on data from file')
    print_info('\t\tsql4json "SELECT id, name FROM some/path WHERE condition == true" <input_file.json')
    print_info('\t\tcat input_file.json|sql4json "SELECT id, name FROM some/path WHERE condition == true"')

    print_info('\r\n\tRun SQL query on data from command line')
    print_info(
        '\t\techo \'[{"id":1,"name":"test"},{"id":2,"name":"other"}]\'sql4json "SELECT id, name FROM some/path WHERE id==1"')

    print_info('\r\n\tInteractive session with data from the web')
    print_info('\t\tcurl "http://api.opencongress.org/people.json?first_name=Chris"|sql4json')
    print_info()


SUPPORTED_OPTIONS = ('help', 'csv', 'csv-with-headers')
SUPPORTED_OPTION_SET = frozenset(SUPPORTED_OPTIONS)


def parse_command_line():
    option_args = set()
    sql_arg = None

    for i in range(1, len(sys.argv)):
        arg = sys.argv[i]

        if arg.startswith('--'):
            option_string = arg[2:].lower()

            if option_string not in SUPPORTED_OPTION_SET:
                print_error("Unknown option %s" % arg)
                exit(1)
            else:
                option_args.add(option_string)

        elif sql_arg is None:
            sql_arg = arg
        else:
            print_error("Unexpected paramater %s" % arg)

    return option_args, sql_arg


def run_single_query(option_args, sql_str):
    try:
        json_str = readjson_from_stdin_and_reinit_stdin().strip()
        query = Sql4Json(json_str, sql_str)

        if 'csv' in option_args or 'csv-with-headers' in option_args:
            sql_statement = query.query_engine.get_sql_statement()
            select_section = sql_statement.get_select_section()
            select_items = split_on_any(select_section, frozenset((',', ' ', '\t', '\n', '\r')))

            flat_data = FlatData(query.get_results(), select_items if '*' not in select_items else None)

            if 'csv-with-headers' in option_args:
                print_csv_row(flat_data.get_headers())

            rows = flat_data.get_rows()

            for row in rows:
                print_csv_row(row)
        else:
            print str(query)

    except Exception, e:
        traceback.print_exc()
        print_error(str(e))
        exit(1)


def run_interactive_session(options):
    json_str = readjson_from_stdin_and_reinit_stdin().strip()
    set_history_file()

    while True:
        try:
            input_str = raw_input('\r\nsql4json2>').strip()
            in_lower = input_str.lower()

            if in_lower == 'exit' or in_lower == 'quit':
                return
            else:
                query = Sql4Json(json_str, input_str)
                print str(query)

        except Exception, e:
            #traceback.print_exc()
            print_error(str(e))


options, sql = parse_command_line()

if 'help' in options:
    print_usage()
elif sql is not None:
    run_single_query(options, sql)
else:
    run_interactive_session(options)

print_info()
