diff --git a/CHANGELOG.md b/CHANGELOG.md
index b8f5098..8aefcbf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # `react-native-maps-directions` Changelog
 
+## 1.9.1 – 2023-03-15
+
+- Add `avoidTolls` option;
+- Add `avoidHighways` option;
+- Add `avoidFerries` option;
+
 ## 1.9.0 – 2022-07-27
 
 - Fix: `timePrecision` prop type to `MapViewDirectionsTimePrecision`
@@ -46,7 +52,6 @@
 - Return “Duration with traffic” as `duration`
 - Return `fare` in `onReady`
 
-
 ## 1.6.0 - 2018-03-09
 
 - Add `directionsServiceBaseUrl` prop to allow customisation of service to use.
diff --git a/README.md b/README.md
index 63e636d..2603c6c 100644
--- a/README.md
+++ b/README.md
@@ -56,22 +56,26 @@ Once the directions in between `destination` and `origin` has been fetched, a `M
 
 ### Props
 
-| Prop | Type | Default | Note
-|---|---|---|---|
-| `origin` | `LatLng` or `String` | | The origin location to start routing from.
-| `destination` | `LatLng` or `String` | | The destination location to start routing to.
-| `apikey` | `String` | | Your Google Maps API Key _(request one [here](https://developers.google.com/maps/documentation/directions/get-api-key); if you're using an existing Google Maps API Key make sure you've enabled the Google Maps Directions API for that key using the [Google API Console](https://console.developers.google.com/apis/) by hitting the “Enable APIs and Services“ button)_.
-| `waypoints` | [`LatLng` or `String`] | `[]` | Array of waypoints to use between origin and destination.
-| `language` | `String` | `"en"` | The language to use when calculating directions. See [here](https://developers.google.com/maps/documentation/javascript/localization) for more info.
-| `mode` | `String` | `"DRIVING"` | Which transportation mode to use when calculating directions. Allowed values are `"DRIVING"`, `"BICYCLING"`, `"WALKING"`, and `"TRANSIT"`. _(See [here](https://developers.google.com/maps/documentation/javascript/examples/directions-travel-modes) for more info)_.
-| `resetOnChange` | `boolean` | `true` | Tweak if the rendered `MapView.Polyline` should reset or not when calculating the route between `origin` and `destionation`. Set to `false` if you see the directions line glitching.
-| `optimizeWaypoints` | `boolean` | `false` | Set it to true if you would like Google Maps to re-order all the waypoints to optimize the route for the fastest route. Please be aware that if this option is enabled, you will be billed at a higher rate by Google as stated [here](https://developers.google.com/maps/documentation/javascript/directions#Waypoints).
-| `splitWaypoints` | `boolean` | `false` | Directions API has a [limit](https://developers.google.com/maps/documentation/directions/usage-and-billing#directions-advanced) of 10 or 25 (depends on the billing plan) waypoints per route. When exceeding this limit you will be billed at a higher reate by Google. Set this to `true` if you would like to automatically split waypoints into multiple routes, thus bypassing this waypoints limit.
-| `directionsServiceBaseUrl` | `string` | _(Google's)_ | Base URL of the Directions Service (API) you are using. By default the Google Directions API is used (`"https://maps.googleapis.com/maps/api/directions/json"`). Usually you won't need to change this.
-| `region` | `String` | | If you are using strings for **origin** or **destination**, sometimes you will get an incorrect route because Google Maps API needs the region where this places belong to. See [here](https://developers.google.com/maps/documentation/javascript/localization#Region) for more info.
-| `precision` | `String` | `"low"` | The precision level of detail of the drawn polyline. Allowed values are "high", and "low". Setting to "low" will yield a polyline that is an approximate (smoothed) path of the resulting directions. Setting to "high" may cause a hit in performance in case a complex route is returned.
-| `timePrecision` | `String` | `"none"` | The timePrecision to get Realtime traffic info. Allowed values are "none", and "now". Defaults to "none".
-| `channel` | `String` | `null` | If you include the channel parameter in your requests, you can generate a Successful Requests report that shows a breakdown of your application's API requests across different applications that use the same client ID (such as externally facing access vs. internally facing access).
+| Prop                       | Type                   | Default      | Note                                                                                                                                                                                                                                                                                                                                                                                                      |
+| -------------------------- | ---------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `origin`                   | `LatLng` or `String`   |              | The origin location to start routing from.                                                                                                                                                                                                                                                                                                                                                                |
+| `destination`              | `LatLng` or `String`   |              | The destination location to start routing to.                                                                                                                                                                                                                                                                                                                                                             |
+| `apikey`                   | `String`               |              | Your Google Maps API Key _(request one [here](https://developers.google.com/maps/documentation/directions/get-api-key); if you're using an existing Google Maps API Key make sure you've enabled the Google Maps Directions API for that key using the [Google API Console](https://console.developers.google.com/apis/) by hitting the “Enable APIs and Services“ button)_.                              |
+| `waypoints`                | [`LatLng` or `String`] | `[]`         | Array of waypoints to use between origin and destination.                                                                                                                                                                                                                                                                                                                                                 |
+| `language`                 | `String`               | `"en"`       | The language to use when calculating directions. See [here](https://developers.google.com/maps/documentation/javascript/localization) for more info.                                                                                                                                                                                                                                                      |
+| `mode`                     | `String`               | `"DRIVING"`  | Which transportation mode to use when calculating directions. Allowed values are `"DRIVING"`, `"BICYCLING"`, `"WALKING"`, and `"TRANSIT"`. _(See [here](https://developers.google.com/maps/documentation/javascript/examples/directions-travel-modes) for more info)_.                                                                                                                                    |
+| `resetOnChange`            | `boolean`              | `true`       | Tweak if the rendered `MapView.Polyline` should reset or not when calculating the route between `origin` and `destionation`. Set to `false` if you see the directions line glitching.                                                                                                                                                                                                                     |
+| `optimizeWaypoints`        | `boolean`              | `false`      | Set it to true if you would like Google Maps to re-order all the waypoints to optimize the route for the fastest route. Please be aware that if this option is enabled, you will be billed at a higher rate by Google as stated [here](https://developers.google.com/maps/documentation/javascript/directions#Waypoints).                                                                                 |
+| `splitWaypoints`           | `boolean`              | `false`      | Directions API has a [limit](https://developers.google.com/maps/documentation/directions/usage-and-billing#directions-advanced) of 10 or 25 (depends on the billing plan) waypoints per route. When exceeding this limit you will be billed at a higher reate by Google. Set this to `true` if you would like to automatically split waypoints into multiple routes, thus bypassing this waypoints limit. |
+| `directionsServiceBaseUrl` | `string`               | _(Google's)_ | Base URL of the Directions Service (API) you are using. By default the Google Directions API is used (`"https://maps.googleapis.com/maps/api/directions/json"`). Usually you won't need to change this.                                                                                                                                                                                                   |
+| `region`                   | `String`               |              | If you are using strings for **origin** or **destination**, sometimes you will get an incorrect route because Google Maps API needs the region where this places belong to. See [here](https://developers.google.com/maps/documentation/javascript/localization#Region) for more info.                                                                                                                    |
+| `precision`                | `String`               | `"low"`      | The precision level of detail of the drawn polyline. Allowed values are "high", and "low". Setting to "low" will yield a polyline that is an approximate (smoothed) path of the resulting directions. Setting to "high" may cause a hit in performance in case a complex route is returned.                                                                                                               |
+| `timePrecision`            | `String`               | `"none"`     | The timePrecision to get Realtime traffic info. Allowed values are "none", and "now". Defaults to "none".                                                                                                                                                                                                                                                                                                 |
+| `channel`                  | `String`               | `null`       | If you include the channel parameter in your requests, you can generate a Successful Requests report that shows a breakdown of your application's API requests across different applications that use the same client ID (such as externally facing access vs. internally facing access).                                                                                                                 |
+| `avoidTolls`               | `boolean`              | `false`      | Set to `true` if you want direction routing to avoid Tollways when possible. Can be combined with other 'avoid' parameters. There might be instances that setting `avoidTolls` may be anough to avoid directions passing both tollways and highways, so just test which parameters apply to your application.                                                                                             |
+| `avoidHighways`            | `boolean`              | `false`      | Set to `true` if you want direction routing to avoid Highways when possible.                                                                                                                                                                                                                                                                                                                              |
+| `avoidFerries`             | `boolean`              | `false`      | Set to `true` if you want direction routing to avoid Ferries when possible.                                                                                                                                                                                                                                                                                                                               |
+
 #### More props
 
 Since the result rendered on screen is a `MapView.Polyline` component, all [`MapView.Polyline` props](https://github.com/airbnb/react-native-maps/blob/master/docs/polyline.md#props) – except for `coordinates` – are also accepted.
@@ -93,7 +97,7 @@ Since the result rendered on screen is a `MapView.Polyline` component, all [`Map
 The values for the `origin` and `destination` props can take several forms. They can either be:
 
 - Coordinates in the form of an object with `latitude` and `longitude` keys
