Documentation
// Copyright 2018 MaidSafe.net limited.
//
// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. Please review the Licences for the specific language governing
// permissions and limitations relating to use of the SAFE Network Software.

//! Self-authentication example.

// For explanation of lint checks, run `rustc -W help` or see
// https://github.com/maidsafe/QA/blob/master/Documentation/Rust%20Lint%20Checks.md
#![forbid(
    exceeding_bitshifts, mutable_transmutes, no_mangle_const_items, unknown_crate_types, warnings
)]
#![deny(
    bad_style, deprecated, improper_ctypes, missing_docs, non_shorthand_field_patterns,
    overflowing_literals, plugin_as_library, private_no_mangle_fns, private_no_mangle_statics,
    stable_features, unconditional_recursion, unknown_lints, unsafe_code, unused, unused_allocation,
    unused_attributes, unused_comparisons, unused_features, unused_parens, while_true
)]
#![warn(
    trivial_casts, trivial_numeric_casts, unused_extern_crates, unused_import_braces,
    unused_qualifications, unused_results
)]
#![allow(
    box_pointers, missing_copy_implementations, missing_debug_implementations,
    variant_size_differences
)]
#![cfg_attr(
    feature = "cargo-clippy",
    deny(clippy, unicode_not_nfc, wrong_pub_self_convention, option_unwrap_used)
)]
#![cfg_attr(feature = "cargo-clippy", allow(implicit_hasher, too_many_arguments, use_debug))]

extern crate clap;
extern crate maidsafe_utilities;
extern crate safe_app;
extern crate safe_authenticator;
#[macro_use]
extern crate unwrap;

use clap::{App, Arg};
use safe_app::{utils, ClientError, CoreError};
use safe_authenticator::{AuthError, Authenticator};

fn main() {
    unwrap!(maidsafe_utilities::log::init(true));

    let matches = App::new("self_authentication")
        .arg(
            Arg::with_name("invite")
                .long("invite")
                .takes_value(true)
                .help("Use the given invite."),
        )
        .get_matches();

    let mut secret_0 = String::new();
    let mut secret_1 = String::new();

    println!("\nDo you already have an account created (enter Y for yes)?");

    let mut user_option = String::new();
    let _ = std::io::stdin().read_line(&mut user_option);
    user_option = user_option.trim().to_string();

    if user_option != "Y" && user_option != "y" {
        println!("\n\tAccount Creation");
        println!("\t================");

        println!("\n------------ Enter account-locator ---------------");
        let _ = std::io::stdin().read_line(&mut secret_0);
        secret_0 = secret_0.trim().to_string();

        println!("\n------------ Enter password ---------------");
        let _ = std::io::stdin().read_line(&mut secret_1);
        secret_1 = secret_1.trim().to_string();

        let invitation: String = if let Some(i) = matches.value_of("invite") {
            i.to_string()
        } else {
            unwrap!(utils::generate_random_string(10))
        };

        // Account Creation
        println!("\nTrying to create an account...");

        match Authenticator::create_acc(
            secret_0.as_str(),
            secret_1.as_str(),
            invitation.as_str(),
            || (),
        ) {
            Ok(_) => (),
            Err(AuthError::CoreError(CoreError::RoutingClientError(
                ClientError::AccountExists,
            ))) => {
                println!(
                    "ERROR: This domain is already taken. Please retry with different \
                     locator and/or password"
                );
                return;
            }
            Err(err) => panic!("{:?}", err),
        }
        println!("Account created successfully!");

        println!("\n\n\tAuto Account Login");
        println!("\t==================");

        // Log into the created account.
        {
            println!("\nTrying to log into the created account using supplied credentials...");

            let _ = unwrap!(Authenticator::login(secret_0, secret_1, || ()));
            println!("Account login successful!");
        }
    }

    println!("\n\n\tManual Account Login");
    println!("\t====================");

    loop {
        secret_0 = String::new();
        secret_1 = String::new();

        println!("\n------------ Enter account-locator ---------------");
        let _ = std::io::stdin().read_line(&mut secret_0);
        secret_0 = secret_0.trim().to_string();

        println!("\n------------ Enter password ---------------");
        let _ = std::io::stdin().read_line(&mut secret_1);
        secret_1 = secret_1.trim().to_string();

        // Log into the created account.
        {
            println!("\nTrying to log in...");
            match Authenticator::login(secret_0, secret_1, || ()) {
                Ok(_) => {
                    println!("Account login successful!");
                    break;
                }
                Err(error) => println!("ERROR: Account login failed!\nReason: {:?}\n\n", error),
            }
        }
    }
}