def parse_settings(root_path):
    config['ROOT_PATH'] = root_path
    # Set the default config files up
    config_files = [get_path('config/config.ini')] if '-cf' not in sys.argv and '--config' not in sys.argv else []
    parser = configargparse.ArgParser(default_config_files=config_files)
    parser.add_argument('-cf', '--config', is_config_file=True, help='Configuration file')
    parser.add_argument('-d', '--debug', help='Debug Mode', action='store_true', default=False)
    parser.add_argument('-H', '--host', help='Set web server listening host', default='127.0.0.1')
    parser.add_argument('-P', '--port', type=int, help='Set web server listening port', default=4000)
    parser.add_argument('-m', '--manager_count', type=int, default=1,
                        help='Number of Manager processes to start.')
    parser.add_argument('-M', '--manager_name', type=parse_unicode, action='append', default=[],
                        help='Names of Manager processes to start.')
    parser.add_argument('-k', '--key', type=parse_unicode, action='append', default=[None],
                        help='Specify a Google API Key to use.')
    parser.add_argument('-f', '--filters', type=parse_unicode, action='append', default=['filters.json'],
                        help='Filters configuration file. default: filters.json')
    parser.add_argument('-a', '--alarms', type=parse_unicode, action='append', default=['alarms.json'],
                        help='Alarms configuration file. default: alarms.json')
    parser.add_argument('-gf', '--geofences', type=parse_unicode, action='append', default=[None],
                        help='Alarms configuration file. default: None')
    parser.add_argument('-l', '--location', type=parse_unicode, action='append', default=[None],
                        help='Location, can be an address or coordinates')
    parser.add_argument('-L', '--locale', type=parse_unicode, action='append', default=['en'],
                        choices=['de', 'en', 'es', 'fr', 'it', 'ko', 'zh_hk'],
                        help='Locale for Pokemon and Move names: default en, check locale folder for more options')
    parser.add_argument('-u', '--units', type=parse_unicode, default=['imperial'], action='append',
                        choices=['metric', 'imperial'],
                        help='Specify either metric or imperial units to use for distance measurements. ')
    parser.add_argument('-tl', '--timelimit', type=int, default=[0], action='append',
                        help='Minimum number of seconds remaining on a pokemon to send a notify')
    parser.add_argument('-ma', '--max_attempts', type=int, default=[3], action='append',
                        help='Maximum number of attempts an alarm makes to send a notification.')
    parser.add_argument('-tz', '--timezone', type=str, action='append', default=[None],
                        help='Timezone used for notifications.  Ex: "America/Los_Angeles"')

    args = parser.parse_args()

    if args.debug:
        log.setLevel(logging.DEBUG)
        logging.getLogger().setLevel(logging.DEBUG)
        logging.getLogger('PokeAlarm').setLevel(logging.DEBUG)
        logging.getLogger('Manager').setLevel(logging.DEBUG)
        log.debug("Debug mode enabled!")

    config['HOST'] = args.host
    config['PORT'] = args.port
    config['DEBUG'] = args.debug

    # Check to make sure that the same number of arguements are included
    for list_ in [args.key, args.filters, args.alarms, args.geofences, args.location,
                  args.locale, args.units, args.timelimit, args.max_attempts, args.timezone]:
        if len(list_) > 1:  # Remove defaults from the list
            list_.pop(0)
        size = len(list_)
        if size != 1 and size != args.manager_count:
            log.critical("Number of arguments must be either 1 for all managers or ".format(args.manager_count) +
                         "equal to Manager Count. Please provided the correct number of arguments.")
            log.critical(list_)
            sys.exit(1)

    # Attempt to parse the timezones
    for i in range(len(args.timezone)):
        if str(args.timezone[i]).lower() == "none":
            args.timezone[i] = None
            continue
        try:
            log.info(args.timezone[i])
            args.timezone[i] = pytz.timezone(args.timezone[i])
        except pytz.exceptions.UnknownTimeZoneError:
            log.error("Invalid timezone. For a list of valid timezones, " +
                      "see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones")
            sys.exit(1)

    # Build the managers
    for m_ct in range(args.manager_count):
        # This needs to be changed a few times... because
        config['UNITS'] = args.units[m_ct] if len(args.units) > 1 else args.units[0]
        m = Manager(
            name=args.manager_name[m_ct] if m_ct < len(args.manager_name) else "Manager_{}".format(m_ct),
            google_key=args.key[m_ct] if len(args.key) > 1 else args.key[0],
            locale=args.locale[m_ct] if len(args.locale) > 1 else args.locale[0],
            units=args.units[m_ct] if len(args.units) > 1 else args.units[0],
            timezone=args.timezone[m_ct] if len(args.timezone) > 1 else args.timezone[0],
            time_limit=args.timelimit[m_ct] if len(args.timelimit) > 1 else args.timelimit[0],
            max_attempts=args.max_attempts[m_ct] if len(args.max_attempts) > 1 else args.max_attempts[0],
            quiet=False,  # TODO: I'll totally document this some day. Promise.
            location=args.location[m_ct] if len(args.location) > 1 else args.location[0],
            filter_file=args.filters[m_ct] if len(args.filters) > 1 else args.filters[0],
            geofence_file=args.geofences[m_ct] if len(args.geofences) > 1 else args.geofences[0],
            alarm_file=args.alarms[m_ct] if len(args.alarms) > 1 else args.alarms[0],
            debug=config['DEBUG']
        )
        if m.get_name() not in managers:
            # Add the manager to the map
            managers[m.get_name()] = m
        else:
            log.critical("Names of Manager processes must be unique (regardless of capitalization)! Process will exit.")
            sys.exit(1)
    log.info("Starting up the Managers")
    for m_name in managers:
        managers[m_name].start()
