import pandas as pd
from transx2gtfs.bank_holidays import get_bank_holiday_dates


def get_service_calendar_dates_exceptions(data):
    """Parses calendar dates exception info from TransXChange VehicleJourney element"""
    try:
        non_operative_days = data.TransXChange.Services.Service.OperatingProfile.BankHolidayOperation.DaysOfNonOperation.get_elements()
        weekdays = []
        for elem in non_operative_days:
            weekdays.append(elem._name)
        if len(weekdays) == 1:
            return weekdays[0]
        else:
            return "|".join(weekdays)
    except:
        return None


def get_calendar_dates_exceptions(vehicle_journey_element):
    """Parses calendar dates exception info from TransXChange VehicleJourney element"""
    j = vehicle_journey_element
    try:
        non_operative_days = j.OperatingProfile.BankHolidayOperation.DaysOfNonOperation.get_elements()
        weekdays = []
        for elem in non_operative_days:
            weekdays.append(elem._name)
        if len(weekdays) == 1:
            return weekdays[0]
        else:
            return "|".join(weekdays)
    except:
        return None

def get_calendar_dates(gtfs_info, bank_holidays_region='england-and-wales'):
    """
    Parse calendar dates attributes from GTFS info DataFrame.

    TransXChange typically indicates exception in operation using 'AllBankHolidays' as an attribute.
    Hence, Bank holiday information is retrieved from "https://www.gov.uk/" site that should keep the data up-to-date.
    If the file (or internet) is not available, a static version of the same file will be used that is bundled with the package.

    There are different bank holidays in different regions in UK. Hence, you can (and should) define
    the region with <bank_holidays_region> -parameter.
    Available regions are: 'england-and-wales', 'scotland', 'northern-ireland'

    """
    # Known exceptions and their counterparts in bankholiday table
    known_holidays = {'SpringBank': 'Spring bank holiday',
                      'LateSummerBankHolidayNotScotland': 'Summer bank holiday',
                      'MayDay': 'Early May bank holiday',
                      'GoodFriday': 'Good Friday'}

    # Get initial info about non-operative days
    non_operative_values = list(gtfs_info['non_operative_days'].unique())

    # Container for all info
    non_operatives = []

    # Parse all non operative ones
    for info in non_operative_values:
        # Check if info consists of multiple values
        if (info is not None) and "|" in info:
            split = info.split('|')
            non_operatives += split
        else:
            # Add individual value
            if info is not None and info != '':
                non_operatives.append(info)

    # Remove duplicates
    non_operatives = list(set(non_operatives))

    # Check if there exists some exceptions that are not known bank holidays
    for holiday in non_operatives:
        if (holiday not in known_holidays.keys()) and (holiday != 'AllBankHolidays'):
            raise NotImplementedError("There were also other exceptions than typical BankHolidays:", holiday)

    if len(non_operatives) > 0:
        # Get bank holidays that are during the operative period of the feed (returns None if they do not exist)
        bank_holidays = get_bank_holiday_dates(gtfs_info, bank_holidays_region=bank_holidays_region)
    else:
        return None

    # Return None if no bank holiday happens to be during the operative period
    if bank_holidays is None:
        return None

    # Otherwise produce calendar_dates data

    # Select distinct (service_id) rows that have bank holiday determined
    calendar_info = gtfs_info[['service_id', 'non_operative_days']].copy()
    calendar_info = calendar_info.drop_duplicates(subset=['service_id'])

    # Create columns for date and exception_type
    calendar_info['date'] = None

    # The exception will always be indicating non-operative service (value 2)
    calendar_info['exception_type'] = 2

    # Container for calendar_dates
    calendar_dates = pd.DataFrame()

    # Iterate over services and produce rows having exception with given bank holiday dates
    for idx, row in calendar_info.iterrows():
        # Iterate over exception dates
        for date in bank_holidays:
            # Generate row
            row = dict(service_id=row['service_id'],
                       date=date,
                       exception_type=row['exception_type'])
            # Add to container
            calendar_dates = calendar_dates.append(row, ignore_index=True, sort=False)

    # Ensure correct datatype
    calendar_dates['exception_type'] = calendar_dates['exception_type'].astype(int)

    return calendar_dates

