import time
import pandas as pd
import numpy as np

CITY_DATA = { 'chicago': 'chicago.csv',
              'new york city': 'new_york_city.csv',
              'washington': 'washington.csv' }

def get_filters():
    """
    Asks user to specify a city, month, and day to analyze.

    Returns:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    """
    print('Hello! Let\'s explore some US bikeshare data!')
    # get user input for city (chicago, new york city, washington). HINT: Use a while loop to handle invalid inputs
    while True:
        try:
            cities = ['chicago', 'new york city', 'washington']
            city = input("Would you like to see data for Chicago, New York, or Washington? Please enter: ").lower()
            if city == 'new york':
                city += ' city'
                break
            elif city in cities:
                break
            else:
                print('It seems the spelling of the city is not correct...Please re-enter the city name.')
        except:  # other error situations e.g. none stings being input; but not sure which type(s) of errors should be specified here 
            print('It seems like an invalid input...Please re-enter the city.')

    # get user input for month (all, january, february, ... , june)
    # get user input for day of week (all, monday, tuesday, ... sunday)
    months = ['january', 'february', 'march', 'april', 'may', 'june']
    days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
    while True:
        choice = input("Would you like to filter by month, day, both, or neither (no filter)? Please enter your choice: ").lower()
        if choice == 'month' or choice == 'by month':
            while True:
                month = input("Which month - January, February, March, April, May, or June? Please enter: ").lower()
                day = 'all'
                if month in months:
                    break
                else:
                    print('The input is not valid. Please input the correct month.')
            break
        elif choice == 'day' or choice == 'by day':
            while True:
                day = input("Which day - Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, or Sunday? Please enter: ").lower()
                month = 'all'
                if day in days:
                    break
                else:
                    print('The input is not valid. Please input the correct day name.')
            break
        elif choice == 'both' or choice == 'by both':
            while True:
                month = input("Which month - January, February, March, April, May, or June? Please enter: ").lower()
                day = input("Which day - Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, or Sunday? Please enter: ").lower()
                if (month in months) and (day in days):
                    break
                else:
                    print('It seems at least one of the inputs is not valid. Please input the correct month and/or day name.')
            break
        elif choice == 'neither' or choice == 'no filter':
            month = 'all'
            day = 'all'
            break
        else:
            print('The input is not valid. Please make sure the choice input is in correct format.')

    print('-'*40)
    return city, month, day


def load_data(city, month, day):
    """
    Loads data for the specified city and filters by month and day if applicable.

    Args:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    Returns:
        df - Pandas DataFrame containing city data filtered by month and day
    """
    months = ['january', 'february', 'march', 'april', 'may', 'june']
    days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
    df = pd.read_csv(CITY_DATA[city])
    df['Start Time'] = pd.to_datetime(df['Start Time']) # convert the Start Time column to datetime
    df['month'] = df['Start Time'].dt.month # extract month from start time to create a new column
    df['day_of_week'] = df['Start Time'].dt.day_name() # extract day from start time to create a new column

    if month in months and day == 'all':  # filter the df only by month if applicable
        month = convert_to_int(months, month)
        df = df.loc[df['month'] == month]
    
    if month == 'all' and day in days : # filter the df only by day of week if applicable
        df = df.loc[df['day_of_week'] == day.title()]
    
    if month in months and day in days:
        # use the index of the months list to get the corresponding month's int
        month = convert_to_int(months, month)

        df = df.loc[df['month'] == month]  # first filter the df by month
        df = df.loc[df['day_of_week'] == day.title()] # then filter the df by day of week

    return df # no filter applied

def convert_to_int(months, month):
    month = months.index(month) + 1
    return month


def frequency_stats(df):
    """Displays statistics on the most frequent times of travel."""
    
    print('\nCalculating The Most Frequent Times of Travel...\n')
    start_time = time.time()

    if df['month'].nunique() != 1 and df['day_of_week'].nunique() != 1: # user choose no filter
        most_common_month = df['month'].value_counts().idxmax() # display the most common month
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        most_common_month = months[int(most_common_month) - 1] # convert the index of month back to month name
        print("\nThe most common month is {}.".format(most_common_month))
        most_common_day = df['day_of_week'].value_counts().idxmax() # display the most common day of week
        print("\nThe most common day of week is {}.".format(most_common_day))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax() # display the most common start hour
        print("\nThe most common start hour is {}.".format(most_common_start_hour))
    
    if df['month'].nunique() == 1 and df['day_of_week'].nunique() != 1: # user choose to filter by month
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        month = months[int(df['month'].iloc[0]) - 1] # convert the index of month back to month name

        most_common_day = df['day_of_week'].value_counts().idxmax() # display the most common day of week
        print("\nThe most common day of week in {0} is {1}.".format(month, most_common_day))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax() # display the most common start hour
        print("\nThe most common start hour in {0} is {1}.".format(month, most_common_start_hour))

    if df['day_of_week'].nunique() == 1 and df['month'].nunique() != 1: # user choose to filter by day of week
        day = str(df['day_of_week'].iloc[0]).title()

        most_common_month = df['month'].value_counts().idxmax() # display the most common month
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        most_common_month = months[int(most_common_month) - 1] # convert the index of month back to month name
        print("\nThe most common month on day of {0} is {1}.".format(day, most_common_month))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax() # display the most common start hour
        print("\nThe most common start hour on day of {0} is {1}.".format(day, most_common_start_hour))

    if df['month'].nunique() == 1 and df['day_of_week'].nunique() == 1: 
    # user choose to filter by both month and day
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        month = months[int(df['month'].iloc[0]) - 1] # convert the index of month back to month name
        day = str(df['day_of_week'].iloc[0]).title()

        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax() # display the most common start hour
        print("\nThe most common start hour on {0} in {1} is {2}.".format(day, month, most_common_start_hour))

    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)


def station_stats(df):
    """Displays statistics on the most popular stations and trip."""

    print('\nCalculating The Most Popular Stations and Trip...\n')
    start_time = time.time()

    # display most commonly used start station
    most_common_start_station = df['Start Station'].value_counts().idxmax()
    print("\nThe most commonly used start station is {}.".format(most_common_start_station))

    # display most commonly used end station
    most_common_end_station = df['End Station'].value_counts().idxmax() # display the most common start station
    print("\nThe most commonly used end station is {}.".format(most_common_start_station))

    # display most frequent combination of start station and end station trip
    df['Route'] = df['Start Station'] + ' to ' + df['End Station']
    most_common_route = df['Route'].value_counts().idxmax()
    print("\nThe most frequent route is from {}.".format(most_common_route))

    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)