-- Coordinates in the form of a string  with `latitude` and `longitude` values separated by a comma
+- Coordinates in the form of a string with `latitude` and `longitude` values separated by a comma
 - Strings representing an address
 - Strings representing a location
 - Strings containing a Place Id from the Google Maps Place API prefixed with `place_id:`
@@ -114,35 +118,34 @@ Tip: Don't forget to tweak the `language` prop when using localized location nam
 
 ### Events/Callbacks
 
-| Event Name | Returns | Notes
-|---|---|---|
-| `onStart` | `{ origin, destination, waypoints: [] }` | Callback that is called when the routing has started.
-| `onReady` | `{ distance: Number, duration: Number, coordinates: [], fare: Object, waypointOrder: [[]] }` | Callback that is called when the routing has succesfully finished. Note: distance returned in kilometers and duration in minutes.
-| `onError` | `errorMessage` | Callback that is called in case the routing has failed.
+| Event Name | Returns                                                                                      | Notes                                                                                                                             |
+| ---------- | -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
+| `onStart`  | `{ origin, destination, waypoints: [] }`                                                     | Callback that is called when the routing has started.                                                                             |
+| `onReady`  | `{ distance: Number, duration: Number, coordinates: [], fare: Object, waypointOrder: [[]] }` | Callback that is called when the routing has succesfully finished. Note: distance returned in kilometers and duration in minutes. |
+| `onError`  | `errorMessage`                                                                               | Callback that is called in case the routing has failed.                                                                           |
 
 ## Extended Example
 
 This example will draw a route between AirBnB's Office and Apple's HQ
 
 ```js
-import React, { Component } from 'react';
-import { Dimensions, StyleSheet } from 'react-native';
-import MapView from 'react-native-maps';
-import MapViewDirections from 'react-native-maps-directions';
+import React, { Component } from 'react'
+import { Dimensions, StyleSheet } from 'react-native'
+import MapView from 'react-native-maps'
+import MapViewDirections from 'react-native-maps-directions'
 
-const { width, height } = Dimensions.get('window');
-const ASPECT_RATIO = width / height;
-const LATITUDE = 37.771707;
-const LONGITUDE = -122.4053769;
-const LATITUDE_DELTA = 0.0922;
-const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;
+const { width, height } = Dimensions.get('window')
+const ASPECT_RATIO = width / height
+const LATITUDE = 37.771707
+const LONGITUDE = -122.4053769
+const LATITUDE_DELTA = 0.0922
+const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO
 
-const GOOGLE_MAPS_APIKEY = '…';
+const GOOGLE_MAPS_APIKEY = '…'
 
 class Example extends Component {
-
   constructor(props) {
-    super(props);
+    super(props)
 
     // AirBnB's Office, and Apple Park
     this.state = {
@@ -156,18 +159,15 @@ class Example extends Component {
           longitude: -122.4053769,
         },
       ],
-    };
+    }
 
-    this.mapView = null;
+    this.mapView = null
   }
 
   onMapPress = (e) => {
     this.setState({
-      coordinates: [
-        ...this.state.coordinates,
-        e.nativeEvent.coordinate,
-      ],
-    });
+      coordinates: [...this.state.coordinates, e.nativeEvent.coordinate],
+    })
   }
 
   render() {
@@ -180,48 +180,59 @@ class Example extends Component {
           longitudeDelta: LONGITUDE_DELTA,
         }}
         style={StyleSheet.absoluteFill}
-        ref={c => this.mapView = c}
+        ref={(c) => (this.mapView = c)}
         onPress={this.onMapPress}
       >
-        {this.state.coordinates.map((coordinate, index) =>
+        {this.state.coordinates.map((coordinate, index) => (
           <MapView.Marker key={`coordinate_${index}`} coordinate={coordinate} />
-        )}
-        {(this.state.coordinates.length >= 2) && (
+        ))}
+        {this.state.coordinates.length >= 2 && (
           <MapViewDirections
             origin={this.state.coordinates[0]}
-            waypoints={ (this.state.coordinates.length > 2) ? this.state.coordinates.slice(1, -1): undefined}
-            destination={this.state.coordinates[this.state.coordinates.length-1]}
+            waypoints={
+              this.state.coordinates.length > 2
+                ? this.state.coordinates.slice(1, -1)
+                : undefined
+            }
+            destination={
+              this.state.coordinates[this.state.coordinates.length - 1]
+            }
             apikey={GOOGLE_MAPS_APIKEY}
             strokeWidth={3}
-            strokeColor="hotpink"
+            strokeColor='hotpink'
             optimizeWaypoints={true}
             onStart={(params) => {
-              console.log(`Started routing between "${params.origin}" and "${params.destination}"`);
+              console.log(
+                `Started routing between "${params.origin}" and "${params.destination}"`
+              )
             }}
-            onReady={result => {
+            onReady={(result) => {
               console.log(`Distance: ${result.distance} km`)
               console.log(`Duration: ${result.duration} min.`)
 
               this.mapView.fitToCoordinates(result.coordinates, {
                 edgePadding: {
-                  right: (width / 20),
-                  bottom: (height / 20),
-                  left: (width / 20),
-                  top: (height / 20),
-                }
-              });
+                  right: width / 20,
+                  bottom: height / 20,
+                  left: width / 20,
+                  top: height / 20,
+                },
+              })
             }}
             onError={(errorMessage) => {
               // console.log('GOT AN ERROR');
             }}
+            avoidTolls={true}
+            avoidFerries={true}
+            avoidHighways={true}
           />
         )}
       </MapView>
-    );
+    )
   }
 }
 
-export default Example;
+export default Example
 ```
 
 ## Example App
