<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// More information about Google Directions API is available on
// https://developers.google.com/maps/documentation/directions/
package maps // import "google.golang.org/maps"

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"strings"
	"time"

	"google.golang.org/maps/internal"

	"golang.org/x/net/context"
)

// Get issues the Directions request and retrieves the Response
func (r *DirectionsRequest) Get(ctx context.Context) (DirectionsResponse, error) {
	var response DirectionsResponse

	if r.Origin == "" {
		return response, errors.New("directions: Origin required")
	}
	if r.Destination == "" {
		return response, errors.New("directions: Destination required")
	}
	if r.Mode != "" && ModeDriving != r.Mode && ModeWalking != r.Mode && ModeBicycling != r.Mode && ModeTransit != r.Mode {
		return response, fmt.Errorf("directions: unknown Mode: '%s'", r.Mode)
	}
	for _, avoid := range r.Avoid {
		if avoid != AvoidTolls && avoid != AvoidHighways && avoid != AvoidFerries {
			return response, fmt.Errorf("directions: Unknown Avoid restriction '%s'", avoid)
		}
	}
	if r.Units != "" && r.Units != UnitsMetric && r.Units != UnitsImperial {
		return response, fmt.Errorf("directions: Unknown Units '%s'", r.Units)
	}
	for _, transitMode := range r.TransitMode {
		if transitMode != TransitModeBus && transitMode != TransitModeSubway && transitMode != TransitModeTrain && transitMode != TransitModeTram && transitMode != TransitModeRail {
			return response, fmt.Errorf("directions: Unknown TransitMode '%s'", r.TransitMode)
		}
	}
	if r.TransitRoutingPreference != "" && r.TransitRoutingPreference != TransitRoutingPreferenceLessWalking && r.TransitRoutingPreference != TransitRoutingPreferenceFewerTransfers {
		return response, fmt.Errorf("directions: Unknown TransitRoutingPreference '%s'", r.TransitRoutingPreference)
	}
	if r.DepartureTime != "" && r.ArrivalTime != "" {
		return response, errors.New("directions: must not specify both DepartureTime and ArrivalTime")
	}

	if r.DepartureTime != "" && r.ArrivalTime != "" {
		return response, errors.New("directions: must not specify both DepartureTime and ArrivalTime")
	}
	if len(r.TransitMode) != 0 && r.Mode != ModeTransit {
		return response, errors.New("directions: must specify mode of transit when specifying transitMode")
	}
	if r.TransitRoutingPreference != "" && r.Mode != ModeTransit {
		return response, errors.New("directions: must specify mode of transit when specifying transitRoutingPreference")
	}

	req, err := http.NewRequest("GET", "https://maps.googleapis.com/maps/api/directions/json", nil)
	if err != nil {
		return response, err
	}
	q := req.URL.Query()
	q.Set("origin", r.Origin)
	q.Set("destination", r.Destination)
	q.Set("key", internal.APIKey(ctx))
	if r.Mode != "" {
		q.Set("mode", string(r.Mode))
	}
	if len(r.Waypoints) != 0 {
		q.Set("waypoints", strings.Join(r.Waypoints, "|"))
	}
	if r.Alternatives {
		q.Set("alternatives", "true")
	}
	if len(r.Avoid) > 0 {
		var avoid []string
		for _, a := range r.Avoid {
			avoid = append(avoid, string(a))
		}
		q.Set("avoid", strings.Join(avoid, "|"))
	}
	if r.Language != "" {
		q.Set("language", r.Language)
	}
	if r.Units != "" {
		q.Set("units", string(r.Units))
	}
	if r.Region != "" {
		q.Set("region", r.Region)
	}
	if len(r.TransitMode) != 0 {
		var transitMode []string
		for _, t := range r.TransitMode {
			transitMode = append(transitMode, string(t))
		}
		q.Set("transit_mode", strings.Join(transitMode, "|"))
	}
	req.URL.RawQuery = q.Encode()

	log.Println("Request:", req)

	err = httpDo(ctx, req, func(resp *http.Response, err error) error {
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
			return err
		}
		return nil
	})
	// httpDo waits for the closure we provided to return, so it's safe to
	// read response here.
	return response, err
}

// DirectionsRequest is the functional options struct for directions.Get
type DirectionsRequest struct {
	// Origin is the address or textual latitude/longitude value from which you wish to calculate directions. Required.
	Origin string
	// Destination is the address or textual latitude/longitude value from which you wish to calculate directions. Required.
	Destination string
	// Mode specifies the mode of transport to use when calculating directions. Optional.
	Mode mode
	// DepartureTime specifies the desired time of departure. You can specify the time as an integer in seconds since midnight, January 1, 1970 UTC. Alternatively, you can specify a value of `"now"`. Optional.
	DepartureTime string
	// ArrivalTime specifies the desired time of arrival for transit directions, in seconds since midnight, January 1, 1970 UTC. Optional. You cannot specify both `DepartureTime` and `ArrivalTime`.
	ArrivalTime string
	// Waypoints specifies an array of points to add to a route. Optional.
	Waypoints []string
	// Alternatives specifies if Directions service may provide more than one route alternative in the response. Optional.
	Alternatives bool
	// Avoid indicates that the calculated route(s) should avoid the indicated features. Optional.
	Avoid []avoid
	// Language specifies the language in which to return results. Optional.
	Language string
	// Units specifies the unit system to use when displaying results. Optional.
	Units units
	// Region specifies the region code, specified as a ccTLD two-character value. Optional.
	Region string
	// TransitMode specifies one or more preferred modes of transit. This parameter may only be specified for transit directions. Optional.
	TransitMode []transitMode
	// TransitRoutingPreference specifies preferences for transit routes. Optional.
	TransitRoutingPreference transitRoutingPreference
}