def trip_duration_stats(df):
    """Displays statistics on the total and average trip duration."""

    print('\nCalculating Trip Duration...\n')
    start_time = time.time()

    # display total travel time
    total_trip_duration = df['Trip Duration'].sum()
    print("\nThe total travel time is {}.".format(total_trip_duration))

    # display mean travel time
    mean_trip_duration = df['Trip Duration'].mean()
    print("\nThe mean travel time is {}.".format(mean_trip_duration))


    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)


def user_stats(df):
    """Displays statistics on bikeshare users."""

    print('\nCalculating User Stats...\n')
    start_time = time.time()

    # Display counts of user types
    user_types = df['User Type'].value_counts()
    print("\nThe distribution of user types is:\n{}".format(user_types))

    # Display counts of gender
    if 'Gender' in df:
        genders_count = df['Gender'].value_counts()
        print("\nThe distribution of user gender is:\n{}".format(genders_count))
    else:
        print("\nThere is no available information regarding users' gender in this city.")

    # Display earliest, most recent, and most common year of birth
    if 'Birth Year' in df:
        earlist_birth_year = int(df['Birth Year'].min())
        most_recent_birth_year = int(df['Birth Year'].max())
        most_common_birth_yaer = int(df['Birth Year'].value_counts().idxmax())
        print("\nThe earlist year of birth among the users is {}.".format(earlist_birth_year))
        print("\nThe most recent year of birth among the users is {}.".format(most_recent_birth_year))
        print("\nThe most common year of birth among the users is {}.".format(most_common_birth_yaer))
    else:
        print("\nThere is no available information regarding users' year of birth in this city.")


    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)

def get_raw_data(df):
    """Prompt the user whether they would like to see the raw data.
        Print out 5 rows of the data (ascending indices, accumulative) for each 'yes' attempt 
        until a 'no' input or the last row.""" 
    
    row_number = 0
    while True:
        attempt = input("\nWould you like to check the raw data? Enter 'yes' or 'no'.\n").lower()
        if attempt in ['yes', 'y', 'no', 'n']:
            while (attempt == 'yes' or attempt == 'y') and row_number < df.shape[0]: # number of total rows
                if row_number < df.shape[0] - 4:
                    df_output = df.iloc[row_number: row_number+5]
                    row_number += 5
                    print(df_output)
                    while True:
                        attempt = input("\nWould you like to continue checking the raw data? Enter 'yes' or 'no'.\n").lower()
                        if attempt in ['yes', 'y', 'no', 'n']:
                            break
                        else:
                            print("\nThe input is not valid. Please re-enter 'yes' or 'no'.\n")
                else:
                    df_output = df.iloc[row_number:]
                    row_number += 5
                    print(df_output)
                    print("\nWe have reached the last row of the raw data.\n")
            if attempt == 'no' or attempt == 'n' or row_number >= df.shape[0]:
                print("\nThe check on raw data is finishing... Thank you.\n")
            break
        else:
            print("\nThe input is not valid. Please enter 'yes' or 'no'.\n")
    
    print('-'*40)

def main():
    while True:
        city, month, day = get_filters()
        df = load_data(city, month, day)

        frequency_stats(df)
        station_stats(df)
        trip_duration_stats(df)
        user_stats(df)

        restart = input('\nWould you like to restart? Enter yes or no.\n')
        if restart.lower() != 'yes':
            break


if __name__ == "__main__":
	main()

071731d701260c2d72d7f894e7f4930c33c3f7f0
<mask token>


def load_data(city, month, day):
    """
    Loads data for the specified city and filters by month and day if applicable.

    Args:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    Returns:
        df - Pandas DataFrame containing city data filtered by month and day
    """
    months = ['january', 'february', 'march', 'april', 'may', 'june']
    days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday',
        'saturday', 'sunday']
    df = pd.read_csv(CITY_DATA[city])
    df['Start Time'] = pd.to_datetime(df['Start Time'])
    df['month'] = df['Start Time'].dt.month
    df['day_of_week'] = df['Start Time'].dt.day_name()
    if month in months and day == 'all':
        month = convert_to_int(months, month)
        df = df.loc[df['month'] == month]
    if month == 'all' and day in days:
        df = df.loc[df['day_of_week'] == day.title()]
    if month in months and day in days:
        month = convert_to_int(months, month)
        df = df.loc[df['month'] == month]
        df = df.loc[df['day_of_week'] == day.title()]
    return df


<mask token>


def frequency_stats(df):
    """Displays statistics on the most frequent times of travel."""
    print('\nCalculating The Most Frequent Times of Travel...\n')
    start_time = time.time()
    if df['month'].nunique() != 1 and df['day_of_week'].nunique() != 1:
        most_common_month = df['month'].value_counts().idxmax()
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        most_common_month = months[int(most_common_month) - 1]
        print('\nThe most common month is {}.'.format(most_common_month))
        most_common_day = df['day_of_week'].value_counts().idxmax()
        print('\nThe most common day of week is {}.'.format(most_common_day))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour is {}.'.format(
            most_common_start_hour))
    if df['month'].nunique() == 1 and df['day_of_week'].nunique() != 1:
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        month = months[int(df['month'].iloc[0]) - 1]
        most_common_day = df['day_of_week'].value_counts().idxmax()
        print('\nThe most common day of week in {0} is {1}.'.format(month,
            most_common_day))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour in {0} is {1}.'.format(month,
            most_common_start_hour))
    if df['day_of_week'].nunique() == 1 and df['month'].nunique() != 1:
        day = str(df['day_of_week'].iloc[0]).title()
        most_common_month = df['month'].value_counts().idxmax()
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        most_common_month = months[int(most_common_month) - 1]
        print('\nThe most common month on day of {0} is {1}.'.format(day,
            most_common_month))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour on day of {0} is {1}.'.format(
            day, most_common_start_hour))
    if df['month'].nunique() == 1 and df['day_of_week'].nunique() == 1:
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        month = months[int(df['month'].iloc[0]) - 1]
        day = str(df['day_of_week'].iloc[0]).title()
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour on {0} in {1} is {2}.'.format(
            day, month, most_common_start_hour))
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