diff --git a/index.d.ts b/index.d.ts
index b19991a..62f7d0c 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -1,4 +1,4 @@
-declare module "react-native-maps-directions" {
+declare module 'react-native-maps-directions' {
   // Type definitions for react-native-maps-directions 1.6
   // Project: https://github.com/bramus/react-native-maps-directions
   // Definitions by: Ali Oguzhan Yildiz <https://github.com/alioguzhan>
@@ -6,153 +6,85 @@ declare module "react-native-maps-directions" {
   // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
   // TypeScript Version: 3.3
 
-  import * as React from "react";
-
-  export type MapDirectionsLegs =[
-    {
-      distance: {
-        text: string,
-        value: number
-      },
-      duration: {
-        text: string,
-        value: number
-      },
-      end_address: string,
-      end_location: {
-        lat: number,
-        lng: number
-      },
-      start_address: string,
-      start_location: {
-        lat: number,
-        lng: number
-      },
-      steps: [{
-        distance: {
-          text: string,
-          value: number
-        },
-        duration: {
-          text: string,
-          value: number
-        },
-        end_location: {
-          lat: number,
-          lng: number
-        },
-        start_location: {
-          lat: number,
-          lng: number
-        },
-        html_instructions: string,
-        polyline: {
-          points: string
-        },
-        travel_mode: string,
-        maneuver: string | undefined
-      }],
-      traffic_speed_entry: [],
-      via_waypoint: [],
-    }]
-
-  export type MapDirectionsResponse = {
-    coordinates: [
-      {
-        latitude: number,
-        longitude: number
-      }],
-    distance: number,
-    duration: number,
-    fares: [],
-    legs: MapDirectionsLegs,
-    waypointOrder: [[number]]
-  }
-
-
-
+  import * as React from 'react'
 
   export type MapViewDirectionsOrigin =
     | string
     | {
-        latitude: number;
-        longitude: number;
-      };
+        latitude: number
+        longitude: number
+      }
 
   export type MapViewDirectionsWaypoints =
     | string
     | {
-        latitude: number;
-        longitude: number;
-      };
+        latitude: number
+        longitude: number
+      }
 
   export type MapViewDirectionsDestination =
     | string
     | {
-        latitude: number;
-        longitude: number;
-      };
+        latitude: number
+        longitude: number
+      }
 
   export type MapViewDirectionsMode =
-    | "DRIVING"
-    | "BICYCLING"
-    | "TRANSIT"
-    | "WALKING";
+    | 'DRIVING'
+    | 'BICYCLING'
+    | 'TRANSIT'
+    | 'WALKING'
 
-  export type MapViewDirectionsPrecision =
-    | "high"
-    | "low";
+  export type MapViewDirectionsPrecision = 'high' | 'low'
 
