#!/usr/bin/env python

# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.


"""CLI tool for data load from json string or file with set of json strings.

Usage for strings:
    bin/data-load -t (or --table) <table_name> -s (or --string) <json_string>
    or
    echo <string> | bin/data-load -t (or --table) <table_name>

Usage for files:
    bin/data-load -t (or --table) <table_name> -f (or --file) <file_path>
    or
    cat <file_path> | bin/data-load -t (or --table) <table_name>

For help:
    bin/data-load -h (or --help)

"""

from gevent import monkey
monkey.patch_all()

import argparse
import json
import sys

from magnetodb.storage import models
from magnetodb.storage.impl import cassandra_impl

TYPE_DICT = {'N': models.ATTRIBUTE_TYPE_NUMBER,
             'S': models.ATTRIBUTE_TYPE_STRING,
             'B': models.ATTRIBUTE_TYPE_BLOB,
             'NS': models.ATTRIBUTE_TYPE_NUMBER_SET,
             'SS': models.ATTRIBUTE_TYPE_STRING_SET,
             'BS': models.ATTRIBUTE_TYPE_BLOB_SET}


class NameSpace(object):
    """Custom Namespace object for parser. """
    pass


def context():
    """Custom context object. """
    pass


def put_item(storage_impl, table, py_obj):
    """CassandraStorageImpl put_item method wrapper. """
    put = {}

    for k, v in py_obj.items():
        put[k] = models.AttributeValue(TYPE_DICT[v.keys()[0]], v.values()[0])

    put_request = models.PutItemRequest(table, put)
    storage_impl.put_item(context, put_request)


def string_loader(storage_impl, table, input_string):
    """Load data from specified string. """
    py_obj = json.loads(input_string)
    put_item(storage_impl, table, py_obj)


def sequence_loader(storage_impl, table, sequence):
    """Load data from specified text file.

    :param table: Table name
    :param sequence: string sequence (collection of strings). It can be already
    opened python file object (or another object, supported iteration protocol,
    for example list) with input json data

    """
    line_counter = 0
    for item in sequence:
        line_counter += 1
        try:
            string_loader(storage_impl, table, item)
        except ValueError as e:
            print ('Error in json input. Line %s was not processed. '
                   'Please fix and try again. %s' % (line_counter, e))


def main():
    namespace = NameSpace()

    parser = argparse.ArgumentParser(description='CLI tool for data load')

    parser.add_argument('-t', '--table', type=str, dest='table_name',
                        help='Name of the table in format: tenant.table')
    parser.add_argument('-f', '--file', type=file, dest='input_file',
                        help='File with imported data')
    parser.add_argument('-s', '--string', type=str, dest='input_string',
                        help='String with imported data')

    parser.parse_args(namespace=namespace)

    if not namespace.table_name:
        print ("You have not specified table name. Use '-t' or '--table' "
               "<table_name>")
        return

    try:
        context.tenant, table = namespace.table_name.split('.')
    except ValueError:
        print 'Bad table name. Use format: <tenant_name>.<table_name>'
        return

    storage_impl = cassandra_impl.CassandraStorageImpl(cql_version="3.1.5")

    #Checking for stdin
    if not sys.stdin.isatty():
        lines = sys.stdin.readlines()
        sequence_loader(storage_impl, table, lines)
        return

    if namespace.input_file:
        sequence_loader(storage_impl, table, namespace.input_file)
    elif namespace.input_string:
        string_loader(storage_impl, table, namespace.input_string)
    else:
        print ("You have not specified any input data. Use '-h' or '--help' "
               "keys for script using info")
        return


if __name__ == '__main__':
    main()