<mask token>


def trip_duration_stats(df):
    """Displays statistics on the total and average trip duration."""
    print('\nCalculating Trip Duration...\n')
    start_time = time.time()
    total_trip_duration = df['Trip Duration'].sum()
    print('\nThe total travel time is {}.'.format(total_trip_duration))
    mean_trip_duration = df['Trip Duration'].mean()
    print('\nThe mean travel time is {}.'.format(mean_trip_duration))
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


<mask token>


def main():
    while True:
        city, month, day = get_filters()
        df = load_data(city, month, day)
        frequency_stats(df)
        station_stats(df)
        trip_duration_stats(df)
        user_stats(df)
        restart = input('\nWould you like to restart? Enter yes or no.\n')
        if restart.lower() != 'yes':
            break


<mask token>

<mask token>


def get_filters():
    """
    Asks user to specify a city, month, and day to analyze.

    Returns:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    """
    print("Hello! Let's explore some US bikeshare data!")
    while True:
        try:
            cities = ['chicago', 'new york city', 'washington']
            city = input(
                'Would you like to see data for Chicago, New York, or Washington? Please enter: '
                ).lower()
            if city == 'new york':
                city += ' city'
                break
            elif city in cities:
                break
            else:
                print(
                    'It seems the spelling of the city is not correct...Please re-enter the city name.'
                    )
        except:
            print('It seems like an invalid input...Please re-enter the city.')
    months = ['january', 'february', 'march', 'april', 'may', 'june']
    days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday',
        'saturday', 'sunday']
    while True:
        choice = input(
            'Would you like to filter by month, day, both, or neither (no filter)? Please enter your choice: '
            ).lower()
        if choice == 'month' or choice == 'by month':
            while True:
                month = input(
                    'Which month - January, February, March, April, May, or June? Please enter: '
                    ).lower()
                day = 'all'
                if month in months:
                    break
                else:
                    print(
                        'The input is not valid. Please input the correct month.'
                        )
            break
        elif choice == 'day' or choice == 'by day':
            while True:
                day = input(
                    'Which day - Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, or Sunday? Please enter: '
                    ).lower()
                month = 'all'
                if day in days:
                    break
                else:
                    print(
                        'The input is not valid. Please input the correct day name.'
                        )
            break
        elif choice == 'both' or choice == 'by both':
            while True:
                month = input(
                    'Which month - January, February, March, April, May, or June? Please enter: '
                    ).lower()
                day = input(
                    'Which day - Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, or Sunday? Please enter: '
                    ).lower()
                if month in months and day in days:
                    break
                else:
                    print(
                        'It seems at least one of the inputs is not valid. Please input the correct month and/or day name.'
                        )
            break
        elif choice == 'neither' or choice == 'no filter':
            month = 'all'
            day = 'all'
            break
        else:
            print(
                'The input is not valid. Please make sure the choice input is in correct format.'
                )
    print('-' * 40)
    return city, month, day


def load_data(city, month, day):
    """
    Loads data for the specified city and filters by month and day if applicable.

    Args:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    Returns:
        df - Pandas DataFrame containing city data filtered by month and day
    """
    months = ['january', 'february', 'march', 'april', 'may', 'june']
    days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday',
        'saturday', 'sunday']
    df = pd.read_csv(CITY_DATA[city])
    df['Start Time'] = pd.to_datetime(df['Start Time'])
    df['month'] = df['Start Time'].dt.month
    df['day_of_week'] = df['Start Time'].dt.day_name()
    if month in months and day == 'all':
        month = convert_to_int(months, month)
        df = df.loc[df['month'] == month]
    if month == 'all' and day in days:
        df = df.loc[df['day_of_week'] == day.title()]
    if month in months and day in days:
        month = convert_to_int(months, month)
        df = df.loc[df['month'] == month]
        df = df.loc[df['day_of_week'] == day.title()]
    return df


<mask token>


def frequency_stats(df):
    """Displays statistics on the most frequent times of travel."""
    print('\nCalculating The Most Frequent Times of Travel...\n')
    start_time = time.time()
    if df['month'].nunique() != 1 and df['day_of_week'].nunique() != 1:
        most_common_month = df['month'].value_counts().idxmax()
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        most_common_month = months[int(most_common_month) - 1]
        print('\nThe most common month is {}.'.format(most_common_month))
        most_common_day = df['day_of_week'].value_counts().idxmax()
        print('\nThe most common day of week is {}.'.format(most_common_day))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour is {}.'.format(
            most_common_start_hour))
    if df['month'].nunique() == 1 and df['day_of_week'].nunique() != 1:
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        month = months[int(df['month'].iloc[0]) - 1]
        most_common_day = df['day_of_week'].value_counts().idxmax()
        print('\nThe most common day of week in {0} is {1}.'.format(month,
            most_common_day))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour in {0} is {1}.'.format(month,
            most_common_start_hour))
    if df['day_of_week'].nunique() == 1 and df['month'].nunique() != 1:
        day = str(df['day_of_week'].iloc[0]).title()
        most_common_month = df['month'].value_counts().idxmax()
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        most_common_month = months[int(most_common_month) - 1]
        print('\nThe most common month on day of {0} is {1}.'.format(day,
            most_common_month))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour on day of {0} is {1}.'.format(
            day, most_common_start_hour))
    if df['month'].nunique() == 1 and df['day_of_week'].nunique() == 1:
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        month = months[int(df['month'].iloc[0]) - 1]
        day = str(df['day_of_week'].iloc[0]).title()
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour on {0} in {1} is {2}.'.format(
            day, month, most_common_start_hour))
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


def station_stats(df):
    """Displays statistics on the most popular stations and trip."""
    print('\nCalculating The Most Popular Stations and Trip...\n')
    start_time = time.time()
    most_common_start_station = df['Start Station'].value_counts().idxmax()
    print('\nThe most commonly used start station is {}.'.format(
        most_common_start_station))
    most_common_end_station = df['End Station'].value_counts().idxmax()
    print('\nThe most commonly used end station is {}.'.format(
        most_common_start_station))
    df['Route'] = df['Start Station'] + ' to ' + df['End Station']
    most_common_route = df['Route'].value_counts().idxmax()
    print('\nThe most frequent route is from {}.'.format(most_common_route))
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