// DirectionsResponse represents a Directions API response.
type DirectionsResponse struct {
	// Routes lists the found routes between origin and destination.
	Routes []Route

	// Status contains the status of the request, and may contain
	// debugging information to help you track down why the Directions
	// service failed.
	// See https://developers.google.com/maps/documentation/directions/#StatusCodes
	Status string
}

// Route represents a single route between an origin and a destination.
type Route struct {
	// Summary contains a short textual description for the route, suitable for
	// naming and disambiguating the route from alternatives.
	Summary string `json:"summary"`

	// Legs contains information about a leg of the route, between two locations within the
	// given route. A separate leg will be present for each waypoint or destination specified.
	// (A route with no waypoints will contain exactly one leg within the legs array.)
	Legs []*Leg `json:"legs"`

	// WaypointOrder contains an array indicating the order of any waypoints in the calculated route.
	WaypointOrder []int `json:"waypoint_order"`

	// OverviewPolyline contains an approximate (smoothed) path of the resulting directions.
	OverviewPolyline Polyline `json:"overview_polyline"`

	// Bounds contains the viewport bounding box of the overview polyline.
	Bounds `json:"bounds"`

	// Copyrights contains the copyrights text to be displayed for this route. You must handle
	// and display this information yourself.
	Copyrights string `json:"copyrights"`

	// Warnings contains an array of warnings to be displayed when showing these directions.
	// You must handle and display these warnings yourself.
	Warnings []string `json:"warnings"`
}<commit_msg>Converting non OK status returns into Errors<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// More information about Google Directions API is available on
// https://developers.google.com/maps/documentation/directions/
package maps // import "google.golang.org/maps"

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"strings"
	"time"

	"google.golang.org/maps/internal"

	"golang.org/x/net/context"
)

