#!/usr/bin/env python3
# Copyright (c) 2016 Arista Networks, Inc.  All rights reserved.
# Arista Networks, Inc. Confidential and Proprietary.

import argparse
import readline
import socket
import sys
import os

from EapiClientLib import EapiClient
from EapiClientLib import EapiException

AUTO_COMPLETE_CACHE = {}
eapiClient = EapiClient( disableAaa=True )

def complete( text, state ):
   result = autoComplete( text )
   sortResultList = sorted( result.keys() )
   if state > len( result ):
      return None
   if readline.get_completion_type() == ord( '?' ):
      # pylint: disable-next=consider-using-f-string
      return '{:<30} {:}'.format( sortResultList[ state ],
                                result[ sortResultList[ state ] ] )
   else:
      return ( ' '.join( text.split( ' ' )[ : -1 ] + [ sortResultList[ state ] ] ) +
               ' ' )

def showOnlineHelp( subst, matches, longest_match ):
   print()
   for match in matches:
      print( match )
   print( f'{socket.gethostname()}#{readline.get_line_buffer()}', end=' ' )

def autoComplete( command ):
   if command in AUTO_COMPLETE_CACHE:
      return AUTO_COMPLETE_CACHE[ command ]
   try:
      result = eapiClient.getCommandHelp( command )[ 'result' ]
      AUTO_COMPLETE_CACHE[ command ] = result
      return result
   except EapiException:
      return {}
   except KeyboardInterrupt:
      return {}

def printCommands( commands ):
   # strip out any empty lines
   commands = [ cmd.strip() for cmd in commands if cmd.strip() and cmd[ 0 ] != '!' ]
   if not commands:
      return

   try:
      results = eapiClient.runCmds( version="latest",
                                   cmds=commands, format='text',
                                   autoComplete=True )
      for result in results[ 'result' ]:
         print( result[ 'output' ] )
   except EapiException as e:
      if e.data:
         print( e.data[ -1 ][ 'output' ] )
      else:
         print( str( e ) )
   except KeyboardInterrupt:
      return
   except EOFError:
      print()
      sys.exit( 0 )


def printCommand( command ):
   command = command.strip()
   if not command:
      return

   if command[ -1 ]  == '?':
      print( "\n".join( autoComplete( command[ : -1 ] ) ) )
      return

   # pylint: disable-next=consider-using-in
   if command == "exit" or command == "exi" or command == "ex":
      print()
      sys.exit( 0 )

   printCommands( [ command ] )

def main( command ):
   if command:
      commands = command.split( '\n' )
      if len( commands ) > 1:
         printCommands( commands )
      else:
         printCommand( command )
      return

   if not os.isatty( sys.stdout.fileno() ):
      printCommands( sys.stdin.readlines() )
      return

   while True:
      # print our fake prompt
      try:
         # pylint: disable-next=consider-using-f-string
         command = input( '%s#' % socket.gethostname() ).rstrip()
      except KeyboardInterrupt:
         print()
      except EOFError:
         print()
         return

      if not command:
         # They entered a new line or just whitespace: no-op
         continue

      printCommand( command )

if __name__ == '__main__':
   parser = argparse.ArgumentParser()
   parser.add_argument( '-c', '--command', action='store',
                        help='run COMMAND non-interactively. '
                             'Use \'\\n\' for multiple commands.' )
   parser.add_argument( "-s", "--sysname", action="store",
                        default=os.environ.get( "SYSNAME","ar" ),
                        # pylint: disable-next=consider-using-f-string
                        help="system name (default: %s)" %
                              os.environ.get( "SYSNAME", "ar" ) )
   options = parser.parse_args()
   readline.set_completer_delims( '\n' )
   readline.parse_and_bind( 'tab: complete' )
   readline.parse_and_bind( '?: possible-completions' ) # same as tab-tab
   readline.set_completer( complete )
   readline.set_completion_display_matches_hook( showOnlineHelp )
   main( options.command )