def trip_duration_stats(df):
    """Displays statistics on the total and average trip duration."""
    print('\nCalculating Trip Duration...\n')
    start_time = time.time()
    total_trip_duration = df['Trip Duration'].sum()
    print('\nThe total travel time is {}.'.format(total_trip_duration))
    mean_trip_duration = df['Trip Duration'].mean()
    print('\nThe mean travel time is {}.'.format(mean_trip_duration))
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


def user_stats(df):
    """Displays statistics on bikeshare users."""
    print('\nCalculating User Stats...\n')
    start_time = time.time()
    user_types = df['User Type'].value_counts()
    print('\nThe distribution of user types is:\n{}'.format(user_types))
    if 'Gender' in df:
        genders_count = df['Gender'].value_counts()
        print('\nThe distribution of user gender is:\n{}'.format(genders_count)
            )
    else:
        print(
            "\nThere is no available information regarding users' gender in this city."
            )
    if 'Birth Year' in df:
        earlist_birth_year = int(df['Birth Year'].min())
        most_recent_birth_year = int(df['Birth Year'].max())
        most_common_birth_yaer = int(df['Birth Year'].value_counts().idxmax())
        print('\nThe earlist year of birth among the users is {}.'.format(
            earlist_birth_year))
        print('\nThe most recent year of birth among the users is {}.'.
            format(most_recent_birth_year))
        print('\nThe most common year of birth among the users is {}.'.
            format(most_common_birth_yaer))
    else:
        print(
            "\nThere is no available information regarding users' year of birth in this city."
            )
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


def get_raw_data(df):
    """Prompt the user whether they would like to see the raw data.
        Print out 5 rows of the data (ascending indices, accumulative) for each 'yes' attempt 
        until a 'no' input or the last row."""
    row_number = 0
    while True:
        attempt = input(
            "\nWould you like to check the raw data? Enter 'yes' or 'no'.\n"
            ).lower()
        if attempt in ['yes', 'y', 'no', 'n']:
            while (attempt == 'yes' or attempt == 'y'
                ) and row_number < df.shape[0]:
                if row_number < df.shape[0] - 4:
                    df_output = df.iloc[row_number:row_number + 5]
                    row_number += 5
                    print(df_output)
                    while True:
                        attempt = input(
                            """
Would you like to continue checking the raw data? Enter 'yes' or 'no'.
"""
                            ).lower()
                        if attempt in ['yes', 'y', 'no', 'n']:
                            break
                        else:
                            print(
                                "\nThe input is not valid. Please re-enter 'yes' or 'no'.\n"
                                )
                else:
                    df_output = df.iloc[row_number:]
                    row_number += 5
                    print(df_output)
                    print('\nWe have reached the last row of the raw data.\n')
            if attempt == 'no' or attempt == 'n' or row_number >= df.shape[0]:
                print('\nThe check on raw data is finishing... Thank you.\n')
            break
        else:
            print("\nThe input is not valid. Please enter 'yes' or 'no'.\n")
    print('-' * 40)


def main():
    while True:
        city, month, day = get_filters()
        df = load_data(city, month, day)
        frequency_stats(df)
        station_stats(df)
        trip_duration_stats(df)
        user_stats(df)
        restart = input('\nWould you like to restart? Enter yes or no.\n')
        if restart.lower() != 'yes':
            break


<mask token>

<mask token>


def get_filters():
    """
    Asks user to specify a city, month, and day to analyze.

    Returns:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    """
    print("Hello! Let's explore some US bikeshare data!")
    while True:
        try:
            cities = ['chicago', 'new york city', 'washington']
            city = input(
                'Would you like to see data for Chicago, New York, or Washington? Please enter: '
                ).lower()
            if city == 'new york':
                city += ' city'
                break
            elif city in cities:
                break
            else:
                print(
                    'It seems the spelling of the city is not correct...Please re-enter the city name.'
                    )
        except:
            print('It seems like an invalid input...Please re-enter the city.')
    months = ['january', 'february', 'march', 'april', 'may', 'june']
    days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday',
        'saturday', 'sunday']
    while True:
        choice = input(
            'Would you like to filter by month, day, both, or neither (no filter)? Please enter your choice: '
            ).lower()
        if choice == 'month' or choice == 'by month':
            while True:
                month = input(
                    'Which month - January, February, March, April, May, or June? Please enter: '
                    ).lower()
                day = 'all'
                if month in months:
                    break
                else:
                    print(
                        'The input is not valid. Please input the correct month.'
                        )
            break
        elif choice == 'day' or choice == 'by day':
            while True:
                day = input(
                    'Which day - Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, or Sunday? Please enter: '
                    ).lower()
                month = 'all'
                if day in days:
                    break
                else:
                    print(
                        'The input is not valid. Please input the correct day name.'
                        )
            break
        elif choice == 'both' or choice == 'by both':
            while True:
                month = input(
                    'Which month - January, February, March, April, May, or June? Please enter: '
                    ).lower()
                day = input(
                    'Which day - Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, or Sunday? Please enter: '
                    ).lower()
                if month in months and day in days:
                    break
                else:
                    print(
                        'It seems at least one of the inputs is not valid. Please input the correct month and/or day name.'
                        )
            break
        elif choice == 'neither' or choice == 'no filter':
            month = 'all'
            day = 'all'
            break
        else:
            print(
                'The input is not valid. Please make sure the choice input is in correct format.'
                )
    print('-' * 40)
    return city, month, day


def load_data(city, month, day):
    """
    Loads data for the specified city and filters by month and day if applicable.

    Args:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    Returns:
        df - Pandas DataFrame containing city data filtered by month and day
    """
    months = ['january', 'february', 'march', 'april', 'may', 'june']
    days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday',
        'saturday', 'sunday']
    df = pd.read_csv(CITY_DATA[city])
    df['Start Time'] = pd.to_datetime(df['Start Time'])
    df['month'] = df['Start Time'].dt.month
    df['day_of_week'] = df['Start Time'].dt.day_name()
    if month in months and day == 'all':
        month = convert_to_int(months, month)
        df = df.loc[df['month'] == month]
    if month == 'all' and day in days:
        df = df.loc[df['day_of_week'] == day.title()]
    if month in months and day in days:
        month = convert_to_int(months, month)
        df = df.loc[df['month'] == month]
        df = df.loc[df['day_of_week'] == day.title()]
    return df


