// Copyright 2019 California Institute of Technology.

// You should have received a copy of the licensing terms for this
// software included in the file “LICENSE” located in the top-level
// directory of this package. If you did not, you can view a copy at
// http://dcc.ligo.org/M1500244/LICENSE.txt

#include "completion.hh"

#include <cstdlib>
#include <deque>
#include <iostream>
#include <stdexcept>

static const char CHAN_LIST_ENV[] = "CHAN_LIST";

std::string
get_environment( const char* key )
{
    std::string result;
    const char* e = std::getenv( key );
    return result = ( e ? e : "" );
}

struct option_t
{
    option_t( )
        : db_path( "" ), key( "" ), search( true ), resort( false ),
          abort( false )
    {
    }
    std::string db_path;
    std::string key;
    bool        search;
    bool        resort;
    bool        abort;
};

void
show_help( const char* prog )
{
    std::cerr << "Usage " << prog << " -d <path to db> options\n";
    std::cerr << "Where option is one of:\n";
    std::cerr << "\t-h - this help.\n";
    std::cerr << "\t-d <path to db>- the path to the database to use. [A "
                 "required option]\n";
    std::cerr << "\t-r - sort the database, dump results to stdout.\n";
    std::cerr << "\t<search param> - search for the completion following the "
                 "given text.\n";
}

option_t
parse_options( int argc, char* argv[] )
{
    static const std::string opt_help( "-h" );
    static const std::string opt_sort( "-r" );
    static const std::string opt_db( "-d" );

    option_t opts;

    std::deque< std::string > args;
    auto                      next_opt = [&args]( ) -> std::string {
        if ( args.empty( ) )
        {
            throw std::runtime_error( "Expecting another argument" );
        }
        std::string results = args.front( );
        args.pop_front( );
        return results;
    };

    for ( int i = 1; i < argc; ++i )
    {
        args.emplace_back( argv[ i ] );
    }
    try
    {
        while ( !args.empty( ) )
        {
            std::string cur = next_opt( );

            if ( cur == opt_help )
            {
                show_help( argv[ 0 ] );
                opts.abort = true;
                break;
            }
            else if ( cur == opt_sort )
            {
                opts.resort = true;
                opts.search = false;
            }
            else if ( cur == opt_db )
            {
                opts.db_path = next_opt( );
            }
            else
            {
                opts.key = cur;
            }
        }
    }
    catch ( std::runtime_error& err )
    {
        opts.abort = true;
    }
    return opts;
}

int
main( int argc, char* argv[] )
{
    option_t opts = parse_options( argc, argv );
    if ( opts.abort )
    {
        exit( 1 );
    }
    completion::Database db = completion::load_database( opts.db_path );
    if ( opts.search )
    {
        completion::string_list choices;
        std::string             key = opts.key;
        std::string             prev_key;
        do
        {
            choices = completion::search(
                db.channels.begin( ), db.channels.end( ), key );
            prev_key = key;
            if ( !choices.empty( ) )
            {
                key = choices.front( );
            }
        } while ( choices.size( ) == 1 && prev_key != key );
        std::copy( choices.begin( ),
                   choices.end( ),
                   std::ostream_iterator< std::string >( std::cout, "\n" ) );
    }
    else if ( opts.resort )
    {
        completion::sort( db );
        std::copy(
            db.channels.begin( ),
            db.channels.end( ),
            std::ostream_iterator< completion::channel >( std::cout, "\n" ) );
    }
    return 0;
}