-  export type MapViewDirectionsTimePrecision =
-      | "now"
-      | "none";
+  export type MapViewDirectionsTimePrecision = 'now' | 'none'
 
   export interface MapViewDirectionsProps {
     /**
      * The origin location to start routing from.
      */
-    origin?: MapViewDirectionsOrigin;
+    origin?: MapViewDirectionsOrigin
     /**
      * Array of waypoints to use between origin and destination.
      */
-    waypoints?: MapViewDirectionsWaypoints[];
+    waypoints?: MapViewDirectionsWaypoints[]
     /**
      * The destination location to start routing to.
      */
-    destination?: MapViewDirectionsDestination;
+    destination?: MapViewDirectionsDestination
     /**
      * Your Google Maps API Key
      */
-    apikey: string;
+    apikey: string
     /**
      * Callback that is called when the routing has started.
      */
-    onStart?: (...args: any[]) => any;
+    onStart?: (...args: any[]) => any
     /**
      * Callback that is called when the routing has succesfully finished.
      */
-    onReady?: (...args: MapDirectionsResponse[]) => any;
+    onReady?: (...args: any[]) => any
     /**
      * Callback that is called in case the routing has failed.
      */
-    onError?: (...args: any[]) => any;
+    onError?: (...args: any[]) => any
     /**
      * Which transportation mode to use when calculating directions.
      * Allowed values are "DRIVING", "BICYCLING", "WALKING", and "TRANSIT".
      */
-    mode?: MapViewDirectionsMode;
+    mode?: MapViewDirectionsMode
     /**
      * The precision to draw the polyline with.
      * Allowed values are "high", and "low".
      * Defaults to "low"
      */
-    precision?: MapViewDirectionsPrecision;
+    precision?: MapViewDirectionsPrecision
     /**
      * The timePrecision to get Realtime traffic info.
      * Allowed values are "none", and "now".
      * Defaults to "none"
      */
-    timePrecision?: MapViewDirectionsTimePrecision;
+    timePrecision?: MapViewDirectionsPrecision
     /**
      * If you include the channel parameter in your requests,
      * you can generate a Successful Requests report that shows a breakdown
@@ -160,64 +92,64 @@ declare module "react-native-maps-directions" {
      * use the same client ID (such as externally facing access vs. internally
      * facing access).
      */
-    channel?: string;
+    channel?: string
     /**
      * The language to use when calculating directions.
      */
-    language?: string;
+    language?: string
     /**
      * Tweak if the rendered MapView. Polyline should reset or not
      * when calculating the route between origin and destionation.
      * Set to false if you see the directions line glitching.
      */
-    resetOnChange?: boolean;
+    resetOnChange?: boolean
     /**
      * Set it to true if you would like Google Maps to re-order all the
      * waypoints to optimize the route for the fastest route.
      * Please be aware that if this option is enabled,
      * you will be billed for a higher rate by Google
      */
-    optimizeWaypoints?: boolean;
+    optimizeWaypoints?: boolean
     /**
      * Directions API has a limit of 10 or 25 (depends on the billing plan)
      * waypoints per route. So waypoints array size is limited to those numbers.
      * Set this to true if you would like to automatically split waypoints to
      * multiple routes and by that avoid waypoints limit.
      */
-    splitWaypoints?: boolean;
+    splitWaypoints?: boolean
     /**
      * Base URL of the Directions Service (API) you are using.
      * By default the Google Directions API is used
      * ("https://maps.googleapis.com/maps/api/directions/json").
      * Usually you won't need to change this.
      */
-    directionsServiceBaseUrl?: string;
+    directionsServiceBaseUrl?: string
     /**
      * If you are using strings for origin or destination,
      * sometimes you will get an incorrect route because
      * Google Maps API needs the region where this places belong to.
      */
-    region?: string;
+    region?: string
     /**
      * @number
      * The stroke width to use for the path - the line displayed
      * by polyline between two navigation points.
      * Default: 1
      */
-    strokeWidth?: number;
+    strokeWidth?: number
     /**
      * @string
      * The stroke color to use for the path.
      * Default: "#000"
      */
-    strokeColor?: string;
+    strokeColor?: string
     /**
      * @Array
      * The stroke colors to use for the path (iOS only).
      * Must be the same length as coordinates.
      * Default: null
      */
-    strokeColors?: Array<string>;
+    strokeColors?: Array<string>
     /**
      * @string
      * The line cap style to apply to the open ends of the path.
@@ -225,14 +157,14 @@ declare module "react-native-maps-directions" {
      * Note: lineCap is not yet supported for GoogleMaps provider on iOS.
      * Default: "round"
      */
-    lineCap?: string;
+    lineCap?: string
     /**
      * @string
      * The line join style to apply to corners of the path.
      * Possible values are miter, round or bevel.
      * Default: "round"
      */
-    lineJoin?: string;
+    lineJoin?: string
     /**
      * @number
      * The limiting value that helps avoid spikes at junctions
@@ -243,7 +175,7 @@ declare module "react-native-maps-directions" {
      * to a bevel join. The default miter limit is 10, which results in the
      * conversion of miters whose angle at the joint is less than 11 degrees.
      */
-    miterLimit?: number;
+    miterLimit?: number
     /**
      * @boolean
      * Boolean to indicate whether to draw each segment of the line as a geodesic
@@ -251,7 +183,7 @@ declare module "react-native-maps-directions" {
      * shortest path between two points on the Earth's surface.
      * The geodesic curve is constructed assuming the Earth is a sphere.
      */
-    geodesic?: boolean;
+    geodesic?: boolean
     /**
      * @number
      * (iOS only) The offset (in points) at which to start drawing the
@@ -260,7 +192,7 @@ declare module "react-native-maps-directions" {
      * the patter 5-2-3-2 would cause drawing to begin in the middle of the first gap.
      * Default: 0
      */
-    lineDashPhase?: number;
+    lineDashPhase?: number
     /**
      * @Array
      * An array of numbers specifying the dash pattern to use for the path.
@@ -270,18 +202,30 @@ declare module "react-native-maps-directions" {
      * followed by the second line segment length, and so on.
      * Default: null
      */
-    lineDashPattern?: Array<number>;
+    lineDashPattern?: Array<number>
     /**
      * @boolean
      * Boolean to allow a polyline to be tappable and use the onPress function.
      */
-    tappable?: boolean;
+    tappable?: boolean
+    /**
+     * Set it to true if you would like Google Maps to avoid tolls where possible.
+     */
+    avoidTolls?: boolean
+    /**
+     * Set it to true if you would like Google Maps to avoid highways where possible.
+     */
+    avoidHighways?: boolean
+    /**
+     * Set it to true if you would like Google Maps to avoid ferries where possible.
+     */
+    avoidFerries?: boolean
   }
 
   export default class MapViewDirections extends React.Component<
     MapViewDirectionsProps,
     any
   > {
-    render(): JSX.Element;
+    render(): JSX.Element
   }
 }