def convert_to_int(months, month):
    month = months.index(month) + 1
    return month


def frequency_stats(df):
    """Displays statistics on the most frequent times of travel."""
    print('\nCalculating The Most Frequent Times of Travel...\n')
    start_time = time.time()
    if df['month'].nunique() != 1 and df['day_of_week'].nunique() != 1:
        most_common_month = df['month'].value_counts().idxmax()
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        most_common_month = months[int(most_common_month) - 1]
        print('\nThe most common month is {}.'.format(most_common_month))
        most_common_day = df['day_of_week'].value_counts().idxmax()
        print('\nThe most common day of week is {}.'.format(most_common_day))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour is {}.'.format(
            most_common_start_hour))
    if df['month'].nunique() == 1 and df['day_of_week'].nunique() != 1:
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        month = months[int(df['month'].iloc[0]) - 1]
        most_common_day = df['day_of_week'].value_counts().idxmax()
        print('\nThe most common day of week in {0} is {1}.'.format(month,
            most_common_day))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour in {0} is {1}.'.format(month,
            most_common_start_hour))
    if df['day_of_week'].nunique() == 1 and df['month'].nunique() != 1:
        day = str(df['day_of_week'].iloc[0]).title()
        most_common_month = df['month'].value_counts().idxmax()
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        most_common_month = months[int(most_common_month) - 1]
        print('\nThe most common month on day of {0} is {1}.'.format(day,
            most_common_month))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour on day of {0} is {1}.'.format(
            day, most_common_start_hour))
    if df['month'].nunique() == 1 and df['day_of_week'].nunique() == 1:
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        month = months[int(df['month'].iloc[0]) - 1]
        day = str(df['day_of_week'].iloc[0]).title()
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour on {0} in {1} is {2}.'.format(
            day, month, most_common_start_hour))
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


def station_stats(df):
    """Displays statistics on the most popular stations and trip."""
    print('\nCalculating The Most Popular Stations and Trip...\n')
    start_time = time.time()
    most_common_start_station = df['Start Station'].value_counts().idxmax()
    print('\nThe most commonly used start station is {}.'.format(
        most_common_start_station))
    most_common_end_station = df['End Station'].value_counts().idxmax()
    print('\nThe most commonly used end station is {}.'.format(
        most_common_start_station))
    df['Route'] = df['Start Station'] + ' to ' + df['End Station']
    most_common_route = df['Route'].value_counts().idxmax()
    print('\nThe most frequent route is from {}.'.format(most_common_route))
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


def trip_duration_stats(df):
    """Displays statistics on the total and average trip duration."""
    print('\nCalculating Trip Duration...\n')
    start_time = time.time()
    total_trip_duration = df['Trip Duration'].sum()
    print('\nThe total travel time is {}.'.format(total_trip_duration))
    mean_trip_duration = df['Trip Duration'].mean()
    print('\nThe mean travel time is {}.'.format(mean_trip_duration))
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


def user_stats(df):
    """Displays statistics on bikeshare users."""
    print('\nCalculating User Stats...\n')
    start_time = time.time()
    user_types = df['User Type'].value_counts()
    print('\nThe distribution of user types is:\n{}'.format(user_types))
    if 'Gender' in df:
        genders_count = df['Gender'].value_counts()
        print('\nThe distribution of user gender is:\n{}'.format(genders_count)
            )
    else:
        print(
            "\nThere is no available information regarding users' gender in this city."
            )
    if 'Birth Year' in df:
        earlist_birth_year = int(df['Birth Year'].min())
        most_recent_birth_year = int(df['Birth Year'].max())
        most_common_birth_yaer = int(df['Birth Year'].value_counts().idxmax())
        print('\nThe earlist year of birth among the users is {}.'.format(
            earlist_birth_year))
        print('\nThe most recent year of birth among the users is {}.'.
            format(most_recent_birth_year))
        print('\nThe most common year of birth among the users is {}.'.
            format(most_common_birth_yaer))
    else:
        print(
            "\nThere is no available information regarding users' year of birth in this city."
            )
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


def get_raw_data(df):
    """Prompt the user whether they would like to see the raw data.
        Print out 5 rows of the data (ascending indices, accumulative) for each 'yes' attempt 
        until a 'no' input or the last row."""
    row_number = 0
    while True:
        attempt = input(
            "\nWould you like to check the raw data? Enter 'yes' or 'no'.\n"
            ).lower()
        if attempt in ['yes', 'y', 'no', 'n']:
            while (attempt == 'yes' or attempt == 'y'
                ) and row_number < df.shape[0]:
                if row_number < df.shape[0] - 4:
                    df_output = df.iloc[row_number:row_number + 5]
                    row_number += 5
                    print(df_output)
                    while True:
                        attempt = input(
                            """
Would you like to continue checking the raw data? Enter 'yes' or 'no'.
"""
                            ).lower()
                        if attempt in ['yes', 'y', 'no', 'n']:
                            break
                        else:
                            print(
                                "\nThe input is not valid. Please re-enter 'yes' or 'no'.\n"
                                )
                else:
                    df_output = df.iloc[row_number:]
                    row_number += 5
                    print(df_output)
                    print('\nWe have reached the last row of the raw data.\n')
            if attempt == 'no' or attempt == 'n' or row_number >= df.shape[0]:
                print('\nThe check on raw data is finishing... Thank you.\n')
            break
        else:
            print("\nThe input is not valid. Please enter 'yes' or 'no'.\n")
    print('-' * 40)


def main():
    while True:
        city, month, day = get_filters()
        df = load_data(city, month, day)
        frequency_stats(df)
        station_stats(df)
        trip_duration_stats(df)
        user_stats(df)
        restart = input('\nWould you like to restart? Enter yes or no.\n')
        if restart.lower() != 'yes':
            break


if __name__ == '__main__':
    main()

import time
import pandas as pd
import numpy as np
CITY_DATA = {'chicago': 'chicago.csv', 'new york city': 'new_york_city.csv',
    'washington': 'washington.csv'}


