#!/usr/bin/env python

# Copyright 2014 Mirantis Inc.
# Copyright 2014 Symantec Corporation
# 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)

"""
import Queue
from threading import Event

from gevent import monkey
monkey.patch_all()

from magnetodb.common import setup_global_env
from oslo.config.cfg import Opt

import json as json
import sys

from magnetodb.api.openstack.v1.parser import Parser

from magnetodb.storage import models
from magnetodb import storage
from magnetodb.common.config import CONF


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


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


def parse_put_item(table, item_json):
    """CassandraStorageImpl put_item method wrapper. """
    py_obj = json.loads(item_json)
    return models.PutItemRequest(
        table, Parser.parse_item_attributes(py_obj)
    )


def string_loader(storage_impl, table, input_string):
    """Load data from specified string. """

    storage_impl.put_item(context, parse_put_item(table, input_string))


def sequence_loader(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

    """
    count_sent = 0

    future_ready_event = Event()
    future_ready_queue = Queue.Queue
    count_done = [0]

    for item in sequence:
        future = storage.put_item_async(context, parse_put_item(table, item))
        count_sent += 1

        def callback(future):
            count_done[0] += 1
            future_ready_queue.put_nowait(future)
            future_ready_event.set()

        future.add_done_callback(callback)
        try:
            while True:
                finished_future = future_ready_queue.get_nowait()
                finished_future.result()
        except Queue.Empty:
            pass

        if count_sent % 1000 == 0:
            print "sent: {}, done: {}".format(count_sent, count_done[0])

    while count_done[0] < count_sent:
        future_ready_event.wait()
        future_ready_event.clear()
    print "sent: {}, done: {}".format(count_sent, count_done[0])


def main():
    CONF.register_cli_opt(
        Opt(
            name="table", short="t", type=str, dest='table_name',
            required=True, help='Name of the table in format: tenant.table'
        )
    )
    CONF.register_cli_opt(
        Opt(
            name="file", short="f", type=file, dest='input_file',
            help='File with imported data'
        )
    )
    CONF.register_cli_opt(
        Opt(
            name="string", short="s", type=str, dest='input_string',
            help='String with imported data'
        )
    )

    setup_global_env(args=sys.argv[1:])

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

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

    if CONF.input_file:
        sequence_loader(table, CONF.input_file)
    elif CONF.input_string:
        string_loader(table, CONF.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()
