//  
//   Rebex Sample Code License
// 
//   Copyright 2025, REBEX CR s.r.o.
//   All rights reserved.
//   https://www.rebex.net/
// 
//   Permission to use, copy, modify, and/or distribute this software for any
//   purpose with or without fee is hereby granted.
// 
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//   OTHER DEALINGS IN THE SOFTWARE.
// 

using System;

using Rebex.Net;
using Rebex.TerminalEmulation;

namespace Rebex.Samples
{
    /// <summary>
    /// The SimpleShell class provides a very simple shell:
    ///  - read the command from the user input 
    ///  - send the command to the remote host 
    ///  - read the response from the remote host
    ///  - write the response to the console
    /// </summary>
    public class SimpleShell
    {
        /// <summary>
        /// Class that stores input program arguments.
        /// </summary>
        private class ProgramArguments
        {
            /// <summary>
            /// Gets or sets the host name.
            /// </summary>
            public string HostName
            {
                get { return _hostName; }
                set { _hostName = value; }
            }
            private string _hostName;

            /// <summary>
            /// Gets or sets the login name.
            /// </summary>
            public string LoginName
            {
                get { return _loginName; }
                set { _loginName = value; }
            }
            private string _loginName;

            /// <summary>
            /// Gets or sets the password.
            /// </summary>
            public string Password
            {
                get { return _Password; }
                set { _Password = value; }
            }
            private string _Password;
        }

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        /// <param name="args">Program arguments.</param>
        /// <returns>Exit code.</returns>
        public static int Main(string[] args)
        {
            // set the trial license key
            Rebex.Licensing.Key = Rebex.Samples.TrialKey.Key;


            // show program header
            ShowHeader();

            // if no arguments was specified, show syntax and examples also
            if (args.Length == 0)
            {
                ShowHelp();
            }

            // get program arguments
            ProgramArguments arguments = GetProgramArguments(args);

            // create an Ssh object
            Ssh ssh = new Ssh();

            try
            {
                // connect to the host
                ssh.Connect(arguments.HostName);

                // login
                ssh.Login(arguments.LoginName, arguments.Password);

                // start scripting
                Scripting scripting = ssh.StartScripting();

                // --------------------------------------------------------
                // A proper value of Scripting.Timeout property depends on the nature of
                // the command you invoke.
                // If the response of the command is being sent continuously,
                // the timeout can be small (for example commands like 'ls -R /').
                // If the response of the command is sent rarely or only at the end of the command,
                // bigger timeout should be used (for example commands like 'ls -R / > list.txt').
                // --------------------------------------------------------

                // decrease the response timeout to 20 seconds (default is 60)
                scripting.Timeout = 20000;

                // detect prompt automatically
                scripting.DetectPrompt();

                // main loop
                ScriptMatch result;
                do
                {
                    // output a prompt to a console
                    Console.Write("Enter shell command: ");

                    // read the command from a console
                    string command = Console.ReadLine();

                    // send the command to the server
                    scripting.SendCommand(command);

                    // --------------------------------------------------------
                    // There are several ways to read command response.
                    // Please check out http://www.rebex.net/terminal-emulation.net/features/scripting.aspx for more information.
                    // --------------------------------------------------------

                    // read the response line by line
                    do
                    {
                        // read until a line is received (or prompt, or the connection is closed)
                        string line = scripting.ReadUntil(ScriptEvent.Line, ScriptEvent.Prompt, ScriptEvent.Closed);

                        // get the result of the ReadUntil method
                        result = scripting.LastResult;

                        // display the line
                        Console.WriteLine(line);

                    } while (result.IsLine);

                } while (!result.IsClosed);
            }
            catch (Exception e)
            {
                Console.WriteLine("\nException occured: {0}", e);
                return 1;
            }
            finally
            {
                // disconnect from the server
                if( ssh != null)
                    ssh.Disconnect();
            }

            return 0;
        }

        private static void ShowHeader()
        {
            Console.WriteLine("----------------------------------------------------------");
            Console.WriteLine("Rebex Simple Shell - executes commands on the remote host.");
            Console.WriteLine("----------------------------------------------------------");
            Console.WriteLine("Note: Don't start commands that require user interaction.");
            Console.WriteLine();
        }

        private static void ShowHelp()
        {
            Console.WriteLine("Syntax: SimpleShell [host [login [password]]]");
            Console.WriteLine();
            Console.WriteLine("Example: SimpleShell sample.host.com test test123");
            Console.WriteLine("Example: SimpleShell sample.host.com test");
            Console.WriteLine("Example: SimpleShell sample.host.com");
            Console.WriteLine("Example: SimpleShell");
            Console.WriteLine();
        }

        /// <summary>
        /// Initialize the ProgramArguments class by the given arguments.
        /// If any argument is missing the user is prompted.
        /// </summary>
        /// <param name="args">Command line arguments.</param>
        /// <returns>Initialized ProgramArguments class.</returns>
        private static ProgramArguments GetProgramArguments(string[] args)
        {
            ProgramArguments arguments = new ProgramArguments();

            if (args.Length > 0)
            {
                arguments.HostName = args[0];
            }
            else
            {
                Console.Write("host: ");
                arguments.HostName = Console.ReadLine();
            }

            if (args.Length > 1)
            {
                arguments.LoginName = args[1];
            }
            else
            {
                Console.Write("login: ");
                arguments.LoginName = Console.ReadLine();
            }

            if (args.Length > 2)
            {
                arguments.Password = args[2];
            }
            else
            {
                Console.Write("password: ");
                arguments.Password = Console.ReadLine();
            }

            return arguments;
        }
    }
}