def parse_settings(root_path):
    config['ROOT_PATH'] = root_path
    # Set the default config files up
    config_files = [get_path('config/config.ini')]
    if '-cf' in sys.argv or '--config' in sys.argv:
        config_files = []
    parser = configargparse.ArgParser(default_config_files=config_files)
    parser.add_argument(
        '-cf', '--config', is_config_file=True, help='Configuration file')

    # Webserver Settings:
    parser.add_argument(
        '-H', '--host', help='Set web server listening host',
        default='127.0.0.1')
    parser.add_argument(
        '-P', '--port', type=int,
        help='Set web server listening port', default=4000)
    parser.add_argument(
        '-C', '--concurrency', type=int,
        help='Maximum concurrent connections for the webserver.', default=200)

    parser.add_argument(
        '-d', '--debug', action='store_true', default=False,
        help='Enable debuging mode.')
    parser.add_argument(
        '-q', '--quiet', action='store_true', default=False,
        help='Disables output to console.')
    parser.add_argument(
        '-ll', '--log-lvl', type=int, choices=[1, 2, 3, 4, 5], default=3,
        help='Verbosity of the root logger.')
    parser.add_argument(
        '-lf', '--log-file', type=parse_unicode, default='logs/pokealarm.log',
        help="Path of a file to attach to a manager's logger.")
    parser.add_argument(
        '-ls', '--log-size', type=int, default=100,
        help="Maximum size in mb of a log before rollover.")
    parser.add_argument(
        '-lc', '--log-ct', type=int, default=5,
        help="Maximum number of logs to keep.")

    # Manager Settings
    parser.add_argument(
        '-m', '--manager_count', type=int, default=1,
        help='Number of Manager processes to start.')
    parser.add_argument(
        '-M', '--manager_name', type=parse_unicode,
        action='append', default=[],
        help='Names of Manager processes to start.')
    parser.add_argument(
        '-mll', '--mgr-log-lvl', type=int, choices=[1, 2, 3, 4, 5],
        action='append', default=[3],
        help="Set the verbosity of a manager's logger.")
    parser.add_argument(
        '-mlf', '--mgr-log-file', type=parse_unicode,
        action='append', default=[None],
        help="Path of a file to attach to a manager's logger.")
    parser.add_argument(
        '-mls', '--mgr-log-size', type=int, action='append', default=[100],
        help="Maximum megabytes of a manager's log before rollover.")
    parser.add_argument(
        '-mlc', '--mgr-log-ct', type=int, action='append', default=[5],
        help="Maximum number of old manager's logs to keep before deletion.")
    # Files
    parser.add_argument(
        '-f', '--filters', type=parse_unicode, action='append',
        default=['filters.json'],
        help='Filters configuration file. default: filters.json')
    parser.add_argument(
        '-a', '--alarms', type=parse_unicode, action='append',
        default=['alarms.json'],
        help='Alarms configuration file. default: alarms.json')
    parser.add_argument(
        '-r', '--rules', type=parse_unicode, action='append',
        default=[None],
        help='Rules configuration file. default: None')
    parser.add_argument(
        '-gf', '--geofences', type=parse_unicode,
        action='append', default=[None],
        help='Alarms configuration file. default: None')

    # Location Specific
    parser.add_argument(
        '-l', '--location', type=parse_unicode, action='append',
        default=[None], help='Location, can be an address or coordinates')
    parser.add_argument(
        '-L', '--locale', type=parse_unicode, action='append', default=['en'],
        choices=['de', 'en', 'es', 'fr', 'it', 'ko', 'pt', 'zh_hk'],
        help='Locale for Pokemon and Move names: default en," '
             '+ " check locale folder for more options')
    parser.add_argument(
        '-u', '--units', type=parse_unicode, default=['imperial'],
        action='append', choices=['metric', 'imperial'],
        help='Specify either metric or imperial units to use for distance " '
             '+ "measurements. ')
    parser.add_argument(
        '-tz', '--timezone', type=str, action='append', default=[None],
        help='Timezone used for notifications. Ex: "America/Los_Angeles"')

    # GMaps
    parser.add_argument(
        '-k', '--gmaps-key', type=parse_unicode, action='append',
        default=[None], help='Specify a Google API Key to use.')
    parser.add_argument(
        '--gmaps-rev-geocode', type=parse_boolean, action='append',
        default=[None], help='Enable Walking Distance Matrix DTS.')
    parser.add_argument(
        '--gmaps-dm-walk', type=parse_boolean, action='append',
        default=[None], help='Enable Walking Distance Matrix DTS.')
    parser.add_argument(
        '--gmaps-dm-bike', type=parse_boolean, action='append',
        default=[None], help='Enable Bicycling Distance Matrix DTS.')
    parser.add_argument(
        '--gmaps-dm-drive', type=parse_boolean, action='append',
        default=[None], help='Enable Driving Distance Matrix DTS.')
    parser.add_argument(
        '--gmaps-dm-transit', type=parse_boolean, action='append',
        default=[None], help='Enable Transit Distance Matrix DTS.')

    # Misc
    parser.add_argument(
        '-ct', '--cache_type', type=parse_unicode, action='append',
        default=['mem'], choices=cache_options,
        help="Specify the type of cache to use. Options: "
             + "['mem', 'file'] (Default: 'mem')")
    parser.add_argument(
        '-tl', '--timelimit', type=int, default=[0], action='append',
        help='Minimum limit')
    parser.add_argument(
        '-ma', '--max_attempts', type=int, default=[3], action='append',
        help='Maximum attempts an alarm makes to send a notification.')

    args = parser.parse_args()

    root_logger = logging.getLogger()
    if not args.quiet:
        setup_std_handler(root_logger)

    # Setup file logging
    if not os.path.exists(get_path('logs')):
        os.mkdir(get_path('logs'))
    setup_file_handler(root_logger, args.log_file, args.log_size, args.log_ct)

    if args.debug:
        # Set everything to VERY VERBOSE
        args.log_lvl = 5
        args.mgr_log_lvl = [5]
        log.info("Debug mode enabled!")

    logging.getLogger('webserver.internal').setLevel(logging.WARNING)
    # Set up webserver logging
    if args.log_lvl == 1:
        logging.getLogger('pokealarm.webserver').setLevel(logging.WARNING)
        logging.getLogger('pokealarm.setup').setLevel(logging.WARNING)
    elif args.log_lvl == 2:
        logging.getLogger('pokealarm.webserver').setLevel(logging.INFO)
        logging.getLogger('pokealarm.setup').setLevel(logging.WARNING)
    elif args.log_lvl == 3:
        logging.getLogger('pokealarm.webserver').setLevel(logging.INFO)
        logging.getLogger('pokealarm.setup').setLevel(logging.INFO)
    elif args.log_lvl == 4:
        logging.getLogger('pokealarm.webserver').setLevel(logging.INFO)
        logging.getLogger('pokealarm.setup').setLevel(logging.DEBUG)
    elif args.log_lvl == 5:
        logging.getLogger('pokealarm.webserver').setLevel(logging.DEBUG)
        logging.getLogger('pokealarm.setup').setLevel(logging.DEBUG)

    config['HOST'] = args.host
    config['PORT'] = args.port
    config['CONCURRENCY'] = args.concurrency
    config['DEBUG'] = args.debug

    # Check to make sure that the same number of arguments are included
    for arg in [args.gmaps_key, args.filters, args.alarms, args.rules,
                args.geofences, args.location, args.locale, args.units,
                args.cache_type, args.timelimit, args.max_attempts,
                args.timezone, args.gmaps_rev_geocode, args.gmaps_dm_walk,
                args.gmaps_dm_bike, args.gmaps_dm_drive,
                args.gmaps_dm_transit, args.mgr_log_lvl, args.mgr_log_size,
                args.mgr_log_file]:
        if len(arg) > 1:  # Remove defaults from the list
            arg.pop(0)
        size = len(arg)
        if size != 1 and size != args.manager_count:
            log.critical("Number of arguments must be either 1 for all "
                         + "managers or equal to Manager Count. Please "
                         + "provided the correct number of arguments.")
            log.critical(arg)
            sys.exit(1)

    # Attempt to parse the timezones
    for i in range(len(args.timezone)):
        if str(args.timezone[i]).lower() == "none":
            args.timezone[i] = None
            continue
        try:
            log.info(args.timezone[i])
            args.timezone[i] = pytz.timezone(args.timezone[i])
        except pytz.exceptions.UnknownTimeZoneError:
            log.error("Invalid timezone. For a list of valid timezones, see "
                      + "https://en.wikipedia.org/wiki"
                      + "/List_of_tz_database_time_zones")
            sys.exit(1)

    # Pad manager_name to match manager_count
    while len(args.manager_name) < args.manager_count:
        m_ct = len(args.manager_name)
        args.manager_name.append("Manager_{}".format(m_ct))

    # Build the managers
    for m_ct in range(args.manager_count):
        # TODO: Fix this mess better next time
        log.info("----------- Setting up 'manager_0'")
        config['UNITS'] = get_from_list(args.units, m_ct, args.units[0])
        m = Manager(
            name=args.manager_name[m_ct],
            google_key=get_from_list(
                args.gmaps_key, m_ct, args.gmaps_key[0]),
            locale=get_from_list(args.locale, m_ct, args.locale[0]),
            units=get_from_list(args.units, m_ct, args.units[0]),
            timezone=get_from_list(args.timezone, m_ct, args.timezone[0]),
            time_limit=get_from_list(args.timelimit, m_ct, args.timelimit[0]),
            max_attempts=get_from_list(
                args.max_attempts, m_ct, args.max_attempts[0]),
            cache_type=get_from_list(
                args.cache_type, m_ct, args.cache_type[0]),
            location=get_from_list(args.location, m_ct, args.location[0]),
            geofence_file=get_from_list(
                args.geofences, m_ct, args.geofences[0]),
            debug=config['DEBUG']
        )

        m.set_log_level(get_from_list(
            args.mgr_log_lvl, m_ct, args.mgr_log_lvl[0]))

        file_log = get_from_list(args.mgr_log_file, m_ct, args.mgr_log_file[0])
        if str(file_log).lower() != "none":
            size = get_from_list(args.mgr_log_size, m_ct, args.mgr_log_size[0])
            log_ct = get_from_list(args.mgr_log_ct, m_ct, args.mgr_log_ct[0])
            m.add_file_logger(file_log, size, log_ct)

        parse_filters_file(
            m, get_from_list(args.filters, m_ct, args.filters[0]))
        parse_alarms_file(
            m, get_from_list(args.alarms, m_ct, args.alarms[0]))
        parse_rules_file(m, get_from_list(args.rules, m_ct, args.rules[0]))

        # Set up GMaps stuff
        if get_from_list(
                args.gmaps_rev_geocode, m_ct, args.gmaps_rev_geocode[0]):
            m.enable_gmaps_reverse_geocoding()
        if get_from_list(args.gmaps_dm_walk, m_ct, args.gmaps_dm_walk[0]):
            m.enable_gmaps_distance_matrix('walking')
        if get_from_list(args.gmaps_dm_bike, m_ct, args.gmaps_dm_bike[0]):
            m.enable_gmaps_distance_matrix('biking')
        if get_from_list(args.gmaps_dm_drive, m_ct, args.gmaps_dm_drive[0]):
            m.enable_gmaps_distance_matrix('driving')
        if get_from_list(
                args.gmaps_dm_transit, m_ct, args.gmaps_dm_transit[0]):
            m.enable_gmaps_distance_matrix('transit')

        if m.get_name() not in managers:
            # Add the manager to the map
            managers[m.get_name()] = m
        else:
            log.critical("Names of Manager processes must be unique "
                         + "(not case sensitive)! Process will exit.")
            sys.exit(1)
        log.info("----------- Finished setting up 'manager_0'")
    for m_name in managers:
        managers[m_name].start()

    # Set up signal handlers for graceful exit
    signal(signal.SIGINT, exit_gracefully)
    signal(signal.SIGTERM, exit_gracefully)
