#!/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

import eventlet
eventlet.patcher.monkey_patch(all=True)

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

from magnetodb import context as req_context


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


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


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

    storage.put_item(tenant, table, parse_put_item(input_string))


def sequence_loader(tenant, 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(tenant, table, parse_put_item(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:])

    req_context.RequestContext()

    try:
        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(tenant, table, lines)
        return

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