def get_filters():
    """
    Asks user to specify a city, month, and day to analyze.

    Returns:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    """
    print("Hello! Let's explore some US bikeshare data!")
    while True:
        try:
            cities = ['chicago', 'new york city', 'washington']
            city = input(
                'Would you like to see data for Chicago, New York, or Washington? Please enter: '
                ).lower()
            if city == 'new york':
                city += ' city'
                break
            elif city in cities:
                break
            else:
                print(
                    'It seems the spelling of the city is not correct...Please re-enter the city name.'
                    )
        except:
            print('It seems like an invalid input...Please re-enter the city.')
    months = ['january', 'february', 'march', 'april', 'may', 'june']
    days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday',
        'saturday', 'sunday']
    while True:
        choice = input(
            'Would you like to filter by month, day, both, or neither (no filter)? Please enter your choice: '
            ).lower()
        if choice == 'month' or choice == 'by month':
            while True:
                month = input(
                    'Which month - January, February, March, April, May, or June? Please enter: '
                    ).lower()
                day = 'all'
                if month in months:
                    break
                else:
                    print(
                        'The input is not valid. Please input the correct month.'
                        )
            break
        elif choice == 'day' or choice == 'by day':
            while True:
                day = input(
                    'Which day - Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, or Sunday? Please enter: '
                    ).lower()
                month = 'all'
                if day in days:
                    break
                else:
                    print(
                        'The input is not valid. Please input the correct day name.'
                        )
            break
        elif choice == 'both' or choice == 'by both':
            while True:
                month = input(
                    'Which month - January, February, March, April, May, or June? Please enter: '
                    ).lower()
                day = input(
                    'Which day - Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, or Sunday? Please enter: '
                    ).lower()
                if month in months and day in days:
                    break
                else:
                    print(
                        'It seems at least one of the inputs is not valid. Please input the correct month and/or day name.'
                        )
            break
        elif choice == 'neither' or choice == 'no filter':
            month = 'all'
            day = 'all'
            break
        else:
            print(
                'The input is not valid. Please make sure the choice input is in correct format.'
                )
    print('-' * 40)
    return city, month, day


def load_data(city, month, day):
    """
    Loads data for the specified city and filters by month and day if applicable.

    Args:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    Returns:
        df - Pandas DataFrame containing city data filtered by month and day
    """
    months = ['january', 'february', 'march', 'april', 'may', 'june']
    days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday',
        'saturday', 'sunday']
    df = pd.read_csv(CITY_DATA[city])
    df['Start Time'] = pd.to_datetime(df['Start Time'])
    df['month'] = df['Start Time'].dt.month
    df['day_of_week'] = df['Start Time'].dt.day_name()
    if month in months and day == 'all':
        month = convert_to_int(months, month)
        df = df.loc[df['month'] == month]
    if month == 'all' and day in days:
        df = df.loc[df['day_of_week'] == day.title()]
    if month in months and day in days:
        month = convert_to_int(months, month)
        df = df.loc[df['month'] == month]
        df = df.loc[df['day_of_week'] == day.title()]
    return df


def convert_to_int(months, month):
    month = months.index(month) + 1
    return month


def frequency_stats(df):
    """Displays statistics on the most frequent times of travel."""
    print('\nCalculating The Most Frequent Times of Travel...\n')
    start_time = time.time()
    if df['month'].nunique() != 1 and df['day_of_week'].nunique() != 1:
        most_common_month = df['month'].value_counts().idxmax()
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        most_common_month = months[int(most_common_month) - 1]
        print('\nThe most common month is {}.'.format(most_common_month))
        most_common_day = df['day_of_week'].value_counts().idxmax()
        print('\nThe most common day of week is {}.'.format(most_common_day))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour is {}.'.format(
            most_common_start_hour))
    if df['month'].nunique() == 1 and df['day_of_week'].nunique() != 1:
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        month = months[int(df['month'].iloc[0]) - 1]
        most_common_day = df['day_of_week'].value_counts().idxmax()
        print('\nThe most common day of week in {0} is {1}.'.format(month,
            most_common_day))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour in {0} is {1}.'.format(month,
            most_common_start_hour))
    if df['day_of_week'].nunique() == 1 and df['month'].nunique() != 1:
        day = str(df['day_of_week'].iloc[0]).title()
        most_common_month = df['month'].value_counts().idxmax()
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        most_common_month = months[int(most_common_month) - 1]
        print('\nThe most common month on day of {0} is {1}.'.format(day,
            most_common_month))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour on day of {0} is {1}.'.format(
            day, most_common_start_hour))
    if df['month'].nunique() == 1 and df['day_of_week'].nunique() == 1:
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        month = months[int(df['month'].iloc[0]) - 1]
        day = str(df['day_of_week'].iloc[0]).title()
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax()
        print('\nThe most common start hour on {0} in {1} is {2}.'.format(
            day, month, most_common_start_hour))
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


def station_stats(df):
    """Displays statistics on the most popular stations and trip."""
    print('\nCalculating The Most Popular Stations and Trip...\n')
    start_time = time.time()
    most_common_start_station = df['Start Station'].value_counts().idxmax()
    print('\nThe most commonly used start station is {}.'.format(
        most_common_start_station))
    most_common_end_station = df['End Station'].value_counts().idxmax()
    print('\nThe most commonly used end station is {}.'.format(
        most_common_start_station))
    df['Route'] = df['Start Station'] + ' to ' + df['End Station']
    most_common_route = df['Route'].value_counts().idxmax()
    print('\nThe most frequent route is from {}.'.format(most_common_route))
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


def trip_duration_stats(df):
    """Displays statistics on the total and average trip duration."""
    print('\nCalculating Trip Duration...\n')
    start_time = time.time()
    total_trip_duration = df['Trip Duration'].sum()
    print('\nThe total travel time is {}.'.format(total_trip_duration))
    mean_trip_duration = df['Trip Duration'].mean()
    print('\nThe mean travel time is {}.'.format(mean_trip_duration))
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