// Get issues the Directions request and retrieves the Response
func (r *DirectionsRequest) Get(ctx context.Context) ([]Route, error) {
	var response DirectionsResponse

	if r.Origin == "" {
		return nil, errors.New("directions: Origin required")
	}
	if r.Destination == "" {
		return nil, errors.New("directions: Destination required")
	}
	if r.Mode != "" && ModeDriving != r.Mode && ModeWalking != r.Mode && ModeBicycling != r.Mode && ModeTransit != r.Mode {
		return nil, fmt.Errorf("directions: unknown Mode: '%s'", r.Mode)
	}
	for _, avoid := range r.Avoid {
		if avoid != AvoidTolls && avoid != AvoidHighways && avoid != AvoidFerries {
			return nil, fmt.Errorf("directions: Unknown Avoid restriction '%s'", avoid)
		}
	}
	if r.Units != "" && r.Units != UnitsMetric && r.Units != UnitsImperial {
		return nil, fmt.Errorf("directions: Unknown Units '%s'", r.Units)
	}
	for _, transitMode := range r.TransitMode {
		if transitMode != TransitModeBus && transitMode != TransitModeSubway && transitMode != TransitModeTrain && transitMode != TransitModeTram && transitMode != TransitModeRail {
			return nil, fmt.Errorf("directions: Unknown TransitMode '%s'", r.TransitMode)
		}
	}
	if r.TransitRoutingPreference != "" && r.TransitRoutingPreference != TransitRoutingPreferenceLessWalking && r.TransitRoutingPreference != TransitRoutingPreferenceFewerTransfers {
		return nil, fmt.Errorf("directions: Unknown TransitRoutingPreference '%s'", r.TransitRoutingPreference)
	}
	if r.DepartureTime != "" && r.ArrivalTime != "" {
		return nil, errors.New("directions: must not specify both DepartureTime and ArrivalTime")
	}

	if r.DepartureTime != "" && r.ArrivalTime != "" {
		return nil, errors.New("directions: must not specify both DepartureTime and ArrivalTime")
	}
	if len(r.TransitMode) != 0 && r.Mode != ModeTransit {
		return nil, errors.New("directions: must specify mode of transit when specifying transitMode")
	}
	if r.TransitRoutingPreference != "" && r.Mode != ModeTransit {
		return nil, errors.New("directions: must specify mode of transit when specifying transitRoutingPreference")
	}

	req, err := http.NewRequest("GET", "https://maps.googleapis.com/maps/api/directions/json", nil)
	if err != nil {
		return nil, err
	}
	q := req.URL.Query()
	q.Set("origin", r.Origin)
	q.Set("destination", r.Destination)
	q.Set("key", internal.APIKey(ctx))
	if r.Mode != "" {
		q.Set("mode", string(r.Mode))
	}
	if len(r.Waypoints) != 0 {
		q.Set("waypoints", strings.Join(r.Waypoints, "|"))
	}
	if r.Alternatives {
		q.Set("alternatives", "true")
	}
	if len(r.Avoid) > 0 {
		var avoid []string
		for _, a := range r.Avoid {
			avoid = append(avoid, string(a))
		}
		q.Set("avoid", strings.Join(avoid, "|"))
	}
	if r.Language != "" {
		q.Set("language", r.Language)
	}
	if r.Units != "" {
		q.Set("units", string(r.Units))
	}
	if r.Region != "" {
		q.Set("region", r.Region)
	}
	if len(r.TransitMode) != 0 {
		var transitMode []string
		for _, t := range r.TransitMode {
			transitMode = append(transitMode, string(t))
		}
		q.Set("transit_mode", strings.Join(transitMode, "|"))
	}
	req.URL.RawQuery = q.Encode()

	log.Println("Request:", req)

	err = httpDo(ctx, req, func(resp *http.Response, err error) error {
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	if response.Status != "OK" {
		return nil, fmt.Errorf("directions: %s - %s", response.Status, response.ErrorMessage)
	}

	return response.Routes, nil
}

// DirectionsRequest is the functional options struct for directions.Get
type DirectionsRequest struct {
	// Origin is the address or textual latitude/longitude value from which you wish to calculate directions. Required.
	Origin string
	// Destination is the address or textual latitude/longitude value from which you wish to calculate directions. Required.
	Destination string
	// Mode specifies the mode of transport to use when calculating directions. Optional.
	Mode mode
	// DepartureTime specifies the desired time of departure. You can specify the time as an integer in seconds since midnight, January 1, 1970 UTC. Alternatively, you can specify a value of `"now"`. Optional.
	DepartureTime string
	// ArrivalTime specifies the desired time of arrival for transit directions, in seconds since midnight, January 1, 1970 UTC. Optional. You cannot specify both `DepartureTime` and `ArrivalTime`.
	ArrivalTime string
	// Waypoints specifies an array of points to add to a route. Optional.
	Waypoints []string
	// Alternatives specifies if Directions service may provide more than one route alternative in the response. Optional.
	Alternatives bool
	// Avoid indicates that the calculated route(s) should avoid the indicated features. Optional.
	Avoid []avoid
	// Language specifies the language in which to return results. Optional.
	Language string
	// Units specifies the unit system to use when displaying results. Optional.
	Units units
	// Region specifies the region code, specified as a ccTLD two-character value. Optional.
	Region string
	// TransitMode specifies one or more preferred modes of transit. This parameter may only be specified for transit directions. Optional.
	TransitMode []transitMode
	// TransitRoutingPreference specifies preferences for transit routes. Optional.
	TransitRoutingPreference transitRoutingPreference
}

// DirectionsResponse represents a Directions API response.
type DirectionsResponse struct {
	// Routes lists the found routes between origin and destination.
	Routes []Route `json:"routes"`

	// Status contains the status of the request, and may contain
	// debugging information to help you track down why the Directions
	// service failed.
	// See https://developers.google.com/maps/documentation/directions/#StatusCodes
	Status string `json:"status"`

	// ErrorMessage is the explanatory field added when Status is an error.
	ErrorMessage string `json:"error_message"`
}

// Route represents a single route between an origin and a destination.
type Route struct {
	// Summary contains a short textual description for the route, suitable for
	// naming and disambiguating the route from alternatives.
	Summary string `json:"summary"`

	// Legs contains information about a leg of the route, between two locations within the
	// given route. A separate leg will be present for each waypoint or destination specified.
	// (A route with no waypoints will contain exactly one leg within the legs array.)
	Legs []*Leg `json:"legs"`

	// WaypointOrder contains an array indicating the order of any waypoints in the calculated route.
	WaypointOrder []int `json:"waypoint_order"`

	// OverviewPolyline contains an approximate (smoothed) path of the resulting directions.
	OverviewPolyline Polyline `json:"overview_polyline"`

	// Bounds contains the viewport bounding box of the overview polyline.
	Bounds `json:"bounds"`

	// Copyrights contains the copyrights text to be displayed for this route. You must handle
	// and display this information yourself.
	Copyrights string `json:"copyrights"`

	// Warnings contains an array of warnings to be displayed when showing these directions.
	// You must handle and display these warnings yourself.
	Warnings []string `json:"warnings"`
}
{'fraction_non_alphanumeric': 0.10822326374094589, 'fraction_numerical': 0.0026781910037129465, 'mean_word_length': 4.135979993748046, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 6, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6458603', 'n_tokens_mistral': 4937, 'n_tokens_neox': 4665, 'n_words': 1740}