Beispiel #3
0
def parse_settings(root_path):
    config['ROOT_PATH'] = root_path
    # Set the default config files up
    config_files = [get_path('config/config.ini')]
    if '-cf' in sys.argv or '--config' in sys.argv:
        config_files = []
    parser = configargparse.ArgParser(default_config_files=config_files)
    parser.add_argument('-cf',
                        '--config',
                        is_config_file=True,
                        help='Configuration file')

    # Webserver Settings:
    parser.add_argument('-d',
                        '--debug',
                        help='Debug Mode',
                        action='store_true',
                        default=False)
    parser.add_argument('-H',
                        '--host',
                        help='Set web server listening host',
                        default='127.0.0.1')
    parser.add_argument('-P',
                        '--port',
                        type=int,
                        help='Set web server listening port',
                        default=4000)
    parser.add_argument(
        '-C',
        '--concurrency',
        type=int,
        help='Maximum concurrent connections for the webserver.',
        default=200)

    # Manager Settings
    parser.add_argument('-m',
                        '--manager_count',
                        type=int,
                        default=1,
                        help='Number of Manager processes to start.')
    parser.add_argument('-M',
                        '--manager_name',
                        type=parse_unicode,
                        action='append',
                        default=[],
                        help='Names of Manager processes to start.')
    # Files
    parser.add_argument(
        '-f',
        '--filters',
        type=parse_unicode,
        action='append',
        default=['filters.json'],
        help='Filters configuration file. default: filters.json')
    parser.add_argument('-a',
                        '--alarms',
                        type=parse_unicode,
                        action='append',
                        default=['alarms.json'],
                        help='Alarms configuration file. default: alarms.json')
    parser.add_argument('-r',
                        '--rules',
                        type=parse_unicode,
                        action='append',
                        default=[None],
                        help='Rules configuration file. default: None')
    parser.add_argument('-gf',
                        '--geofences',
                        type=parse_unicode,
                        action='append',
                        default=[None],
                        help='Alarms configuration file. default: None')

    # Location Specific
    parser.add_argument('-l',
                        '--location',
                        type=parse_unicode,
                        action='append',
                        default=[None],
                        help='Location, can be an address or coordinates')
    parser.add_argument(
        '-L',
        '--locale',
        type=parse_unicode,
        action='append',
        default=['en'],
        choices=['de', 'en', 'es', 'fr', 'it', 'ko', 'pt', 'zh_hk'],
        help='Locale for Pokemon and Move names: default en," '
        '+ " check locale folder for more options')
    parser.add_argument(
        '-u',
        '--units',
        type=parse_unicode,
        default=['imperial'],
        action='append',
        choices=['metric', 'imperial'],
        help='Specify either metric or imperial units to use for distance " '
        '+ "measurements. ')
    parser.add_argument(
        '-tz',
        '--timezone',
        type=str,
        action='append',
        default=[None],
        help='Timezone used for notifications. Ex: "America/Los_Angeles"')

    # GMaps
    parser.add_argument('-k',
                        '--gmaps-key',
                        type=str,
                        action='append',
                        default=[],
                        help='Specify a Google API Key to use.')
    parser.add_argument('--gmaps-rev-geocode',
                        type=parse_boolean,
                        action='append',
                        default=[None],
                        help='Enable Walking Distance Matrix DTS.')
    parser.add_argument('--gmaps-dm-walk',
                        type=parse_boolean,
                        action='append',
                        default=[None],
                        help='Enable Walking Distance Matrix DTS.')
    parser.add_argument('--gmaps-dm-bike',
                        type=parse_boolean,
                        action='append',
                        default=[None],
                        help='Enable Bicycling Distance Matrix DTS.')
    parser.add_argument('--gmaps-dm-drive',
                        type=parse_boolean,
                        action='append',
                        default=[None],
                        help='Enable Driving Distance Matrix DTS.')
    parser.add_argument('--gmaps-dm-transit',
                        type=parse_boolean,
                        action='append',
                        default=[None],
                        help='Enable Transit Distance Matrix DTS.')

    # Misc
    parser.add_argument('-ct',
                        '--cache_type',
                        type=parse_unicode,
                        action='append',
                        default=['mem'],
                        choices=cache_options,
                        help="Specify the type of cache to use. Options: " +
                        "['mem', 'file'] (Default: 'mem')")
    parser.add_argument('-tl',
                        '--timelimit',
                        type=int,
                        default=[0],
                        action='append',
                        help='Minimum limit')
    parser.add_argument(
        '-ma',
        '--max_attempts',
        type=int,
        default=[3],
        action='append',
        help='Maximum attempts an alarm makes to send a notification.')
    parser.add_argument(
        '-api',
        '--channel_id',
        type=parse_unicode,
        action='append',
        default=['channel_id.json'],
        help=
        'Translate Filter set and Geofence to Discord API key. default: channel_id.json'
    )

    args = parser.parse_args()

    if args.debug:
        log.setLevel(logging.DEBUG)
        logging.getLogger().setLevel(logging.DEBUG)
        logging.getLogger('PokeAlarm').setLevel(logging.DEBUG)
        logging.getLogger('Manager').setLevel(logging.DEBUG)
        log.debug("Debug mode enabled!")

    config['HOST'] = args.host
    config['PORT'] = args.port
    config['CONCURRENCY'] = args.concurrency
    config['DEBUG'] = args.debug

    # Check to make sure that the same number of arguments are included
    for arg in [
            args.filters, args.alarms, args.rules, args.geofences,
            args.location, args.locale, args.units, args.cache_type,
            args.timelimit, args.max_attempts, args.timezone,
            args.gmaps_rev_geocode, args.gmaps_dm_walk, args.channel_id,
            args.gmaps_dm_bike, args.gmaps_dm_drive, args.gmaps_dm_transit
    ]:
        if len(arg) > 1:  # Remove defaults from the list
            arg.pop(0)
        size = len(arg)
        if size != 1 and size != args.manager_count:
            log.critical("Number of arguments must be either 1 for all " +
                         "managers or equal to Manager Count. Please " +
                         "provided the correct number of arguments.")
            log.critical(arg)
            sys.exit(1)

    # Attempt to parse the timezones
    for i in range(len(args.timezone)):
        if str(args.timezone[i]).lower() == "none":
            args.timezone[i] = None
            continue
        try:
            log.info(args.timezone[i])
            args.timezone[i] = pytz.timezone(args.timezone[i])
        except pytz.exceptions.UnknownTimeZoneError:
            log.error("Invalid timezone. For a list of valid timezones, see " +
                      "https://en.wikipedia.org/wiki" +
                      "/List_of_tz_database_time_zones")
            sys.exit(1)

    # Pad manager_name to match manager_count
    while len(args.manager_name) < args.manager_count:
        m_ct = len(args.manager_name)
        args.manager_name.append("Manager_{}".format(m_ct))

    # Build the managers
    for m_ct in range(args.manager_count):
        # TODO: Fix this mess better next time
        config['UNITS'] = get_from_list(args.units, m_ct, args.units[0])
        m = Manager(
            name=args.manager_name[m_ct],
            google_key=args.gmaps_key,
            locale=get_from_list(args.locale, m_ct, args.locale[0]),
            units=get_from_list(args.units, m_ct, args.units[0]),
            timezone=get_from_list(args.timezone, m_ct, args.timezone[0]),
            time_limit=get_from_list(args.timelimit, m_ct, args.timelimit[0]),
            max_attempts=get_from_list(args.max_attempts, m_ct,
                                       args.max_attempts[0]),
            quiet=False,  # TODO: I'll totally document this some day. Promise.
            cache_type=get_from_list(args.cache_type, m_ct,
                                     args.cache_type[0]),
            location=get_from_list(args.location, m_ct, args.location[0]),
            filter_file=get_from_list(args.filters, m_ct, args.filters[0]),
            geofence_file=get_from_list(args.geofences, m_ct,
                                        args.geofences[0]),
            alarm_file=get_from_list(args.alarms, m_ct, args.alarms[0]),
            debug=config['DEBUG'],
            channel_id_file=get_from_list(args.channel_id, m_ct,
                                          args.channel_id[0]))
        parse_rules_file(m, get_from_list(args.rules, m_ct, args.rules[0]))

        # Set up GMaps stuff
        if get_from_list(args.gmaps_rev_geocode, m_ct,
                         args.gmaps_rev_geocode[0]):
            m.enable_gmaps_reverse_geocoding()
        if get_from_list(args.gmaps_dm_walk, m_ct, args.gmaps_dm_walk[0]):
            m.enable_gmaps_distance_matrix('walking')
        if get_from_list(args.gmaps_dm_bike, m_ct, args.gmaps_dm_bike[0]):
            m.enable_gmaps_distance_matrix('biking')
        if get_from_list(args.gmaps_dm_drive, m_ct, args.gmaps_dm_drive[0]):
            m.enable_gmaps_distance_matrix('driving')
        if get_from_list(args.gmaps_dm_transit, m_ct,
                         args.gmaps_dm_transit[0]):
            m.enable_gmaps_distance_matrix('transit')

        if m.get_name() not in managers:
            # Add the manager to the map
            managers[m.get_name()] = m
        else:
            log.critical("Names of Manager processes must be unique " +
                         "(not case sensitive)! Process will exit.")
            sys.exit(1)
    log.info("Starting up the Managers")
    for m_name in managers:
        managers[m_name].start()

    # Set up signal handlers for graceful exit
    signal(signal.SIGINT, exit_gracefully)
    signal(signal.SIGTERM, exit_gracefully)
