// An HTTP handler which returns a tileset's `layer.json` file
func LayerHandler(store stores.Storer) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var (
			err   error
			layer []byte
		)

		defer func() {
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				log.Err(err.Error())
			}
		}()

		vars := mux.Vars(r)

		// Try and get a `layer.json` from the stores
		layer, err = store.Layer(vars["tileset"])
		if err == stores.ErrNoItem {
			err = nil // don't persist this error
			if store.TilesetStatus(vars["tileset"]) == stores.NOT_FOUND {
				http.Error(w,
					fmt.Errorf("The tileset `%s` does not exist", vars["tileset"]).Error(),
					http.StatusNotFound)
				return
			}

			// the directory exists: send the default `layer.json`
			layer = []byte(`{
  "tilejson": "2.1.0",
  "format": "heightmap-1.0",
  "version": "1.0.0",
  "scheme": "tms",
  "tiles": ["{z}/{x}/{y}.terrain"]
}`)
		} else if err != nil {
			return
		}

		headers := w.Header()
		headers.Set("Content-Type", "application/json")
		w.Write(layer)
	}
}
func (this *Cache) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var limiter ResponseLimiter
	var recorder http.ResponseWriter
	rec := NewRecorder()

	// If a limiter is provided, wrap the recorder with it.
	if this.limiter != nil {
		limiter = this.limiter(rec, this.Limit)
		recorder = limiter
	} else {
		recorder = rec
	}

	// Write to both the recorder and original writer.
	tee := MultiWriter(w, recorder)
	this.handler.ServeHTTP(tee, r)

	// Only cache 200 responses.
	if rec.Code != 200 {
		return
	}

	// If the cache limit has been exceeded, don't proceed to cache the
	// response.
	if limiter != nil && limiter.LimitExceeded() {
		log.Debug(fmt.Sprintf("cache limit exceeded for %s", r.URL.String()))
		return
	}

	// Cache the response.
	key := this.generateKey(r)
	log.Debug(fmt.Sprintf("setting key: %s", key))
	if err := this.mc.Set(&memcache.Item{Key: key, Value: rec.Body.Bytes()}); err != nil {
		log.Err(err.Error())
	}

	return
}
// An HTTP handler which returns a terrain tile resource
func TerrainHandler(store stores.Storer) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var (
			t   stores.Terrain
			err error
		)

		defer func() {
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				log.Err(err.Error())
			}
		}()

		// get the tile coordinate from the URL
		vars := mux.Vars(r)
		err = t.ParseCoord(vars["x"], vars["y"], vars["z"])
		if err != nil {
			return
		}

		// Try and get a tile from the store
		err = store.Tile(vars["tileset"], &t)
		if err == stores.ErrNoItem {
			if store.TilesetStatus(vars["tileset"]) == stores.NOT_FOUND {
				err = nil
				http.Error(w,
					fmt.Errorf("The tileset `%s` does not exist", vars["tileset"]).Error(),
					http.StatusNotFound)
				return
			}

			if t.IsRoot() {
				// serve up a blank tile as it is a missing root tile
				data, err := assets.Asset("data/smallterrain-blank.terrain")
				if err != nil {
					return
				} else {
					err = t.UnmarshalBinary(data)
					if err != nil {
						return
					}
				}
			} else {
				err = nil
				http.Error(w, errors.New("The terrain tile does not exist").Error(), http.StatusNotFound)
				return
			}
		} else if err != nil {
			return
		}

		body, err := t.MarshalBinary()
		if err != nil {
			return
		}

		// send the tile to the client
		headers := w.Header()
		headers.Set("Content-Type", "application/octet-stream")
		headers.Set("Content-Encoding", "gzip")
		headers.Set("Content-Disposition", "attachment;filename="+vars["y"]+".terrain")
		w.Write(body)
	}
}