diff --git a/src/MapViewDirections.js b/src/MapViewDirections.js
index 8e05906..09bf5be 100644
--- a/src/MapViewDirections.js
+++ b/src/MapViewDirections.js
@@ -1,357 +1,429 @@
-import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import { Polyline } from 'react-native-maps';
-import isEqual from 'lodash.isequal';
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import MapView from 'react-native-maps'
+import isEqual from 'lodash.isequal'
 
-const WAYPOINT_LIMIT = 10;
+const WAYPOINT_LIMIT = 10
 
 class MapViewDirections extends Component {
-
-	constructor(props) {
-		super(props);
-
-		this.state = {
-			coordinates: null,
-			distance: null,
-			duration: null,
-		};
-	}
-
-	componentDidMount() {
-		this.fetchAndRenderRoute(this.props);
-	}
-
-	componentDidUpdate(prevProps) {
-		if (!isEqual(prevProps.origin, this.props.origin) || !isEqual(prevProps.destination, this.props.destination) || !isEqual(prevProps.waypoints, this.props.waypoints) || !isEqual(prevProps.mode, this.props.mode) || !isEqual(prevProps.precision, this.props.precision) || !isEqual(prevProps.splitWaypoints, this.props.splitWaypoints)) {
-			if (this.props.resetOnChange === false) {
-				this.fetchAndRenderRoute(this.props);
-			} else {
-				this.resetState(() => {
-					this.fetchAndRenderRoute(this.props);
-				});
-			}
-		}
-	}
-
-	resetState = (cb = null) => {
-		this.setState({
-			coordinates: null,
-			distance: null,
-			duration: null,
-		}, cb);
-	}
-
-	decode(t) {
-		let points = [];
-		for (let step of t) {
-			let encoded = step.polyline.points;
-			let index = 0, len = encoded.length;
-			let lat = 0, lng = 0;
-			while (index < len) {
-				let b, shift = 0, result = 0;
-				do {
-					b = encoded.charAt(index++).charCodeAt(0) - 63;
-					result |= (b & 0x1f) << shift;
-					shift += 5;
-				} while (b >= 0x20);
-
-				let dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
-				lat += dlat;
-				shift = 0;
-				result = 0;
-				do {
-					b = encoded.charAt(index++).charCodeAt(0) - 63;
-					result |= (b & 0x1f) << shift;
-					shift += 5;
-				} while (b >= 0x20);
-				let dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
-				lng += dlng;
-
-				points.push({ latitude: (lat / 1E5), longitude: (lng / 1E5) });
-			}
-		}
-		return points;
-	}
-
-	fetchAndRenderRoute = (props) => {
-
-		let {
-			origin: initialOrigin,
-			destination: initialDestination,
-			waypoints: initialWaypoints = [],
-			apikey,
-			onStart,
-			onReady,
-			onError,
-			mode = 'DRIVING',
-			language = 'en',
-			optimizeWaypoints,
-			splitWaypoints,
-			directionsServiceBaseUrl = 'https://maps.googleapis.com/maps/api/directions/json',
-			region,
-			precision = 'low',
-			timePrecision = 'none',
-			channel,
-		} = props;
-
-		if (!apikey) {
-			console.warn(`MapViewDirections Error: Missing API Key`); // eslint-disable-line no-console
-			return;
-		}
-
-		if (!initialOrigin || !initialDestination) {
-			return;
-		}
-
-		const timePrecisionString = timePrecision==='none' ? '' : timePrecision;
-		
-		// Routes array which we'll be filling.
-		// We'll perform a Directions API Request for reach route
-		const routes = [];
-
-		// We need to split the waypoints in chunks, in order to not exceede the max waypoint limit
-		// ~> Chunk up the waypoints, yielding multiple routes
-		if (splitWaypoints && initialWaypoints && initialWaypoints.length > WAYPOINT_LIMIT) {
-			// Split up waypoints in chunks with chunksize WAYPOINT_LIMIT
-			const chunckedWaypoints = initialWaypoints.reduce((accumulator, waypoint, index) => {
-				const numChunk = Math.floor(index / WAYPOINT_LIMIT); 
-				accumulator[numChunk] = [].concat((accumulator[numChunk] || []), waypoint); 
-				return accumulator;
-			}, []);
-
-			// Create routes for each chunk, using:
-			// - Endpoints of previous chunks as startpoints for the route (except for the first chunk, which uses initialOrigin)
-			// - Startpoints of next chunks as endpoints for the route (except for the last chunk, which uses initialDestination)
-			for (let i = 0; i < chunckedWaypoints.length; i++) {
-				routes.push({
-					waypoints: chunckedWaypoints[i],
-					origin: (i === 0) ? initialOrigin : chunckedWaypoints[i-1][chunckedWaypoints[i-1].length - 1],
-					destination: (i === chunckedWaypoints.length - 1) ? initialDestination : chunckedWaypoints[i+1][0],
-				});
-			}
-		}
-		
-		// No splitting of the waypoints is requested/needed.
-		// ~> Use one single route
-		else {
-			routes.push({
-				waypoints: initialWaypoints,
-				origin: initialOrigin,
-				destination: initialDestination,
-			});
-		}
-
-		// Perform a Directions API Request for each route
-		Promise.all(routes.map((route, index) => {
-			let {
-				origin,
-				destination,
-				waypoints,
-			} = route;
-
-			if (origin.latitude && origin.longitude) {
-				origin = `${origin.latitude},${origin.longitude}`;
-			}
-
-			if (destination.latitude && destination.longitude) {
-				destination = `${destination.latitude},${destination.longitude}`;
-			}
-
-			waypoints = waypoints
-				.map(waypoint => (waypoint.latitude && waypoint.longitude) ? `${waypoint.latitude},${waypoint.longitude}` : waypoint)
-				.join('|');
-
-			if (optimizeWaypoints) {
-				waypoints = `optimize:true|${waypoints}`;
-			}
-
-			if (index === 0) {
-				onStart && onStart({
-					origin,
-					destination,
-					waypoints: initialWaypoints,
-				});
-			}
-
-			return (
-				this.fetchRoute(directionsServiceBaseUrl, origin, waypoints, destination, apikey, mode, language, region, precision, timePrecisionString, channel)
-					.then(result => {
-						return result;
-					})
-					.catch(errorMessage => {
-						return Promise.reject(errorMessage);
-					})
-			);
-		})).then(results => {
-			// Combine all Directions API Request results into one
-			const result = results.reduce((acc, { distance, duration, coordinates, fare, legs, waypointOrder }) => {
-				acc.coordinates = [
-					...acc.coordinates,
-					...coordinates,
-				];
-				acc.distance += distance;
-				acc.duration += duration;
-				acc.fares = [
-					...acc.fares,
-					fare,
-				];
-				acc.legs = legs;
-				acc.waypointOrder = [
-					...acc.waypointOrder,
-					waypointOrder,
-				];
-
-				return acc;
-			}, {
-				coordinates: [],
-				distance: 0,
-				duration: 0,
-				fares: [],
-				legs: [],
-				waypointOrder: [],
-			});
-
-			// Plot it out and call the onReady callback
-			this.setState({
-				coordinates: result.coordinates,
-			}, function() {
-				if (onReady) {
-					onReady(result);
-				}
-			});
-		})
-			.catch(errorMessage => {
-				this.resetState();
-				console.warn(`MapViewDirections Error: ${errorMessage}`); // eslint-disable-line no-console
-				onError && onError(errorMessage);
-			});
-	}
-
-	fetchRoute(directionsServiceBaseUrl, origin, waypoints, destination, apikey, mode, language, region, precision, timePrecision, channel) {
-
-		// Define the URL to call. Only add default parameters to the URL if it's a string.
-		let url = directionsServiceBaseUrl;
-		if (typeof (directionsServiceBaseUrl) === 'string') {
-			url += `?origin=${origin}&waypoints=${waypoints}&destination=${destination}&key=${apikey}&mode=${mode.toLowerCase()}&language=${language}&region=${region}`;
-			if(timePrecision){
-				url+=`&departure_time=${timePrecision}`;
-			}
-			if(channel){
-				url+=`&channel=${channel}`;
-			}
-		}
-
-		return fetch(url)
-			.then(response => response.json())
-			.then(json => {
-
-				if (json.status !== 'OK') {
-					const errorMessage = json.error_message || json.status || 'Unknown error';
-					return Promise.reject(errorMessage);
-				}
-
-				if (json.routes.length) {
-
-					const route = json.routes[0];
-
-					return Promise.resolve({
-						distance: route.legs.reduce((carry, curr) => {
-							return carry + curr.distance.value;
-						}, 0) / 1000,
-						duration: route.legs.reduce((carry, curr) => {
-							return carry + (curr.duration_in_traffic ? curr.duration_in_traffic.value : curr.duration.value);
-						}, 0) / 60,
-						coordinates: (
-							(precision === 'low') ?
-								this.decode([{polyline: route.overview_polyline}]) :
-								route.legs.reduce((carry, curr) => {
-									return [
-										...carry,
-										...this.decode(curr.steps),
-									];
-								}, [])
-						),
-						fare: route.fare,
-						waypointOrder: route.waypoint_order,
-						legs: route.legs,
-					});
-
-				} else {
-					return Promise.reject();
-				}
-			})
-			.catch(err => {
-				return Promise.reject(`Error on GMAPS route request: ${err}`);
-			});
-	}
-
-	render() {
-		const { coordinates } = this.state;
-
-		if (!coordinates) {
-			return null;
-		}
-
-		const {
-			origin, // eslint-disable-line no-unused-vars
-			waypoints, // eslint-disable-line no-unused-vars
-			splitWaypoints, // eslint-disable-line no-unused-vars
-			destination, // eslint-disable-line no-unused-vars
-			apikey, // eslint-disable-line no-unused-vars
-			onReady, // eslint-disable-line no-unused-vars
-			onError, // eslint-disable-line no-unused-vars
-			mode, // eslint-disable-line no-unused-vars
-			language, // eslint-disable-line no-unused-vars
-			region, // eslint-disable-line no-unused-vars
-			precision,  // eslint-disable-line no-unused-vars
-			...props
-		} = this.props;
-
-		return (
-			<Polyline coordinates={coordinates} {...props} />
-		);
-	}
-
+  constructor(props) {
+    super(props)
+
+    this.state = {
+      coordinates: null,
+      distance: null,
+      duration: null,
+    }
+  }
+
+  componentDidMount() {
+    this.fetchAndRenderRoute(this.props)
+  }
+
+  componentDidUpdate(prevProps) {
+    if (
+      !isEqual(prevProps.origin, this.props.origin) ||
+      !isEqual(prevProps.destination, this.props.destination) ||
+      !isEqual(prevProps.waypoints, this.props.waypoints) ||
+      !isEqual(prevProps.mode, this.props.mode) ||
+      !isEqual(prevProps.precision, this.props.precision) ||
+      !isEqual(prevProps.splitWaypoints, this.props.splitWaypoints) ||
+      !isEqual(prevProps.avoidTolls, this.props.avoidTolls) ||
+      !isEqual(prevProps.avoidHighways, this.props.avoidHighways) ||
+      !isEqual(prevProps.avoidFerries, this.props.avoidFerries)
+    ) {
+      if (this.props.resetOnChange === false) {
+        this.fetchAndRenderRoute(this.props)
+      } else {
+        this.resetState(() => {
+          this.fetchAndRenderRoute(this.props)
+        })
+      }
+    }
+  }
+
+  resetState = (cb = null) => {
+    this.setState(
+      {
+        coordinates: null,
+        distance: null,
+        duration: null,
+      },
+      cb
+    )
+  }
+
+  decode(t) {
+    let points = []
+    for (let step of t) {
+      let encoded = step.polyline.points
+      let index = 0,
+        len = encoded.length
+      let lat = 0,
+        lng = 0
+      while (index < len) {
+        let b,
+          shift = 0,
+          result = 0
+        do {
+          b = encoded.charAt(index++).charCodeAt(0) - 63
+          result |= (b & 0x1f) << shift
+          shift += 5
+        } while (b >= 0x20)
+
+        let dlat = (result & 1) != 0 ? ~(result >> 1) : result >> 1
+        lat += dlat
+        shift = 0
+        result = 0
+        do {
+          b = encoded.charAt(index++).charCodeAt(0) - 63
+          result |= (b & 0x1f) << shift
+          shift += 5
+        } while (b >= 0x20)
+        let dlng = (result & 1) != 0 ? ~(result >> 1) : result >> 1
+        lng += dlng
+
+        points.push({ latitude: lat / 1e5, longitude: lng / 1e5 })
+      }
+    }
+    return points
+  }
+
+  fetchAndRenderRoute = (props) => {
+    let {
+      origin: initialOrigin,
+      destination: initialDestination,
+      waypoints: initialWaypoints = [],
+      apikey,
+      onStart,
+      onReady,
+      onError,
+      mode = 'DRIVING',
+      language = 'en',
+      optimizeWaypoints,
+      splitWaypoints,
+      directionsServiceBaseUrl = 'https://maps.googleapis.com/maps/api/directions/json',
+      region,
+      precision = 'low',
+      timePrecision = 'none',
+      channel,
+      avoidTolls,
+      avoidHighways,
+      avoidFerries,
+    } = props
+
+    if (!apikey) {
+      console.warn(`MapViewDirections Error: Missing API Key`) // eslint-disable-line no-console
+      return
+    }
+
+    if (!initialOrigin || !initialDestination) {
+      return
+    }
+
+    const timePrecisionString = timePrecision === 'none' ? '' : timePrecision
+
+    // Routes array which we'll be filling.
+    // We'll perform a Directions API Request for reach route
+    const routes = []
+
+    // We need to split the waypoints in chunks, in order to not exceede the max waypoint limit
+    // ~> Chunk up the waypoints, yielding multiple routes
+    if (
+      splitWaypoints &&
+      initialWaypoints &&
+      initialWaypoints.length > WAYPOINT_LIMIT
+    ) {
+      // Split up waypoints in chunks with chunksize WAYPOINT_LIMIT
+      const chunckedWaypoints = initialWaypoints.reduce(
+        (accumulator, waypoint, index) => {
+          const numChunk = Math.floor(index / WAYPOINT_LIMIT)
+          accumulator[numChunk] = [].concat(
+            accumulator[numChunk] || [],
+            waypoint
+          )
+          return accumulator
+        },
+        []
+      )
+
+      // Create routes for each chunk, using:
+      // - Endpoints of previous chunks as startpoints for the route (except for the first chunk, which uses initialOrigin)
+      // - Startpoints of next chunks as endpoints for the route (except for the last chunk, which uses initialDestination)
+      for (let i = 0; i < chunckedWaypoints.length; i++) {
+        routes.push({
+          waypoints: chunckedWaypoints[i],
+          origin:
+            i === 0
+              ? initialOrigin
+              : chunckedWaypoints[i - 1][chunckedWaypoints[i - 1].length - 1],
+          destination:
+            i === chunckedWaypoints.length - 1
+              ? initialDestination
+              : chunckedWaypoints[i + 1][0],
+        })
+      }
+    }
+
+    // No splitting of the waypoints is requested/needed.
+    // ~> Use one single route
+    else {
+      routes.push({
+        waypoints: initialWaypoints,
+        origin: initialOrigin,
+        destination: initialDestination,
+      })
+    }
+
+    // Perform a Directions API Request for each route
+    Promise.all(
+      routes.map((route, index) => {
+        let { origin, destination, waypoints } = route
+
+        if (origin.latitude && origin.longitude) {
+          origin = `${origin.latitude},${origin.longitude}`
+        }
+
+        if (destination.latitude && destination.longitude) {
+          destination = `${destination.latitude},${destination.longitude}`
+        }
+
+        waypoints = waypoints
+          .map((waypoint) =>
+            waypoint.latitude && waypoint.longitude
+              ? `${waypoint.latitude},${waypoint.longitude}`
+              : waypoint
+          )
+          .join('|')
+
+        if (optimizeWaypoints) {
+          waypoints = `optimize:true|${waypoints}`
+        }
+
+        if (index === 0) {
+          onStart &&
+            onStart({
+              origin,
+              destination,
+              waypoints: initialWaypoints,
+            })
+        }
+
+        return this.fetchRoute(
+          directionsServiceBaseUrl,
+          origin,
+          waypoints,
+          destination,
+          apikey,
+          mode,
+          language,
+          region,
+          precision,
+          timePrecisionString,
+          channel,
+          avoidTolls,
+          avoidFerries,
+          avoidHighways
+        )
+          .then((result) => {
+            return result
+          })
+          .catch((errorMessage) => {
+            return Promise.reject(errorMessage)
+          })
+      })
+    )
+      .then((results) => {
+        // Combine all Directions API Request results into one
+        const result = results.reduce(
+          (acc, { distance, duration, coordinates, fare, waypointOrder }) => {
+            acc.coordinates = [...acc.coordinates, ...coordinates]
+            acc.distance += distance
+            acc.duration += duration
+            acc.fares = [...acc.fares, fare]
+            acc.waypointOrder = [...acc.waypointOrder, waypointOrder]
+
+            return acc
+          },
+          {
+            coordinates: [],
+            distance: 0,
+            duration: 0,
+            fares: [],
+            waypointOrder: [],
+          }
+        )
+
+        // Plot it out and call the onReady callback
+        this.setState(
+          {
+            coordinates: result.coordinates,
+          },
+          function () {
+            if (onReady) {
+              onReady(result)
+            }
+          }
+        )
+      })
+      .catch((errorMessage) => {
+        this.resetState()
+        console.warn(`MapViewDirections Error: ${errorMessage}`) // eslint-disable-line no-console
+        onError && onError(errorMessage)
+      })
+  }
+
+  fetchRoute(
+    directionsServiceBaseUrl,
+    origin,
+    waypoints,
+    destination,
+    apikey,
+    mode,
+    language,
+    region,
+    precision,
+    timePrecision,
+    channel,
+    avoidTolls,
+    avoidFerries,
+    avoidHighways
+  ) {
+    // Define the URL to call. Only add default parameters to the URL if it's a string.
+    let url = directionsServiceBaseUrl
+    if (typeof directionsServiceBaseUrl === 'string') {
+      url += `?origin=${origin}&waypoints=${waypoints}&destination=${destination}&key=${apikey}&mode=${mode.toLowerCase()}&language=${language}&region=${region}`
+      if (timePrecision) {
+        url += `&departure_time=${timePrecision}`
+      }
+      if (channel) {
+        url += `&channel=${channel}`
+      }
+      if (avoidTolls) {
+        url += `&avoid=tolls`
+      }
+      if (avoidHighways) {
+        url += `&avoid=highways`
+      }
+      if (avoidFerries) {
+        url += `&avoid=ferries`
+      }
+    }
+
+    return fetch(url)
+      .then((response) => response.json())
+      .then((json) => {
+        if (json.status !== 'OK') {
+          const errorMessage =
+            json.error_message || json.status || 'Unknown error'
+          return Promise.reject(errorMessage)
+        }
+
+        if (json.routes.length) {
+          const route = json.routes[0]
+
+          return Promise.resolve({
+            distance:
+              route.legs.reduce((carry, curr) => {
+                return carry + curr.distance.value
+              }, 0) / 1000,
+            duration:
+              route.legs.reduce((carry, curr) => {
+                return (
+                  carry +
+                  (curr.duration_in_traffic
+                    ? curr.duration_in_traffic.value
+                    : curr.duration.value)
+                )
+              }, 0) / 60,
+            coordinates:
+              precision === 'low'
+                ? this.decode([{ polyline: route.overview_polyline }])
+                : route.legs.reduce((carry, curr) => {
+                    return [...carry, ...this.decode(curr.steps)]
+                  }, []),
+            fare: route.fare,
+            waypointOrder: route.waypoint_order,
+          })
+        } else {
+          return Promise.reject()
+        }
+      })
+      .catch((err) => {
+        return Promise.reject(`Error on GMAPS route request: ${err}`)
+      })
+  }
+
+  render() {
+    const { coordinates } = this.state
+
+    if (!coordinates) {
+      return null
+    }
+
+    const {
+      origin, // eslint-disable-line no-unused-vars
+      waypoints, // eslint-disable-line no-unused-vars
+      splitWaypoints, // eslint-disable-line no-unused-vars
+      destination, // eslint-disable-line no-unused-vars
+      apikey, // eslint-disable-line no-unused-vars
+      onReady, // eslint-disable-line no-unused-vars
+      onError, // eslint-disable-line no-unused-vars
+      mode, // eslint-disable-line no-unused-vars
+      language, // eslint-disable-line no-unused-vars
+      region, // eslint-disable-line no-unused-vars
+      precision, // eslint-disable-line no-unused-vars
+      avoidFerries, // eslint-disable-line no-unused-vars
+      avoidHighways, // eslint-disable-line no-unused-vars
+      avoidTolls, // eslint-disable-line no-unused-vars
+      ...props
+    } = this.props
+
+    return <MapView.Polyline coordinates={coordinates} {...props} />
+  }
 }
 
 MapViewDirections.propTypes = {
-	origin: PropTypes.oneOfType([
-		PropTypes.string,
-		PropTypes.shape({
-			latitude: PropTypes.number.isRequired,
-			longitude: PropTypes.number.isRequired,
-		}),
-	]),
-	waypoints: PropTypes.arrayOf(
-		PropTypes.oneOfType([
-			PropTypes.string,
-			PropTypes.shape({
-				latitude: PropTypes.number.isRequired,
-				longitude: PropTypes.number.isRequired,
-			}),
-		]),
-	),
-	destination: PropTypes.oneOfType([
-		PropTypes.string,
-		PropTypes.shape({
-			latitude: PropTypes.number.isRequired,
-			longitude: PropTypes.number.isRequired,
-		}),
-	]),
-	apikey: PropTypes.string.isRequired,
-	onStart: PropTypes.func,
-	onReady: PropTypes.func,
-	onError: PropTypes.func,
-	mode: PropTypes.oneOf(['DRIVING', 'BICYCLING', 'TRANSIT', 'WALKING']),
-	language: PropTypes.string,
-	resetOnChange: PropTypes.bool,
-	optimizeWaypoints: PropTypes.bool,
-	splitWaypoints: PropTypes.bool,
-	directionsServiceBaseUrl: PropTypes.string,
-	region: PropTypes.string,
-	precision: PropTypes.oneOf(['high', 'low']),
-	timePrecision: PropTypes.oneOf(['now', 'none']),
-	channel: PropTypes.string,
-};
-
-export default MapViewDirections;
+  origin: PropTypes.oneOfType([
+    PropTypes.string,
+    PropTypes.shape({
+      latitude: PropTypes.number.isRequired,
+      longitude: PropTypes.number.isRequired,
+    }),
+  ]),
+  waypoints: PropTypes.arrayOf(
+    PropTypes.oneOfType([
+      PropTypes.string,
+      PropTypes.shape({
+        latitude: PropTypes.number.isRequired,
+        longitude: PropTypes.number.isRequired,
+      }),
+    ])
+  ),
+  destination: PropTypes.oneOfType([
+    PropTypes.string,
+    PropTypes.shape({
+      latitude: PropTypes.number.isRequired,
+      longitude: PropTypes.number.isRequired,
+    }),
+  ]),
+  apikey: PropTypes.string.isRequired,
+  onStart: PropTypes.func,
+  onReady: PropTypes.func,
+  onError: PropTypes.func,
+  mode: PropTypes.oneOf(['DRIVING', 'BICYCLING', 'TRANSIT', 'WALKING']),
+  language: PropTypes.string,
+  resetOnChange: PropTypes.bool,
+  optimizeWaypoints: PropTypes.bool,
+  splitWaypoints: PropTypes.bool,
+  directionsServiceBaseUrl: PropTypes.string,
+  region: PropTypes.string,
+  precision: PropTypes.oneOf(['high', 'low']),
+  timePrecision: PropTypes.oneOf(['now', 'none']),
+  channel: PropTypes.string,
+  avoidFerries: PropTypes.bool,
+  avoidTolls: PropTypes.bool,
+  avoidHighways: PropTypes.bool,
+}
+
+export default MapViewDirections