def parse_settings(root_path):
    config['ROOT_PATH'] = root_path
    # Set the default config files up
    config_files = [get_path('config/config.ini')] if '-cf' not in sys.argv and '--config' not in sys.argv else []
    parser = configargparse.ArgParser(default_config_files=config_files)
    parser.add_argument('-cf', '--config', is_config_file=True, help='Configuration file')
    parser.add_argument('-d', '--debug', help='Debug Mode', action='store_true', default=False)
    parser.add_argument('-H', '--host', help='Set web server listening host', default='127.0.0.1')
    parser.add_argument('-P', '--port', type=int, help='Set web server listening port', default=4000)
    parser.add_argument('-m', '--manager_count', type=int, default=1,
                        help='Number of Manager processes to start.')
    parser.add_argument('-M', '--manager_name', type=parse_unicode, action='append', default=[],
                        help='Names of Manager processes to start.')
    parser.add_argument('-k', '--key', type=parse_unicode, action='append', default=[None],
                        help='Specify a Google API Key to use.')
    parser.add_argument('-f', '--filters', type=parse_unicode, action='append', default=['filters.json'],
                        help='Filters configuration file. default: filters.json')
    parser.add_argument('-a', '--alarms', type=parse_unicode, action='append', default=['alarms.json'],
                        help='Alarms configuration file. default: alarms.json')
    parser.add_argument('-gf', '--geofences', type=parse_unicode, action='append', default=[None],
                        help='Alarms configuration file. default: None')
    parser.add_argument('-l', '--location', type=parse_unicode, action='append', default=[None],
                        help='Location, can be an address or coordinates')
    parser.add_argument('-L', '--locale', type=parse_unicode, action='append', default=['en'],
                        choices=['de', 'en', 'es', 'fr', 'it', 'ko', 'zh_hk'],
                        help='Locale for Pokemon and Move names: default en, check locale folder for more options')
    parser.add_argument('-u', '--units', type=parse_unicode, default=['imperial'], action='append',
                        choices=['metric', 'imperial'],
                        help='Specify either metric or imperial units to use for distance measurements. ')
    parser.add_argument('-tl', '--timelimit', type=int, default=[0], action='append',
                        help='Minimum number of seconds remaining on a pokemon to send a notify')
    parser.add_argument('-ma', '--max_attempts', type=int, default=[3], action='append',
                        help='Maximum number of attempts an alarm makes to send a notification.')
    parser.add_argument('-tz', '--timezone', type=str, action='append', default=[None],
                        help='Timezone used for notifications.  Ex: "America/Los_Angeles"')

    args = parser.parse_args()

    if args.debug:
        log.setLevel(logging.DEBUG)
        logging.getLogger().setLevel(logging.DEBUG)
        logging.getLogger('PokeAlarm').setLevel(logging.DEBUG)
        logging.getLogger('Manager').setLevel(logging.DEBUG)
        log.debug("Debug mode enabled!")

    config['HOST'] = args.host
    config['PORT'] = args.port
    config['DEBUG'] = args.debug

    # Check to make sure that the same number of arguements are included
    for list_ in [args.key, args.filters, args.alarms, args.geofences, args.location,
                  args.locale, args.units, args.timelimit, args.max_attempts, args.timezone]:
        if len(list_) > 1:  # Remove defaults from the list
            list_.pop(0)
        size = len(list_)
        if size != 1 and size != args.manager_count:
            log.critical("Number of arguments must be either 1 for all managers or ".format(args.manager_count) +
                         "equal to Manager Count. Please provided the correct number of arguments.")
            log.critical(list_)
            sys.exit(1)

    # Attempt to parse the timezones
    for i in range(len(args.timezone)):
        if str(args.timezone[i]).lower() == "none":
            args.timezone[i] = None
            continue
        try:
            log.info(args.timezone[i])
            args.timezone[i] = pytz.timezone(args.timezone[i])
        except pytz.exceptions.UnknownTimeZoneError:
            log.error("Invalid timezone. For a list of valid timezones, " +
                      "see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones")
            sys.exit(1)

    # Build the managers
    for m_ct in range(args.manager_count):
        # This needs to be changed a few times... because
        config['UNITS'] = args.units[m_ct] if len(args.units) > 1 else args.units[0]
        m = Manager(
            name=args.manager_name[m_ct] if m_ct < len(args.manager_name) else "Manager_{}".format(m_ct),
            google_key=args.key[m_ct] if len(args.key) > 1 else args.key[0],
            locale=args.locale[m_ct] if len(args.locale) > 1 else args.locale[0],
            units=args.units[m_ct] if len(args.units) > 1 else args.units[0],
            timezone=args.timezone[m_ct] if len(args.timezone) > 1 else args.timezone[0],
            time_limit=args.timelimit[m_ct] if len(args.timelimit) > 1 else args.timelimit[0],
            max_attempts=args.max_attempts[m_ct] if len(args.max_attempts) > 1 else args.max_attempts[0],
            quiet=False,  # TODO: I'll totally document this some day. Promise.
            location=args.location[m_ct] if len(args.location) > 1 else args.location[0],
            filter_file=args.filters[m_ct] if len(args.filters) > 1 else args.filters[0],
            geofence_file=args.geofences[m_ct] if len(args.geofences) > 1 else args.geofences[0],
            alarm_file=args.alarms[m_ct] if len(args.alarms) > 1 else args.alarms[0],
            debug=config['DEBUG']
        )
        if m.get_name() not in managers:
            # Add the manager to the map
            managers[m.get_name()] = m
        else:
            log.critical("Names of Manager processes must be unique (regardless of capitalization)! Process will exit.")
            sys.exit(1)
    log.info("Starting up the Managers")
    for m_name in managers:
        managers[m_name].start()