def user_stats(df):
    """Displays statistics on bikeshare users."""
    print('\nCalculating User Stats...\n')
    start_time = time.time()
    user_types = df['User Type'].value_counts()
    print('\nThe distribution of user types is:\n{}'.format(user_types))
    if 'Gender' in df:
        genders_count = df['Gender'].value_counts()
        print('\nThe distribution of user gender is:\n{}'.format(genders_count)
            )
    else:
        print(
            "\nThere is no available information regarding users' gender in this city."
            )
    if 'Birth Year' in df:
        earlist_birth_year = int(df['Birth Year'].min())
        most_recent_birth_year = int(df['Birth Year'].max())
        most_common_birth_yaer = int(df['Birth Year'].value_counts().idxmax())
        print('\nThe earlist year of birth among the users is {}.'.format(
            earlist_birth_year))
        print('\nThe most recent year of birth among the users is {}.'.
            format(most_recent_birth_year))
        print('\nThe most common year of birth among the users is {}.'.
            format(most_common_birth_yaer))
    else:
        print(
            "\nThere is no available information regarding users' year of birth in this city."
            )
    print('\nThis took %s seconds.' % (time.time() - start_time))
    print('-' * 40)


def get_raw_data(df):
    """Prompt the user whether they would like to see the raw data.
        Print out 5 rows of the data (ascending indices, accumulative) for each 'yes' attempt 
        until a 'no' input or the last row."""
    row_number = 0
    while True:
        attempt = input(
            "\nWould you like to check the raw data? Enter 'yes' or 'no'.\n"
            ).lower()
        if attempt in ['yes', 'y', 'no', 'n']:
            while (attempt == 'yes' or attempt == 'y'
                ) and row_number < df.shape[0]:
                if row_number < df.shape[0] - 4:
                    df_output = df.iloc[row_number:row_number + 5]
                    row_number += 5
                    print(df_output)
                    while True:
                        attempt = input(
                            """
Would you like to continue checking the raw data? Enter 'yes' or 'no'.
"""
                            ).lower()
                        if attempt in ['yes', 'y', 'no', 'n']:
                            break
                        else:
                            print(
                                "\nThe input is not valid. Please re-enter 'yes' or 'no'.\n"
                                )
                else:
                    df_output = df.iloc[row_number:]
                    row_number += 5
                    print(df_output)
                    print('\nWe have reached the last row of the raw data.\n')
            if attempt == 'no' or attempt == 'n' or row_number >= df.shape[0]:
                print('\nThe check on raw data is finishing... Thank you.\n')
            break
        else:
            print("\nThe input is not valid. Please enter 'yes' or 'no'.\n")
    print('-' * 40)


def main():
    while True:
        city, month, day = get_filters()
        df = load_data(city, month, day)
        frequency_stats(df)
        station_stats(df)
        trip_duration_stats(df)
        user_stats(df)
        restart = input('\nWould you like to restart? Enter yes or no.\n')
        if restart.lower() != 'yes':
            break


if __name__ == '__main__':
    main()

import time
import pandas as pd
import numpy as np

CITY_DATA = { 'chicago': 'chicago.csv',
              'new york city': 'new_york_city.csv',
              'washington': 'washington.csv' }

def get_filters():
    """
    Asks user to specify a city, month, and day to analyze.

    Returns:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    """
    print('Hello! Let\'s explore some US bikeshare data!')
    # get user input for city (chicago, new york city, washington). HINT: Use a while loop to handle invalid inputs
    while True:
        try:
            cities = ['chicago', 'new york city', 'washington']
            city = input("Would you like to see data for Chicago, New York, or Washington? Please enter: ").lower()
            if city == 'new york':
                city += ' city'
                break
            elif city in cities:
                break
            else:
                print('It seems the spelling of the city is not correct...Please re-enter the city name.')
        except:  # other error situations e.g. none stings being input; but not sure which type(s) of errors should be specified here 
            print('It seems like an invalid input...Please re-enter the city.')

    # get user input for month (all, january, february, ... , june)
    # get user input for day of week (all, monday, tuesday, ... sunday)
    months = ['january', 'february', 'march', 'april', 'may', 'june']
    days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
    while True:
        choice = input("Would you like to filter by month, day, both, or neither (no filter)? Please enter your choice: ").lower()
        if choice == 'month' or choice == 'by month':
            while True:
                month = input("Which month - January, February, March, April, May, or June? Please enter: ").lower()
                day = 'all'
                if month in months:
                    break
                else:
                    print('The input is not valid. Please input the correct month.')
            break
        elif choice == 'day' or choice == 'by day':
            while True:
                day = input("Which day - Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, or Sunday? Please enter: ").lower()
                month = 'all'
                if day in days:
                    break
                else:
                    print('The input is not valid. Please input the correct day name.')
            break
        elif choice == 'both' or choice == 'by both':
            while True:
                month = input("Which month - January, February, March, April, May, or June? Please enter: ").lower()
                day = input("Which day - Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, or Sunday? Please enter: ").lower()
                if (month in months) and (day in days):
                    break
                else:
                    print('It seems at least one of the inputs is not valid. Please input the correct month and/or day name.')
            break
        elif choice == 'neither' or choice == 'no filter':
            month = 'all'
            day = 'all'
            break
        else:
            print('The input is not valid. Please make sure the choice input is in correct format.')

    print('-'*40)
    return city, month, day


def load_data(city, month, day):
    """
    Loads data for the specified city and filters by month and day if applicable.

    Args:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    Returns:
        df - Pandas DataFrame containing city data filtered by month and day
    """
    months = ['january', 'february', 'march', 'april', 'may', 'june']
    days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
    df = pd.read_csv(CITY_DATA[city])
    df['Start Time'] = pd.to_datetime(df['Start Time']) # convert the Start Time column to datetime
    df['month'] = df['Start Time'].dt.month # extract month from start time to create a new column
    df['day_of_week'] = df['Start Time'].dt.day_name() # extract day from start time to create a new column

    if month in months and day == 'all':  # filter the df only by month if applicable
        month = convert_to_int(months, month)
        df = df.loc[df['month'] == month]
    
    if month == 'all' and day in days : # filter the df only by day of week if applicable
        df = df.loc[df['day_of_week'] == day.title()]
    
    if month in months and day in days:
        # use the index of the months list to get the corresponding month's int
        month = convert_to_int(months, month)

        df = df.loc[df['month'] == month]  # first filter the df by month
        df = df.loc[df['day_of_week'] == day.title()] # then filter the df by day of week

    return df # no filter applied

def convert_to_int(months, month):
    month = months.index(month) + 1
    return month


