/**
 * 8. String to Integer (atoi)
 * https://leetcode.com/problems/string-to-integer-atoi/
 * Implement atoi which converts a string to an integer.
 *
 * The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.
 *
 * The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.
 *
 * If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.
 *
 * If no valid conversion could be performed, a zero value is returned.
 *
 * Note:
 *
 * Only the space character ' ' is considered as whitespace character.
 * Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231,  231 − 1]. If the numerical value is out of the range of representable values, INT_MAX (231 − 1) or INT_MIN (−231) is returned.
 * Example 1:
 *
 * Input: "42"
 * Output: 42
 * Example 2:
 *
 * Input: "   -42"
 * Output: -42
 * Explanation: The first non-whitespace character is '-', which is the minus sign.
 *              Then take as many numerical digits as possible, which gets 42.
 * Example 3:
 *
 * Input: "4193 with words"
 * Output: 4193
 * Explanation: Conversion stops at digit '3' as the next character is not a numerical digit.
 * Example 4:
 *
 * Input: "words and 987"
 * Output: 0
 * Explanation: The first non-whitespace character is 'w', which is not a numerical
 *              digit or a +/- sign. Therefore no valid conversion could be performed.
 * Example 5:
 *
 * Input: "-91283472332"
 * Output: -2147483648
 * Explanation: The number "-91283472332" is out of the range of a 32-bit signed integer.
 *              Thefore INT_MIN (−231) is returned.
 */

fn my_atoi(s: String) -> i32 {
  let (mut temp, mut nums, mut is_negative) = (Some(0), vec![], false);

  // split context by space, get the first substring
  if let Some(num_str) = s.split_whitespace().next() {
    let mut not_zero = false;
    for (i, c) in num_str.char_indices() {
      if i == 0 && matches!(c, '+' | '-') {
        // check the first char
        if c == '-' {
          is_negative = true;
        }
      } else if let Some(n) = c.to_digit(10) {
        // check other chars
        if n > 0 || not_zero {
          nums.push(n as i32);
          not_zero = true;
        }
      } else {
        break;
      }
    }
  }

  for i in 0..nums.len() {
    let num = nums[nums.len() - i - 1];
    temp = {
      || {
        10_i32
          .checked_pow(i as u32)?
          .checked_mul(num)?
          .checked_add(temp?)
      }
    }();
  }

  temp
    .map(|v| if is_negative { 0 - v } else { v })
    .unwrap_or(if is_negative { i32::MIN } else { i32::MAX })
}

#[test]
fn q8_test() {
  assert_eq!(my_atoi("".into()), 0);
  assert_eq!(my_atoi(" 010  ".into()), 10);
  assert_eq!(my_atoi("  -0012a42".into()), -12);
  assert_eq!(my_atoi("   00000420000".into()), 420000);
  assert_eq!(my_atoi("  0000000000012345678".into()), 12345678);
  assert_eq!(my_atoi("3.14159".into()), 3);
  assert_eq!(my_atoi("      -42".into()), -42);
  assert_eq!(my_atoi("4193 with words".into()), 4193);
  assert_eq!(my_atoi("words and 987".into()), 0);
  assert_eq!(my_atoi("-91283472332".into()), -2147483648);
  assert_eq!(my_atoi("2147483648".into()), 2147483647);
}