def frequency_stats(df):
    """Displays statistics on the most frequent times of travel."""
    
    print('\nCalculating The Most Frequent Times of Travel...\n')
    start_time = time.time()

    if df['month'].nunique() != 1 and df['day_of_week'].nunique() != 1: # user choose no filter
        most_common_month = df['month'].value_counts().idxmax() # display the most common month
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        most_common_month = months[int(most_common_month) - 1] # convert the index of month back to month name
        print("\nThe most common month is {}.".format(most_common_month))
        most_common_day = df['day_of_week'].value_counts().idxmax() # display the most common day of week
        print("\nThe most common day of week is {}.".format(most_common_day))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax() # display the most common start hour
        print("\nThe most common start hour is {}.".format(most_common_start_hour))
    
    if df['month'].nunique() == 1 and df['day_of_week'].nunique() != 1: # user choose to filter by month
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        month = months[int(df['month'].iloc[0]) - 1] # convert the index of month back to month name

        most_common_day = df['day_of_week'].value_counts().idxmax() # display the most common day of week
        print("\nThe most common day of week in {0} is {1}.".format(month, most_common_day))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax() # display the most common start hour
        print("\nThe most common start hour in {0} is {1}.".format(month, most_common_start_hour))

    if df['day_of_week'].nunique() == 1 and df['month'].nunique() != 1: # user choose to filter by day of week
        day = str(df['day_of_week'].iloc[0]).title()

        most_common_month = df['month'].value_counts().idxmax() # display the most common month
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        most_common_month = months[int(most_common_month) - 1] # convert the index of month back to month name
        print("\nThe most common month on day of {0} is {1}.".format(day, most_common_month))
        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax() # display the most common start hour
        print("\nThe most common start hour on day of {0} is {1}.".format(day, most_common_start_hour))

    if df['month'].nunique() == 1 and df['day_of_week'].nunique() == 1: 
    # user choose to filter by both month and day
        months = ['January', 'February', 'March', 'April', 'May', 'June']
        month = months[int(df['month'].iloc[0]) - 1] # convert the index of month back to month name
        day = str(df['day_of_week'].iloc[0]).title()

        df['hour'] = df['Start Time'].dt.hour
        most_common_start_hour = df['hour'].value_counts().idxmax() # display the most common start hour
        print("\nThe most common start hour on {0} in {1} is {2}.".format(day, month, most_common_start_hour))

    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)


def station_stats(df):
    """Displays statistics on the most popular stations and trip."""

    print('\nCalculating The Most Popular Stations and Trip...\n')
    start_time = time.time()

    # display most commonly used start station
    most_common_start_station = df['Start Station'].value_counts().idxmax()
    print("\nThe most commonly used start station is {}.".format(most_common_start_station))

    # display most commonly used end station
    most_common_end_station = df['End Station'].value_counts().idxmax() # display the most common start station
    print("\nThe most commonly used end station is {}.".format(most_common_start_station))

    # display most frequent combination of start station and end station trip
    df['Route'] = df['Start Station'] + ' to ' + df['End Station']
    most_common_route = df['Route'].value_counts().idxmax()
    print("\nThe most frequent route is from {}.".format(most_common_route))

    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)


def trip_duration_stats(df):
    """Displays statistics on the total and average trip duration."""

    print('\nCalculating Trip Duration...\n')
    start_time = time.time()

    # display total travel time
    total_trip_duration = df['Trip Duration'].sum()
    print("\nThe total travel time is {}.".format(total_trip_duration))

    # display mean travel time
    mean_trip_duration = df['Trip Duration'].mean()
    print("\nThe mean travel time is {}.".format(mean_trip_duration))


    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)


def user_stats(df):
    """Displays statistics on bikeshare users."""

    print('\nCalculating User Stats...\n')
    start_time = time.time()

    # Display counts of user types
    user_types = df['User Type'].value_counts()
    print("\nThe distribution of user types is:\n{}".format(user_types))

    # Display counts of gender
    if 'Gender' in df:
        genders_count = df['Gender'].value_counts()
        print("\nThe distribution of user gender is:\n{}".format(genders_count))
    else:
        print("\nThere is no available information regarding users' gender in this city.")

    # Display earliest, most recent, and most common year of birth
    if 'Birth Year' in df:
        earlist_birth_year = int(df['Birth Year'].min())
        most_recent_birth_year = int(df['Birth Year'].max())
        most_common_birth_yaer = int(df['Birth Year'].value_counts().idxmax())
        print("\nThe earlist year of birth among the users is {}.".format(earlist_birth_year))
        print("\nThe most recent year of birth among the users is {}.".format(most_recent_birth_year))
        print("\nThe most common year of birth among the users is {}.".format(most_common_birth_yaer))
    else:
        print("\nThere is no available information regarding users' year of birth in this city.")


    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)

def get_raw_data(df):
    """Prompt the user whether they would like to see the raw data.
        Print out 5 rows of the data (ascending indices, accumulative) for each 'yes' attempt 
        until a 'no' input or the last row.""" 
    
    row_number = 0
    while True:
        attempt = input("\nWould you like to check the raw data? Enter 'yes' or 'no'.\n").lower()
        if attempt in ['yes', 'y', 'no', 'n']:
            while (attempt == 'yes' or attempt == 'y') and row_number < df.shape[0]: # number of total rows
                if row_number < df.shape[0] - 4:
                    df_output = df.iloc[row_number: row_number+5]
                    row_number += 5
                    print(df_output)
                    while True:
                        attempt = input("\nWould you like to continue checking the raw data? Enter 'yes' or 'no'.\n").lower()
                        if attempt in ['yes', 'y', 'no', 'n']:
                            break
                        else:
                            print("\nThe input is not valid. Please re-enter 'yes' or 'no'.\n")
                else:
                    df_output = df.iloc[row_number:]
                    row_number += 5
                    print(df_output)
                    print("\nWe have reached the last row of the raw data.\n")
            if attempt == 'no' or attempt == 'n' or row_number >= df.shape[0]:
                print("\nThe check on raw data is finishing... Thank you.\n")
            break
        else:
            print("\nThe input is not valid. Please enter 'yes' or 'no'.\n")
    
    print('-'*40)

def main():
    while True:
        city, month, day = get_filters()
        df = load_data(city, month, day)

        frequency_stats(df)
        station_stats(df)
        trip_duration_stats(df)
        user_stats(df)

        restart = input('\nWould you like to restart? Enter yes or no.\n')
        if restart.lower() != 'yes':
            break


if __name__ == "__main__":
	main()
